|
|
|
@@ -62,6 +62,8 @@ export interface AssistantMcpDiscoveryDerivedValueFlow {
|
|
|
|
|
first_movement_date: string | null;
|
|
|
|
|
latest_movement_date: string | null;
|
|
|
|
|
coverage_limited_by_probe_limit: boolean;
|
|
|
|
|
coverage_recovered_by_period_chunking: boolean;
|
|
|
|
|
period_chunking_granularity: AssistantMcpDiscoveryAggregationAxis | null;
|
|
|
|
|
monthly_breakdown: AssistantMcpDiscoveryValueFlowMonthBucket[];
|
|
|
|
|
inference_basis: "sum_of_confirmed_1c_value_flow_rows";
|
|
|
|
|
}
|
|
|
|
@@ -74,6 +76,8 @@ export interface AssistantMcpDiscoveryValueFlowSideSummary {
|
|
|
|
|
first_movement_date: string | null;
|
|
|
|
|
latest_movement_date: string | null;
|
|
|
|
|
coverage_limited_by_probe_limit: boolean;
|
|
|
|
|
coverage_recovered_by_period_chunking: boolean;
|
|
|
|
|
period_chunking_granularity: AssistantMcpDiscoveryAggregationAxis | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface AssistantMcpDiscoveryBidirectionalValueFlowMonthBucket {
|
|
|
|
@@ -99,10 +103,26 @@ export interface AssistantMcpDiscoveryDerivedBidirectionalValueFlow {
|
|
|
|
|
net_amount_human_ru: string;
|
|
|
|
|
net_direction: AssistantMcpDiscoveryNetDirection;
|
|
|
|
|
coverage_limited_by_probe_limit: boolean;
|
|
|
|
|
coverage_recovered_by_period_chunking: boolean;
|
|
|
|
|
period_chunking_granularity: AssistantMcpDiscoveryAggregationAxis | null;
|
|
|
|
|
monthly_breakdown: AssistantMcpDiscoveryBidirectionalValueFlowMonthBucket[];
|
|
|
|
|
inference_basis: "incoming_minus_outgoing_confirmed_1c_value_flow_rows";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface AssistantMcpDiscoveryCoverageAwareQueryResult extends AddressMcpQueryExecutorResult {
|
|
|
|
|
coverage_limited_by_probe_limit: boolean;
|
|
|
|
|
coverage_recovered_by_period_chunking: boolean;
|
|
|
|
|
period_chunking_granularity: AssistantMcpDiscoveryAggregationAxis | null;
|
|
|
|
|
period_chunk_count: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface AssistantMcpDiscoveryCoverageAwareQueryExecution {
|
|
|
|
|
result: AssistantMcpDiscoveryCoverageAwareQueryResult | null;
|
|
|
|
|
probe_results: AssistantMcpDiscoveryProbeResult[];
|
|
|
|
|
query_limitations: string[];
|
|
|
|
|
executed_probe_count: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type AssistantMcpDiscoveryPilotScope =
|
|
|
|
|
| "counterparty_lifecycle_query_documents_v1"
|
|
|
|
|
| "counterparty_value_flow_query_movements_v1"
|
|
|
|
@@ -330,6 +350,193 @@ function queryResultToProbeResult(
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function toCoverageAwareQueryResult(
|
|
|
|
|
result: AddressMcpQueryExecutorResult | null,
|
|
|
|
|
options: {
|
|
|
|
|
coverageLimitedByProbeLimit?: boolean;
|
|
|
|
|
coverageRecoveredByPeriodChunking?: boolean;
|
|
|
|
|
periodChunkingGranularity?: AssistantMcpDiscoveryAggregationAxis | null;
|
|
|
|
|
periodChunkCount?: number;
|
|
|
|
|
} = {}
|
|
|
|
|
): AssistantMcpDiscoveryCoverageAwareQueryResult | null {
|
|
|
|
|
if (!result) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
...result,
|
|
|
|
|
coverage_limited_by_probe_limit: options.coverageLimitedByProbeLimit ?? false,
|
|
|
|
|
coverage_recovered_by_period_chunking: options.coverageRecoveredByPeriodChunking ?? false,
|
|
|
|
|
period_chunking_granularity: options.periodChunkingGranularity ?? null,
|
|
|
|
|
period_chunk_count: options.periodChunkCount ?? 0
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function monthWindowsForYear(year: string): Array<{ period_from: string; period_to: string }> {
|
|
|
|
|
const result: Array<{ period_from: string; period_to: string }> = [];
|
|
|
|
|
for (let month = 0; month < 12; month += 1) {
|
|
|
|
|
const start = new Date(Date.UTC(Number(year), month, 1));
|
|
|
|
|
const end = new Date(Date.UTC(Number(year), month + 1, 0));
|
|
|
|
|
result.push({
|
|
|
|
|
period_from: `${start.getUTCFullYear()}-${String(start.getUTCMonth() + 1).padStart(2, "0")}-${String(start.getUTCDate()).padStart(2, "0")}`,
|
|
|
|
|
period_to: `${end.getUTCFullYear()}-${String(end.getUTCMonth() + 1).padStart(2, "0")}-${String(end.getUTCDate()).padStart(2, "0")}`
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function periodWindowsForDateScope(dateScope: string | null): Array<{ period_from: string; period_to: string }> {
|
|
|
|
|
const yearMatch = dateScope?.match(/^(\d{4})$/);
|
|
|
|
|
if (yearMatch) {
|
|
|
|
|
return monthWindowsForYear(yearMatch[1]);
|
|
|
|
|
}
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function mergeCoverageAwareQueryResults(
|
|
|
|
|
results: AddressMcpQueryExecutorResult[],
|
|
|
|
|
options: {
|
|
|
|
|
coverageLimitedByProbeLimit: boolean;
|
|
|
|
|
coverageRecoveredByPeriodChunking: boolean;
|
|
|
|
|
periodChunkingGranularity: AssistantMcpDiscoveryAggregationAxis | null;
|
|
|
|
|
periodChunkCount: number;
|
|
|
|
|
}
|
|
|
|
|
): AssistantMcpDiscoveryCoverageAwareQueryResult {
|
|
|
|
|
const rawRows = results.flatMap((item) => item.raw_rows);
|
|
|
|
|
const rows = results.flatMap((item) => item.rows);
|
|
|
|
|
const errors = results.map((item) => toNonEmptyString(item.error)).filter((item): item is string => Boolean(item));
|
|
|
|
|
return {
|
|
|
|
|
fetched_rows: results.reduce((sum, item) => sum + item.fetched_rows, 0),
|
|
|
|
|
matched_rows: results.reduce((sum, item) => sum + item.matched_rows, 0),
|
|
|
|
|
raw_rows: rawRows,
|
|
|
|
|
rows,
|
|
|
|
|
error: errors[0] ?? null,
|
|
|
|
|
coverage_limited_by_probe_limit: options.coverageLimitedByProbeLimit,
|
|
|
|
|
coverage_recovered_by_period_chunking: options.coverageRecoveredByPeriodChunking,
|
|
|
|
|
period_chunking_granularity: options.periodChunkingGranularity,
|
|
|
|
|
period_chunk_count: options.periodChunkCount
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function executeCoverageAwareValueFlowQuery(input: {
|
|
|
|
|
primitiveId: string;
|
|
|
|
|
recipePlanBuilder: (filters: AddressFilterSet) => {
|
|
|
|
|
query: string;
|
|
|
|
|
limit: number;
|
|
|
|
|
account_scope?: string[];
|
|
|
|
|
};
|
|
|
|
|
baseFilters: AddressFilterSet;
|
|
|
|
|
dateScope: string | null;
|
|
|
|
|
maxProbeCount: number;
|
|
|
|
|
maxRowsPerProbe: number;
|
|
|
|
|
deps: AssistantMcpDiscoveryPilotExecutorDeps;
|
|
|
|
|
}): Promise<AssistantMcpDiscoveryCoverageAwareQueryExecution> {
|
|
|
|
|
const queryLimitations: string[] = [];
|
|
|
|
|
const probeResults: AssistantMcpDiscoveryProbeResult[] = [];
|
|
|
|
|
let executedProbeCount = 0;
|
|
|
|
|
|
|
|
|
|
const broadRecipePlan = input.recipePlanBuilder(input.baseFilters);
|
|
|
|
|
const broadResult = await input.deps.executeAddressMcpQuery({
|
|
|
|
|
query: broadRecipePlan.query,
|
|
|
|
|
limit: broadRecipePlan.limit,
|
|
|
|
|
account_scope: broadRecipePlan.account_scope
|
|
|
|
|
});
|
|
|
|
|
executedProbeCount += 1;
|
|
|
|
|
probeResults.push(queryResultToProbeResult(input.primitiveId, broadResult));
|
|
|
|
|
const broadCoverageLimited = !broadResult.error && broadResult.matched_rows >= input.maxRowsPerProbe;
|
|
|
|
|
|
|
|
|
|
if (broadResult.error) {
|
|
|
|
|
pushUnique(queryLimitations, broadResult.error);
|
|
|
|
|
return {
|
|
|
|
|
result: toCoverageAwareQueryResult(broadResult, {
|
|
|
|
|
coverageLimitedByProbeLimit: false
|
|
|
|
|
}),
|
|
|
|
|
probe_results: probeResults,
|
|
|
|
|
query_limitations: queryLimitations,
|
|
|
|
|
executed_probe_count: executedProbeCount
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const periodWindows = periodWindowsForDateScope(input.dateScope);
|
|
|
|
|
if (!broadCoverageLimited || periodWindows.length === 0) {
|
|
|
|
|
return {
|
|
|
|
|
result: toCoverageAwareQueryResult(broadResult, {
|
|
|
|
|
coverageLimitedByProbeLimit: broadCoverageLimited
|
|
|
|
|
}),
|
|
|
|
|
probe_results: probeResults,
|
|
|
|
|
query_limitations: queryLimitations,
|
|
|
|
|
executed_probe_count: executedProbeCount
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const requiredChunkProbeCount = periodWindows.length;
|
|
|
|
|
if (executedProbeCount + requiredChunkProbeCount > input.maxProbeCount) {
|
|
|
|
|
pushUnique(
|
|
|
|
|
queryLimitations,
|
|
|
|
|
"Requested period hit the MCP row limit, but the approved monthly recovery probe budget is smaller than the required subperiod count"
|
|
|
|
|
);
|
|
|
|
|
return {
|
|
|
|
|
result: toCoverageAwareQueryResult(broadResult, {
|
|
|
|
|
coverageLimitedByProbeLimit: true
|
|
|
|
|
}),
|
|
|
|
|
probe_results: probeResults,
|
|
|
|
|
query_limitations: queryLimitations,
|
|
|
|
|
executed_probe_count: executedProbeCount
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const chunkResults: AddressMcpQueryExecutorResult[] = [];
|
|
|
|
|
let anyChunkLimited = false;
|
|
|
|
|
let anyChunkError = false;
|
|
|
|
|
|
|
|
|
|
for (const window of periodWindows) {
|
|
|
|
|
const chunkFilters: AddressFilterSet = {
|
|
|
|
|
...input.baseFilters,
|
|
|
|
|
period_from: window.period_from,
|
|
|
|
|
period_to: window.period_to
|
|
|
|
|
};
|
|
|
|
|
const chunkPlan = input.recipePlanBuilder(chunkFilters);
|
|
|
|
|
const chunkResult = await input.deps.executeAddressMcpQuery({
|
|
|
|
|
query: chunkPlan.query,
|
|
|
|
|
limit: chunkPlan.limit,
|
|
|
|
|
account_scope: chunkPlan.account_scope
|
|
|
|
|
});
|
|
|
|
|
executedProbeCount += 1;
|
|
|
|
|
probeResults.push(queryResultToProbeResult(input.primitiveId, chunkResult));
|
|
|
|
|
if (chunkResult.error) {
|
|
|
|
|
anyChunkError = true;
|
|
|
|
|
pushUnique(queryLimitations, chunkResult.error);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (chunkResult.matched_rows >= input.maxRowsPerProbe) {
|
|
|
|
|
anyChunkLimited = true;
|
|
|
|
|
}
|
|
|
|
|
chunkResults.push(chunkResult);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (chunkResults.length === 0 && anyChunkError) {
|
|
|
|
|
return {
|
|
|
|
|
result: toCoverageAwareQueryResult(broadResult, {
|
|
|
|
|
coverageLimitedByProbeLimit: true
|
|
|
|
|
}),
|
|
|
|
|
probe_results: probeResults,
|
|
|
|
|
query_limitations: queryLimitations,
|
|
|
|
|
executed_probe_count: executedProbeCount
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
result: mergeCoverageAwareQueryResults(chunkResults, {
|
|
|
|
|
coverageLimitedByProbeLimit: anyChunkLimited || anyChunkError,
|
|
|
|
|
coverageRecoveredByPeriodChunking: true,
|
|
|
|
|
periodChunkingGranularity: "month",
|
|
|
|
|
periodChunkCount: periodWindows.length
|
|
|
|
|
}),
|
|
|
|
|
probe_results: probeResults,
|
|
|
|
|
query_limitations: queryLimitations,
|
|
|
|
|
executed_probe_count: executedProbeCount
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function summarizeLifecycleRows(result: AddressMcpQueryExecutorResult): string | null {
|
|
|
|
|
if (result.error) {
|
|
|
|
|
return null;
|
|
|
|
@@ -340,13 +547,16 @@ function summarizeLifecycleRows(result: AddressMcpQueryExecutorResult): string |
|
|
|
|
|
return `${result.fetched_rows} MCP document rows fetched, ${result.matched_rows} matched lifecycle scope`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function summarizeValueFlowRows(result: AddressMcpQueryExecutorResult): string | null {
|
|
|
|
|
function summarizeValueFlowRows(result: AssistantMcpDiscoveryCoverageAwareQueryResult): string | null {
|
|
|
|
|
if (result.error) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
if (result.fetched_rows <= 0) {
|
|
|
|
|
return "0 MCP value-flow rows fetched";
|
|
|
|
|
}
|
|
|
|
|
if (result.coverage_recovered_by_period_chunking && result.period_chunking_granularity === "month") {
|
|
|
|
|
return `${result.period_chunk_count} monthly MCP value-flow probes fetched ${result.fetched_rows} rows total, ${result.matched_rows} matched value-flow scope after the broad probe hit the row limit`;
|
|
|
|
|
}
|
|
|
|
|
return `${result.fetched_rows} MCP value-flow rows fetched, ${result.matched_rows} matched value-flow scope`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -482,7 +692,7 @@ function formatAmountHumanRu(amount: number): string {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function deriveValueFlowMonthBreakdown(
|
|
|
|
|
result: AddressMcpQueryExecutorResult | null,
|
|
|
|
|
result: AssistantMcpDiscoveryCoverageAwareQueryResult | null,
|
|
|
|
|
aggregationAxis: AssistantMcpDiscoveryAggregationAxis | null
|
|
|
|
|
): AssistantMcpDiscoveryValueFlowMonthBucket[] {
|
|
|
|
|
if (!result || result.error || aggregationAxis !== "month") {
|
|
|
|
@@ -512,8 +722,8 @@ function deriveValueFlowMonthBreakdown(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function deriveBidirectionalValueFlowMonthBreakdown(input: {
|
|
|
|
|
incomingResult: AddressMcpQueryExecutorResult | null;
|
|
|
|
|
outgoingResult: AddressMcpQueryExecutorResult | null;
|
|
|
|
|
incomingResult: AssistantMcpDiscoveryCoverageAwareQueryResult | null;
|
|
|
|
|
outgoingResult: AssistantMcpDiscoveryCoverageAwareQueryResult | null;
|
|
|
|
|
aggregationAxis: AssistantMcpDiscoveryAggregationAxis | null;
|
|
|
|
|
}): AssistantMcpDiscoveryBidirectionalValueFlowMonthBucket[] {
|
|
|
|
|
if (input.aggregationAxis !== "month") {
|
|
|
|
@@ -557,11 +767,10 @@ function deriveBidirectionalValueFlowMonthBreakdown(input: {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function deriveValueFlow(
|
|
|
|
|
result: AddressMcpQueryExecutorResult | null,
|
|
|
|
|
result: AssistantMcpDiscoveryCoverageAwareQueryResult | null,
|
|
|
|
|
counterparty: string | null,
|
|
|
|
|
periodScope: string | null,
|
|
|
|
|
direction: AssistantMcpDiscoveryDerivedValueFlow["value_flow_direction"],
|
|
|
|
|
probeLimit: number,
|
|
|
|
|
aggregationAxis: AssistantMcpDiscoveryAggregationAxis | null
|
|
|
|
|
): AssistantMcpDiscoveryDerivedValueFlow | null {
|
|
|
|
|
if (!result || result.error || result.matched_rows <= 0) {
|
|
|
|
@@ -594,15 +803,16 @@ function deriveValueFlow(
|
|
|
|
|
total_amount_human_ru: formatAmountHumanRu(totalAmount),
|
|
|
|
|
first_movement_date: dates[0] ?? null,
|
|
|
|
|
latest_movement_date: dates[dates.length - 1] ?? null,
|
|
|
|
|
coverage_limited_by_probe_limit: result.matched_rows >= probeLimit,
|
|
|
|
|
coverage_limited_by_probe_limit: result.coverage_limited_by_probe_limit,
|
|
|
|
|
coverage_recovered_by_period_chunking: result.coverage_recovered_by_period_chunking,
|
|
|
|
|
period_chunking_granularity: result.period_chunking_granularity,
|
|
|
|
|
monthly_breakdown: deriveValueFlowMonthBreakdown(result, aggregationAxis),
|
|
|
|
|
inference_basis: "sum_of_confirmed_1c_value_flow_rows"
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function deriveValueFlowSideSummary(
|
|
|
|
|
result: AddressMcpQueryExecutorResult | null,
|
|
|
|
|
probeLimit: number
|
|
|
|
|
result: AssistantMcpDiscoveryCoverageAwareQueryResult | null
|
|
|
|
|
): AssistantMcpDiscoveryValueFlowSideSummary {
|
|
|
|
|
if (!result || result.error || result.matched_rows <= 0) {
|
|
|
|
|
return {
|
|
|
|
@@ -612,7 +822,9 @@ function deriveValueFlowSideSummary(
|
|
|
|
|
total_amount_human_ru: formatAmountHumanRu(0),
|
|
|
|
|
first_movement_date: null,
|
|
|
|
|
latest_movement_date: null,
|
|
|
|
|
coverage_limited_by_probe_limit: false
|
|
|
|
|
coverage_limited_by_probe_limit: false,
|
|
|
|
|
coverage_recovered_by_period_chunking: false,
|
|
|
|
|
period_chunking_granularity: null
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -636,20 +848,21 @@ function deriveValueFlowSideSummary(
|
|
|
|
|
total_amount_human_ru: formatAmountHumanRu(totalAmount),
|
|
|
|
|
first_movement_date: dates[0] ?? null,
|
|
|
|
|
latest_movement_date: dates[dates.length - 1] ?? null,
|
|
|
|
|
coverage_limited_by_probe_limit: result.matched_rows >= probeLimit
|
|
|
|
|
coverage_limited_by_probe_limit: result.coverage_limited_by_probe_limit,
|
|
|
|
|
coverage_recovered_by_period_chunking: result.coverage_recovered_by_period_chunking,
|
|
|
|
|
period_chunking_granularity: result.period_chunking_granularity
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function deriveBidirectionalValueFlow(input: {
|
|
|
|
|
incomingResult: AddressMcpQueryExecutorResult | null;
|
|
|
|
|
outgoingResult: AddressMcpQueryExecutorResult | null;
|
|
|
|
|
incomingResult: AssistantMcpDiscoveryCoverageAwareQueryResult | null;
|
|
|
|
|
outgoingResult: AssistantMcpDiscoveryCoverageAwareQueryResult | null;
|
|
|
|
|
counterparty: string | null;
|
|
|
|
|
periodScope: string | null;
|
|
|
|
|
probeLimit: number;
|
|
|
|
|
aggregationAxis: AssistantMcpDiscoveryAggregationAxis | null;
|
|
|
|
|
}): AssistantMcpDiscoveryDerivedBidirectionalValueFlow | null {
|
|
|
|
|
const incoming = deriveValueFlowSideSummary(input.incomingResult, input.probeLimit);
|
|
|
|
|
const outgoing = deriveValueFlowSideSummary(input.outgoingResult, input.probeLimit);
|
|
|
|
|
const incoming = deriveValueFlowSideSummary(input.incomingResult);
|
|
|
|
|
const outgoing = deriveValueFlowSideSummary(input.outgoingResult);
|
|
|
|
|
if (incoming.rows_with_amount <= 0 && outgoing.rows_with_amount <= 0) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
@@ -665,6 +878,10 @@ function deriveBidirectionalValueFlow(input: {
|
|
|
|
|
net_direction: netDirectionFromAmount(netAmount),
|
|
|
|
|
coverage_limited_by_probe_limit:
|
|
|
|
|
incoming.coverage_limited_by_probe_limit || outgoing.coverage_limited_by_probe_limit,
|
|
|
|
|
coverage_recovered_by_period_chunking:
|
|
|
|
|
incoming.coverage_recovered_by_period_chunking || outgoing.coverage_recovered_by_period_chunking,
|
|
|
|
|
period_chunking_granularity:
|
|
|
|
|
incoming.period_chunking_granularity ?? outgoing.period_chunking_granularity ?? null,
|
|
|
|
|
monthly_breakdown: deriveBidirectionalValueFlowMonthBreakdown({
|
|
|
|
|
incomingResult: input.incomingResult,
|
|
|
|
|
outgoingResult: input.outgoingResult,
|
|
|
|
@@ -675,8 +892,8 @@ function deriveBidirectionalValueFlow(input: {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function summarizeBidirectionalValueFlowRows(input: {
|
|
|
|
|
incomingResult: AddressMcpQueryExecutorResult | null;
|
|
|
|
|
outgoingResult: AddressMcpQueryExecutorResult | null;
|
|
|
|
|
incomingResult: AssistantMcpDiscoveryCoverageAwareQueryResult | null;
|
|
|
|
|
outgoingResult: AssistantMcpDiscoveryCoverageAwareQueryResult | null;
|
|
|
|
|
}): string | null {
|
|
|
|
|
const incoming = input.incomingResult;
|
|
|
|
|
const outgoing = input.outgoingResult;
|
|
|
|
@@ -685,10 +902,14 @@ function summarizeBidirectionalValueFlowRows(input: {
|
|
|
|
|
}
|
|
|
|
|
const incomingSummary = incoming?.error
|
|
|
|
|
? "incoming value-flow query failed"
|
|
|
|
|
: `${incoming?.fetched_rows ?? 0} incoming value-flow rows fetched, ${incoming?.matched_rows ?? 0} matched`;
|
|
|
|
|
: incoming?.coverage_recovered_by_period_chunking && incoming.period_chunking_granularity === "month"
|
|
|
|
|
? `${incoming.period_chunk_count} monthly incoming value-flow probes fetched ${incoming.fetched_rows} rows total, ${incoming.matched_rows} matched`
|
|
|
|
|
: `${incoming?.fetched_rows ?? 0} incoming value-flow rows fetched, ${incoming?.matched_rows ?? 0} matched`;
|
|
|
|
|
const outgoingSummary = outgoing?.error
|
|
|
|
|
? "outgoing supplier-payout query failed"
|
|
|
|
|
: `${outgoing?.fetched_rows ?? 0} outgoing supplier-payout rows fetched, ${outgoing?.matched_rows ?? 0} matched`;
|
|
|
|
|
: outgoing?.coverage_recovered_by_period_chunking && outgoing.period_chunking_granularity === "month"
|
|
|
|
|
? `${outgoing.period_chunk_count} monthly outgoing supplier-payout probes fetched ${outgoing.fetched_rows} rows total, ${outgoing.matched_rows} matched`
|
|
|
|
|
: `${outgoing?.fetched_rows ?? 0} outgoing supplier-payout rows fetched, ${outgoing?.matched_rows ?? 0} matched`;
|
|
|
|
|
return `${incomingSummary}; ${outgoingSummary}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -704,7 +925,7 @@ function buildLifecycleConfirmedFacts(result: AddressMcpQueryExecutorResult, cou
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function buildValueFlowConfirmedFacts(
|
|
|
|
|
result: AddressMcpQueryExecutorResult,
|
|
|
|
|
result: AssistantMcpDiscoveryCoverageAwareQueryResult,
|
|
|
|
|
counterparty: string | null,
|
|
|
|
|
direction: AssistantMcpDiscoveryDerivedValueFlow["value_flow_direction"]
|
|
|
|
|
): string[] {
|
|
|
|
@@ -760,6 +981,11 @@ function buildValueFlowInferredFacts(derived: AssistantMcpDiscoveryDerivedValueF
|
|
|
|
|
} else {
|
|
|
|
|
facts.push("Counterparty value-flow total was calculated from confirmed 1C movement rows");
|
|
|
|
|
}
|
|
|
|
|
if (derived.coverage_recovered_by_period_chunking && derived.period_chunking_granularity === "month") {
|
|
|
|
|
facts.push(
|
|
|
|
|
"Requested period coverage was recovered through monthly 1C value-flow probes after the broad probe hit the row limit"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
if (derived.aggregation_axis === "month" && derived.monthly_breakdown.length > 0) {
|
|
|
|
|
facts.push("Counterparty monthly value-flow breakdown was grouped by month over confirmed 1C movement rows");
|
|
|
|
|
}
|
|
|
|
@@ -773,6 +999,11 @@ function buildBidirectionalValueFlowInferredFacts(
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
const facts = ["Counterparty net value-flow was calculated as incoming confirmed 1C rows minus outgoing confirmed 1C rows"];
|
|
|
|
|
if (derived.coverage_recovered_by_period_chunking && derived.period_chunking_granularity === "month") {
|
|
|
|
|
facts.push(
|
|
|
|
|
"Requested period coverage for bidirectional value-flow was recovered through monthly 1C side probes after a broad probe hit the row limit"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
if (derived.aggregation_axis === "month" && derived.monthly_breakdown.length > 0) {
|
|
|
|
|
facts.push("Counterparty monthly net value-flow breakdown was grouped by month over confirmed incoming and outgoing 1C rows");
|
|
|
|
|
}
|
|
|
|
@@ -933,12 +1164,12 @@ export async function executeAssistantMcpDiscoveryPilot(
|
|
|
|
|
const aggregationAxis = aggregationAxisForPlanner(planner);
|
|
|
|
|
|
|
|
|
|
if (valueFlowPilotEligible) {
|
|
|
|
|
let queryResult: AddressMcpQueryExecutorResult | null = null;
|
|
|
|
|
let queryResult: AssistantMcpDiscoveryCoverageAwareQueryResult | null = null;
|
|
|
|
|
const filters = buildValueFlowFilters(planner);
|
|
|
|
|
const valueFlowProfile = valueFlowPilotProfile(planner);
|
|
|
|
|
if (valueFlowProfile.direction === "bidirectional_net_value_flow") {
|
|
|
|
|
let incomingResult: AddressMcpQueryExecutorResult | null = null;
|
|
|
|
|
let outgoingResult: AddressMcpQueryExecutorResult | null = null;
|
|
|
|
|
let incomingResult: AssistantMcpDiscoveryCoverageAwareQueryResult | null = null;
|
|
|
|
|
let outgoingResult: AssistantMcpDiscoveryCoverageAwareQueryResult | null = null;
|
|
|
|
|
const incomingSelection = selectAddressRecipe("customer_revenue_and_payments", filters);
|
|
|
|
|
const outgoingSelection = selectAddressRecipe("supplier_payouts_profile", filters);
|
|
|
|
|
if (!incomingSelection.selected_recipe || !outgoingSelection.selected_recipe) {
|
|
|
|
@@ -965,8 +1196,6 @@ export async function executeAssistantMcpDiscoveryPilot(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pushReason(reasonCodes, "pilot_bidirectional_value_flow_recipes_selected");
|
|
|
|
|
const incomingRecipePlan = buildAddressRecipePlan(incomingSelection.selected_recipe, filters);
|
|
|
|
|
const outgoingRecipePlan = buildAddressRecipePlan(outgoingSelection.selected_recipe, filters);
|
|
|
|
|
|
|
|
|
|
for (const step of dryRun.execution_steps) {
|
|
|
|
|
if (step.primitive_id !== "query_movements") {
|
|
|
|
@@ -977,28 +1206,44 @@ export async function executeAssistantMcpDiscoveryPilot(
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
incomingResult = await deps.executeAddressMcpQuery({
|
|
|
|
|
query: incomingRecipePlan.query,
|
|
|
|
|
limit: incomingRecipePlan.limit,
|
|
|
|
|
account_scope: incomingRecipePlan.account_scope
|
|
|
|
|
const incomingExecution = await executeCoverageAwareValueFlowQuery({
|
|
|
|
|
primitiveId: step.primitive_id,
|
|
|
|
|
recipePlanBuilder: (scopedFilters) => buildAddressRecipePlan(incomingSelection.selected_recipe!, scopedFilters),
|
|
|
|
|
baseFilters: filters,
|
|
|
|
|
dateScope,
|
|
|
|
|
maxProbeCount: planner.discovery_plan.execution_budget.max_probe_count,
|
|
|
|
|
maxRowsPerProbe: planner.discovery_plan.execution_budget.max_rows_per_probe,
|
|
|
|
|
deps
|
|
|
|
|
});
|
|
|
|
|
outgoingResult = await deps.executeAddressMcpQuery({
|
|
|
|
|
query: outgoingRecipePlan.query,
|
|
|
|
|
limit: outgoingRecipePlan.limit,
|
|
|
|
|
account_scope: outgoingRecipePlan.account_scope
|
|
|
|
|
const outgoingExecution = await executeCoverageAwareValueFlowQuery({
|
|
|
|
|
primitiveId: step.primitive_id,
|
|
|
|
|
recipePlanBuilder: (scopedFilters) => buildAddressRecipePlan(outgoingSelection.selected_recipe!, scopedFilters),
|
|
|
|
|
baseFilters: filters,
|
|
|
|
|
dateScope,
|
|
|
|
|
maxProbeCount: planner.discovery_plan.execution_budget.max_probe_count,
|
|
|
|
|
maxRowsPerProbe: planner.discovery_plan.execution_budget.max_rows_per_probe,
|
|
|
|
|
deps
|
|
|
|
|
});
|
|
|
|
|
incomingResult = incomingExecution.result;
|
|
|
|
|
outgoingResult = outgoingExecution.result;
|
|
|
|
|
pushUnique(executedPrimitives, step.primitive_id);
|
|
|
|
|
probeResults.push(queryResultToProbeResult(step.primitive_id, incomingResult));
|
|
|
|
|
probeResults.push(queryResultToProbeResult(step.primitive_id, outgoingResult));
|
|
|
|
|
if (incomingResult.error) {
|
|
|
|
|
pushUnique(queryLimitations, incomingResult.error);
|
|
|
|
|
probeResults.push(...incomingExecution.probe_results, ...outgoingExecution.probe_results);
|
|
|
|
|
for (const limitation of [...incomingExecution.query_limitations, ...outgoingExecution.query_limitations]) {
|
|
|
|
|
pushUnique(queryLimitations, limitation);
|
|
|
|
|
}
|
|
|
|
|
if (incomingResult?.error) {
|
|
|
|
|
pushReason(reasonCodes, "pilot_bidirectional_incoming_query_movements_mcp_error");
|
|
|
|
|
}
|
|
|
|
|
if (outgoingResult.error) {
|
|
|
|
|
pushUnique(queryLimitations, outgoingResult.error);
|
|
|
|
|
if (outgoingResult?.error) {
|
|
|
|
|
pushReason(reasonCodes, "pilot_bidirectional_outgoing_query_movements_mcp_error");
|
|
|
|
|
}
|
|
|
|
|
if (!incomingResult.error || !outgoingResult.error) {
|
|
|
|
|
if (incomingResult?.coverage_recovered_by_period_chunking) {
|
|
|
|
|
pushReason(reasonCodes, "pilot_bidirectional_incoming_monthly_period_chunking_recovered_coverage");
|
|
|
|
|
}
|
|
|
|
|
if (outgoingResult?.coverage_recovered_by_period_chunking) {
|
|
|
|
|
pushReason(reasonCodes, "pilot_bidirectional_outgoing_monthly_period_chunking_recovered_coverage");
|
|
|
|
|
}
|
|
|
|
|
if (!incomingResult?.error || !outgoingResult?.error) {
|
|
|
|
|
pushReason(reasonCodes, "pilot_bidirectional_query_movements_mcp_executed");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -1009,7 +1254,6 @@ export async function executeAssistantMcpDiscoveryPilot(
|
|
|
|
|
outgoingResult,
|
|
|
|
|
counterparty,
|
|
|
|
|
periodScope: dateScope,
|
|
|
|
|
probeLimit: planner.discovery_plan.execution_budget.max_rows_per_probe,
|
|
|
|
|
aggregationAxis
|
|
|
|
|
});
|
|
|
|
|
if (derivedBidirectionalValueFlow) {
|
|
|
|
@@ -1080,26 +1324,35 @@ export async function executeAssistantMcpDiscoveryPilot(
|
|
|
|
|
: "pilot_customer_revenue_recipe_selected"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const recipePlan = buildAddressRecipePlan(selection.selected_recipe, filters);
|
|
|
|
|
for (const step of dryRun.execution_steps) {
|
|
|
|
|
if (step.primitive_id !== "query_movements") {
|
|
|
|
|
skippedPrimitives.push(step.primitive_id);
|
|
|
|
|
probeResults.push(skippedProbeResult(step, "pilot_value_flow_uses_query_movements_and_derives_aggregate"));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
queryResult = await deps.executeAddressMcpQuery({
|
|
|
|
|
query: recipePlan.query,
|
|
|
|
|
limit: recipePlan.limit,
|
|
|
|
|
account_scope: recipePlan.account_scope
|
|
|
|
|
const execution = await executeCoverageAwareValueFlowQuery({
|
|
|
|
|
primitiveId: step.primitive_id,
|
|
|
|
|
recipePlanBuilder: (scopedFilters) => buildAddressRecipePlan(selection.selected_recipe!, scopedFilters),
|
|
|
|
|
baseFilters: filters,
|
|
|
|
|
dateScope,
|
|
|
|
|
maxProbeCount: planner.discovery_plan.execution_budget.max_probe_count,
|
|
|
|
|
maxRowsPerProbe: planner.discovery_plan.execution_budget.max_rows_per_probe,
|
|
|
|
|
deps
|
|
|
|
|
});
|
|
|
|
|
executedPrimitives.push(step.primitive_id);
|
|
|
|
|
probeResults.push(queryResultToProbeResult(step.primitive_id, queryResult));
|
|
|
|
|
if (queryResult.error) {
|
|
|
|
|
pushUnique(queryLimitations, queryResult.error);
|
|
|
|
|
queryResult = execution.result;
|
|
|
|
|
pushUnique(executedPrimitives, step.primitive_id);
|
|
|
|
|
probeResults.push(...execution.probe_results);
|
|
|
|
|
for (const limitation of execution.query_limitations) {
|
|
|
|
|
pushUnique(queryLimitations, limitation);
|
|
|
|
|
}
|
|
|
|
|
if (queryResult?.error) {
|
|
|
|
|
pushReason(reasonCodes, "pilot_query_movements_mcp_error");
|
|
|
|
|
} else {
|
|
|
|
|
pushReason(reasonCodes, "pilot_query_movements_mcp_executed");
|
|
|
|
|
}
|
|
|
|
|
if (queryResult?.coverage_recovered_by_period_chunking) {
|
|
|
|
|
pushReason(reasonCodes, "pilot_monthly_period_chunking_recovered_coverage");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const sourceRowsSummary = queryResult ? summarizeValueFlowRows(queryResult) : null;
|
|
|
|
@@ -1108,7 +1361,6 @@ export async function executeAssistantMcpDiscoveryPilot(
|
|
|
|
|
counterparty,
|
|
|
|
|
dateScope,
|
|
|
|
|
valueFlowProfile.direction,
|
|
|
|
|
planner.discovery_plan.execution_budget.max_rows_per_probe,
|
|
|
|
|
aggregationAxis
|
|
|
|
|
);
|
|
|
|
|
if (derivedValueFlow) {
|
|
|
|
|