Очистить бизнес-язык ответов phase98
This commit is contained in:
+59
-43
@@ -86,7 +86,7 @@ function userFacingLines(values) {
|
||||
return uniqueStrings(values).filter((line) => !hasInternalMechanics(line));
|
||||
}
|
||||
function sanitizeUserFacingMechanics(value) {
|
||||
return String(value ?? "").replace(/MCP-срез(?:ом|у|е|а)?/giu, (match) => {
|
||||
let text = String(value ?? "").replace(/MCP-срез(?:ом|у|е|а)?/giu, (match) => {
|
||||
const normalized = match.toLowerCase();
|
||||
if (normalized.endsWith("ом")) {
|
||||
return "срезом 1С";
|
||||
@@ -102,6 +102,28 @@ function sanitizeUserFacingMechanics(value) {
|
||||
}
|
||||
return "срез 1С";
|
||||
});
|
||||
const replacements = [
|
||||
[/\bprocurement-concentration route\b/giu, "проверка концентрации закупок/исходящих платежей"],
|
||||
[/\breviewed vendor-risk route\b/giu, "отдельная проверка поставщицкого риска"],
|
||||
[/\bvendor-risk route\b/giu, "проверка поставщицкого риска"],
|
||||
[/\bdue-date route\b/giu, "проверка просрочки по срокам оплаты"],
|
||||
[/\bdebt-quality proxy\b/giu, "ограниченный долговой сигнал"],
|
||||
[/\bstaleness-risk proxy\b/giu, "косвенный признак залежалости"],
|
||||
[/\bstaleness risk proxy\b/giu, "косвенный признак залежалости"],
|
||||
[/\boperating-flow proxy\b/giu, "денежный операционный показатель"],
|
||||
[/\btrading-margin proxy\b/giu, "товарная маржинальность по проверенным документам"],
|
||||
[/\bprocurement concentration proxy\b/giu, "сигнал концентрации закупок/исходящих платежей"],
|
||||
[/\boutgoing cash concentration proxy\b/giu, "сигнал концентрации исходящих денег"],
|
||||
[/\bproxy-сигналы\b/giu, "косвенные признаки"],
|
||||
[/\bproxy\b/giu, "косвенный показатель"],
|
||||
[/\bsales-to-stock\b/giu, "отношение продаж к остатку"],
|
||||
[/\boverdue\/due-date aging\b/giu, "просрочку по договорным срокам"],
|
||||
[/\bP&L\b/gu, "полный отчет о прибылях и убытках"]
|
||||
];
|
||||
for (const [pattern, replacement] of replacements) {
|
||||
text = text.replace(pattern, replacement);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
function localizeLine(value) {
|
||||
const sanitizedValue = sanitizeUserFacingMechanics(value);
|
||||
@@ -385,6 +407,10 @@ function businessOverviewCoverageLimitLine(overview) {
|
||||
? `Важно: по направлению ${limited.join(" и ")} проверка достигла лимита строк; это расширенный проверенный срез найденных строк, но не гарантия полного бухгалтерского оборота без отдельной полной выгрузки.`
|
||||
: null;
|
||||
}
|
||||
function joinBusinessReplyLines(lines) {
|
||||
const reply = userFacingLines(lines.map(localizeLine)).join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
}
|
||||
function businessOverviewYearRowsLine(overview) {
|
||||
const years = Array.isArray(overview.yearly_breakdown) ? overview.yearly_breakdown : [];
|
||||
const values = years
|
||||
@@ -577,8 +603,7 @@ function buildCompactBidirectionalValueFlowReply(entryPoint, draft) {
|
||||
if (fallbackNextStep) {
|
||||
lines.push(`Следующий шаг: ${localizeLine(fallbackNextStep)}`);
|
||||
}
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
function compactComparable(value) {
|
||||
return String(value ?? "")
|
||||
@@ -748,8 +773,7 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) {
|
||||
: "сумма не распознана";
|
||||
lines.push(`Коротко: по бухгалтерскому маршруту 90/91/99 за ${periodScope} подтвержден ${directionText}: ${amountText}${marginPct ? `; маржа к выручке 90.01 ${marginPct}` : "; маржа к выручке 90.01 не рассчитана"}.`);
|
||||
lines.push("Это учетный финрезультат по найденным строкам закрытия периода в 1С, а не внешний аудит и не юридически подтвержденная отчетность.");
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
const headline = toNonEmptyString(draft.headline);
|
||||
const cleanHeadline = headline?.replace(/^Коротко:\s*/iu, "").trim();
|
||||
@@ -770,8 +794,7 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) {
|
||||
if (limitLine) {
|
||||
lines.push(limitLine);
|
||||
}
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
if (debtDueDateBoundary) {
|
||||
const dueDateAging = toRecordObject(overview.debt_due_date_aging);
|
||||
@@ -786,36 +809,35 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) {
|
||||
const rowsWithAmount = typeof dueDateAging.rows_with_amount === "number" && Number.isFinite(dueDateAging.rows_with_amount)
|
||||
? dueDateAging.rows_with_amount
|
||||
: null;
|
||||
const dueDateScopePrefix = organizationScope ? `по компании ${organizationScope} ` : "";
|
||||
if (status === "confirmed_overdue") {
|
||||
lines.push(`Коротко: на ${asOfDate} подтвержденная просрочка есть: ${overdueAmount ?? "сумма не распознана"} по ${dueDateAging.overdue_rows ?? "найденным"} строкам.`);
|
||||
lines.push("Основа ответа: открытые расчеты 60/62/76, договорный срок оплаты и дата расчетного документа; это уже due-date route, не старение договора как proxy.");
|
||||
lines.push(`Коротко: ${dueDateScopePrefix}на ${asOfDate} подтвержденная просрочка есть: ${overdueAmount ?? "сумма не распознана"} по ${dueDateAging.overdue_rows ?? "найденным"} строкам.`);
|
||||
lines.push("Основа ответа: открытые расчеты 60/62/76, договорный срок оплаты и дата расчетного документа; это проверка просрочки по срокам оплаты, а не просто возраст договора.");
|
||||
}
|
||||
else if (status === "no_payment_terms_configured") {
|
||||
lines.push(`Коротко: на ${asOfDate} подтвержденной просрочки нет: открытые расчеты проверены${grossAmount ? ` на ${grossAmount}` : ""}, но в найденных договорах срок оплаты не установлен.`);
|
||||
lines.push(`Коротко: ${dueDateScopePrefix}на ${asOfDate} подтвержденной просрочки нет: открытые расчеты проверены${grossAmount ? ` на ${grossAmount}` : ""}, но в найденных договорах срок оплаты не установлен.`);
|
||||
lines.push(rowsWithAmount !== null
|
||||
? `Проверено строк с суммой: ${rowsWithAmount}. Без установленного срока оплаты нельзя честно назвать эти остатки просрочкой.`
|
||||
: "Без установленного срока оплаты нельзя честно назвать эти остатки просрочкой.");
|
||||
}
|
||||
else if (status === "insufficient_due_date_basis") {
|
||||
lines.push(`Коротко: due-date route запущен на ${asOfDate}, но просрочка не подтверждена: по строкам с установленным сроком оплаты не хватило даты расчетного документа.`);
|
||||
lines.push(`Коротко: ${dueDateScopePrefix}на ${asOfDate} просрочка не подтверждена: по строкам с установленным сроком оплаты не хватило даты расчетного документа.`);
|
||||
if (rowsWithPaymentTerms !== null) {
|
||||
lines.push(`Строк с установленным сроком оплаты: ${rowsWithPaymentTerms}; нужен документ-основание с датой для расчета due date.`);
|
||||
lines.push(`Строк с установленным сроком оплаты: ${rowsWithPaymentTerms}; нужен документ-основание с датой, чтобы посчитать договорный срок оплаты.`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
lines.push(`Коротко: due-date route на ${asOfDate} проверен, подтвержденной просрочки не найдено${rowsWithPaymentTerms !== null ? `; строк с установленным сроком оплаты ${rowsWithPaymentTerms}` : ""}.`);
|
||||
lines.push(`Коротко: ${dueDateScopePrefix}на ${asOfDate} проверка просрочки по срокам оплаты выполнена, подтвержденной просрочки не найдено${rowsWithPaymentTerms !== null ? `; строк с установленным сроком оплаты ${rowsWithPaymentTerms}` : ""}.`);
|
||||
}
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
const headline = toNonEmptyString(draft.headline);
|
||||
const cleanHeadline = headline?.replace(/^Коротко:\s*/iu, "").trim();
|
||||
lines.push(cleanHeadline
|
||||
? `Коротко: ${localizeLine(cleanHeadline)}`
|
||||
: "Коротко: нельзя точно определить, какая дебиторка просрочена, по текущему срезу 1С; есть только debt-quality proxy, но нет проверенного due-date маршрута.");
|
||||
lines.push("Проверить нужно отдельно: договоры, сроки оплаты, погашение и закрытие задолженности; без этого нельзя доказать overdue/due-date aging.");
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
: "Коротко: нельзя точно определить, какая дебиторка просрочена, по текущему срезу 1С; есть только ограниченный долговой сигнал, но нет проверки договорных сроков оплаты.");
|
||||
lines.push("Проверить нужно отдельно: договоры, сроки оплаты, погашение и закрытие задолженности; без этого нельзя доказать просрочку по договорным срокам.");
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
if (vendorRiskBoundary) {
|
||||
const vendorProcurementQuality = toRecordObject(overview.vendor_procurement_quality);
|
||||
@@ -839,7 +861,7 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) {
|
||||
const periodScope = toNonEmptyString(vendorProcurementQuality.period_scope) ?? period;
|
||||
const totalText = totalOutgoing ? `; всего исходящих платежей в проверенном срезе ${totalOutgoing}` : "";
|
||||
if (status === "financial_institution_leads_outgoing_cash") {
|
||||
lines.push(`Коротко: проверенный procurement-concentration route за ${periodScope} не подтверждает зависимость от обычного поставщика: крупнейший получатель исходящих денег ${topOutgoingName ?? "не распознан"}${topOutgoingShare ? ` держит около ${topOutgoingShare}` : ""}${topOutgoingAmount ? ` (${topOutgoingAmount})` : ""}, но по названию это банк/финансовая организация${totalText}.`);
|
||||
lines.push(`Коротко: проверка концентрации закупок/исходящих платежей за ${periodScope} не подтверждает зависимость от обычного поставщика: крупнейший получатель исходящих денег ${topOutgoingName ?? "не распознан"}${topOutgoingShare ? ` держит около ${topOutgoingShare}` : ""}${topOutgoingAmount ? ` (${topOutgoingAmount})` : ""}, но по названию это банк/финансовая организация${totalText}.`);
|
||||
const financialHintText = financialFlowHintTextRuFromRecord(topOutgoingRecord);
|
||||
if (financialHintText) {
|
||||
lines.push(financialHintText);
|
||||
@@ -849,19 +871,18 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) {
|
||||
}
|
||||
}
|
||||
else if (status === "reviewed_procurement_concentration") {
|
||||
lines.push(`Коротко: проверенный procurement-concentration route за ${periodScope} нашел основную зависимость исходящего потока: ${topOutgoingName ?? nonFinancialName ?? "получатель не распознан"}${topOutgoingShare ? ` держит около ${topOutgoingShare}` : nonFinancialShare ? ` держит около ${nonFinancialShare}` : ""}${topOutgoingAmount ? ` (${topOutgoingAmount})` : nonFinancialAmount ? ` (${nonFinancialAmount})` : ""}${totalText}.`);
|
||||
lines.push(`Коротко: точный риск зависимости от одного поставщика не подтвержден полностью; проверка концентрации закупок/исходящих платежей за ${periodScope} нашла крупнейшего получателя исходящего потока: ${topOutgoingName ?? nonFinancialName ?? "получатель не распознан"}${topOutgoingShare ? ` держит около ${topOutgoingShare}` : nonFinancialShare ? ` держит около ${nonFinancialShare}` : ""}${topOutgoingAmount ? ` (${topOutgoingAmount})` : nonFinancialAmount ? ` (${nonFinancialAmount})` : ""}${totalText}.`);
|
||||
}
|
||||
else {
|
||||
lines.push(`Коротко: procurement-concentration route за ${periodScope} отработал, но надежной небанковской концентрации поставщика по найденным исходящим платежам не хватает${totalText}.`);
|
||||
lines.push(`Коротко: проверка концентрации закупок/исходящих платежей за ${periodScope} выполнена, но надежной небанковской концентрации поставщика по найденным исходящим платежам не хватает${totalText}.`);
|
||||
}
|
||||
const contractText = typeof vendorProcurementQuality.used_contracts === "number" && Number.isFinite(vendorProcurementQuality.used_contracts)
|
||||
? typeof vendorProcurementQuality.total_contracts === "number" && Number.isFinite(vendorProcurementQuality.total_contracts)
|
||||
? ` Договорный профиль: используется ${vendorProcurementQuality.used_contracts}/${vendorProcurementQuality.total_contracts} договоров${typeof vendorProcurementQuality.used_contract_share_pct === "number" && Number.isFinite(vendorProcurementQuality.used_contract_share_pct) ? ` (${vendorProcurementQuality.used_contract_share_pct}%)` : ""}.`
|
||||
: ` Договорный профиль: используется ${vendorProcurementQuality.used_contracts} договоров.`
|
||||
: "";
|
||||
lines.push(`Что не доказано этим маршрутом: надежность поставщика, качество поставок, договорные условия, назначение каждого платежа и полная структура всех расходов.${contractText}`);
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
lines.push(`Что не доказано этим срезом: надежность поставщика, качество поставок, договорные условия, назначение каждого платежа и полная структура всех расходов.${contractText}`);
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
const supplierBasis = topSupplier
|
||||
? topSupplierLooksFinancial
|
||||
@@ -870,26 +891,24 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) {
|
||||
: outgoingAmount
|
||||
? `исходящие платежи/закупочный поток в проверенном срезе: ${outgoingAmount}`
|
||||
: "есть только ограниченный срез исходящих платежей без полного vendor-risk профиля";
|
||||
const proxyLabel = topSupplierLooksFinancial ? "outgoing cash concentration proxy" : "procurement concentration proxy";
|
||||
const proxyLabel = topSupplierLooksFinancial
|
||||
? "сигнал концентрации исходящих денег"
|
||||
: "сигнал концентрации закупок/исходящих платежей";
|
||||
lines.push(`Коротко: точный риск зависимости от одного поставщика по текущим данным не подтвержден; есть только ${proxyLabel}: ${supplierBasis}.`);
|
||||
lines.push("Это сигнал концентрации закупок/исходящих платежей, а не полный аудит надежности поставщиков, условий, качества и структуры всех расходов.");
|
||||
lines.push("Для точного вывода нужен отдельный reviewed vendor-risk route: поставщики, договорные условия, качество поставок, сроки, доля в закупках и полная структура расходов.");
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
lines.push("Для точного вывода нужна отдельная проверка поставщицкого риска: поставщики, договорные условия, качество поставок, сроки, доля в закупках и полная структура расходов.");
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
if (inventoryReserveBoundary) {
|
||||
const headline = toNonEmptyString(draft.headline);
|
||||
const inventoryQualityEvents = toRecordObject(overview.inventory_quality_events);
|
||||
const cleanHeadline = headline?.replace(/^Коротко:\s*/iu, "").trim();
|
||||
lines.push(cleanHeadline
|
||||
? `Коротко: ${localizeLine(cleanHeadline)}`
|
||||
const reserveBasis = cleanHeadline ? localizeLine(cleanHeadline).replace(/^проверил/iu, "Проверены") : null;
|
||||
lines.push(reserveBasis
|
||||
? `Коротко: точно подтвердить резерв под неликвиды нельзя. ${reserveBasis}`
|
||||
: "Коротко: точно подтвердить резерв под неликвиды по текущим данным нельзя.");
|
||||
if (inventoryQualityEvents) {
|
||||
if (limitLine) {
|
||||
lines.push(limitLine);
|
||||
}
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
const boundaryLines = userFacingLines([
|
||||
...toStringList(draft.unknown_lines),
|
||||
@@ -900,9 +919,8 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) {
|
||||
if (boundaryLines.length > 0) {
|
||||
lines.push(...boundaryLines.map(localizeLine));
|
||||
}
|
||||
lines.push("Проверить нужно отдельно: складской срез на дату, учетную политику резервов, списания и ликвидационную стоимость; proxy-сигналы нельзя выдавать за доказанный факт резерва.");
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
lines.push("Проверить нужно отдельно: складской срез на дату, учетную политику резервов, списания и ликвидационную стоимость; косвенные признаки нельзя выдавать за доказанный факт резерва.");
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
if (crossScopeExecutiveSummary && separateSubject && previousCounterpartySummary && (incomingAmount || outgoingAmount || netAmount)) {
|
||||
lines.push(`Коротко: по компании ${organizationScope ?? "в выбранном контуре"} ${period} подтвержден денежный срез: получили ${incomingAmount ?? "0 руб."}, исходящие платежи/списания ${outgoingAmount ?? "0 руб."}, ${netDirection} ${sentenceAmount(netAmount) ?? netAmount ?? "0 руб."}${previousCounterpartySummary.lead}; можно утверждать только эти подтвержденные срезы, нельзя называть это чистой прибылью, полным оборотом или доказанной ролью главного клиента/поставщика.`);
|
||||
@@ -912,8 +930,7 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) {
|
||||
if (limitLine) {
|
||||
lines.push(limitLine);
|
||||
}
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
if (rankingNeed) {
|
||||
const incomingLeader = strongestIncomingYear(overview);
|
||||
@@ -1005,8 +1022,7 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) {
|
||||
lines.push(limitLine);
|
||||
}
|
||||
lines.push("Для ответа именно про чистую прибыль нужно отдельно считать себестоимость, расходы и закрытие периода.");
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
function statusFrom(entryPoint) {
|
||||
if (!entryPoint || entryPoint.entry_status === "skipped_not_applicable") {
|
||||
|
||||
@@ -120,7 +120,7 @@ function userFacingLines(values: string[]): string[] {
|
||||
}
|
||||
|
||||
function sanitizeUserFacingMechanics(value: string): string {
|
||||
return String(value ?? "").replace(/MCP-срез(?:ом|у|е|а)?/giu, (match) => {
|
||||
let text = String(value ?? "").replace(/MCP-срез(?:ом|у|е|а)?/giu, (match) => {
|
||||
const normalized = match.toLowerCase();
|
||||
if (normalized.endsWith("ом")) {
|
||||
return "срезом 1С";
|
||||
@@ -136,6 +136,28 @@ function sanitizeUserFacingMechanics(value: string): string {
|
||||
}
|
||||
return "срез 1С";
|
||||
});
|
||||
const replacements: Array<[RegExp, string]> = [
|
||||
[/\bprocurement-concentration route\b/giu, "проверка концентрации закупок/исходящих платежей"],
|
||||
[/\breviewed vendor-risk route\b/giu, "отдельная проверка поставщицкого риска"],
|
||||
[/\bvendor-risk route\b/giu, "проверка поставщицкого риска"],
|
||||
[/\bdue-date route\b/giu, "проверка просрочки по срокам оплаты"],
|
||||
[/\bdebt-quality proxy\b/giu, "ограниченный долговой сигнал"],
|
||||
[/\bstaleness-risk proxy\b/giu, "косвенный признак залежалости"],
|
||||
[/\bstaleness risk proxy\b/giu, "косвенный признак залежалости"],
|
||||
[/\boperating-flow proxy\b/giu, "денежный операционный показатель"],
|
||||
[/\btrading-margin proxy\b/giu, "товарная маржинальность по проверенным документам"],
|
||||
[/\bprocurement concentration proxy\b/giu, "сигнал концентрации закупок/исходящих платежей"],
|
||||
[/\boutgoing cash concentration proxy\b/giu, "сигнал концентрации исходящих денег"],
|
||||
[/\bproxy-сигналы\b/giu, "косвенные признаки"],
|
||||
[/\bproxy\b/giu, "косвенный показатель"],
|
||||
[/\bsales-to-stock\b/giu, "отношение продаж к остатку"],
|
||||
[/\boverdue\/due-date aging\b/giu, "просрочку по договорным срокам"],
|
||||
[/\bP&L\b/gu, "полный отчет о прибылях и убытках"]
|
||||
];
|
||||
for (const [pattern, replacement] of replacements) {
|
||||
text = text.replace(pattern, replacement);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
function localizeLine(value: string): string {
|
||||
@@ -454,6 +476,11 @@ function businessOverviewCoverageLimitLine(overview: Record<string, unknown>): s
|
||||
: null;
|
||||
}
|
||||
|
||||
function joinBusinessReplyLines(lines: string[]): string | null {
|
||||
const reply = userFacingLines(lines.map(localizeLine)).join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
}
|
||||
|
||||
function businessOverviewYearRowsLine(overview: Record<string, unknown>): string | null {
|
||||
const years = Array.isArray(overview.yearly_breakdown) ? overview.yearly_breakdown : [];
|
||||
const values = years
|
||||
@@ -670,8 +697,7 @@ function buildCompactBidirectionalValueFlowReply(
|
||||
lines.push(`Следующий шаг: ${localizeLine(fallbackNextStep)}`);
|
||||
}
|
||||
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
|
||||
function compactComparable(value: string | null): string {
|
||||
@@ -883,8 +909,7 @@ function buildCompactBusinessOverviewReply(
|
||||
lines.push(
|
||||
"Это учетный финрезультат по найденным строкам закрытия периода в 1С, а не внешний аудит и не юридически подтвержденная отчетность."
|
||||
);
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
const headline = toNonEmptyString(draft.headline);
|
||||
const cleanHeadline = headline?.replace(/^Коротко:\s*/iu, "").trim();
|
||||
@@ -909,8 +934,7 @@ function buildCompactBusinessOverviewReply(
|
||||
if (limitLine) {
|
||||
lines.push(limitLine);
|
||||
}
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
|
||||
if (debtDueDateBoundary) {
|
||||
@@ -928,14 +952,15 @@ function buildCompactBusinessOverviewReply(
|
||||
typeof dueDateAging.rows_with_amount === "number" && Number.isFinite(dueDateAging.rows_with_amount)
|
||||
? dueDateAging.rows_with_amount
|
||||
: null;
|
||||
const dueDateScopePrefix = organizationScope ? `по компании ${organizationScope} ` : "";
|
||||
if (status === "confirmed_overdue") {
|
||||
lines.push(
|
||||
`Коротко: на ${asOfDate} подтвержденная просрочка есть: ${overdueAmount ?? "сумма не распознана"} по ${dueDateAging.overdue_rows ?? "найденным"} строкам.`
|
||||
`Коротко: ${dueDateScopePrefix}на ${asOfDate} подтвержденная просрочка есть: ${overdueAmount ?? "сумма не распознана"} по ${dueDateAging.overdue_rows ?? "найденным"} строкам.`
|
||||
);
|
||||
lines.push("Основа ответа: открытые расчеты 60/62/76, договорный срок оплаты и дата расчетного документа; это уже due-date route, не старение договора как proxy.");
|
||||
lines.push("Основа ответа: открытые расчеты 60/62/76, договорный срок оплаты и дата расчетного документа; это проверка просрочки по срокам оплаты, а не просто возраст договора.");
|
||||
} else if (status === "no_payment_terms_configured") {
|
||||
lines.push(
|
||||
`Коротко: на ${asOfDate} подтвержденной просрочки нет: открытые расчеты проверены${grossAmount ? ` на ${grossAmount}` : ""}, но в найденных договорах срок оплаты не установлен.`
|
||||
`Коротко: ${dueDateScopePrefix}на ${asOfDate} подтвержденной просрочки нет: открытые расчеты проверены${grossAmount ? ` на ${grossAmount}` : ""}, но в найденных договорах срок оплаты не установлен.`
|
||||
);
|
||||
lines.push(
|
||||
rowsWithAmount !== null
|
||||
@@ -944,31 +969,29 @@ function buildCompactBusinessOverviewReply(
|
||||
);
|
||||
} else if (status === "insufficient_due_date_basis") {
|
||||
lines.push(
|
||||
`Коротко: due-date route запущен на ${asOfDate}, но просрочка не подтверждена: по строкам с установленным сроком оплаты не хватило даты расчетного документа.`
|
||||
`Коротко: ${dueDateScopePrefix}на ${asOfDate} просрочка не подтверждена: по строкам с установленным сроком оплаты не хватило даты расчетного документа.`
|
||||
);
|
||||
if (rowsWithPaymentTerms !== null) {
|
||||
lines.push(`Строк с установленным сроком оплаты: ${rowsWithPaymentTerms}; нужен документ-основание с датой для расчета due date.`);
|
||||
lines.push(`Строк с установленным сроком оплаты: ${rowsWithPaymentTerms}; нужен документ-основание с датой, чтобы посчитать договорный срок оплаты.`);
|
||||
}
|
||||
} else {
|
||||
lines.push(
|
||||
`Коротко: due-date route на ${asOfDate} проверен, подтвержденной просрочки не найдено${rowsWithPaymentTerms !== null ? `; строк с установленным сроком оплаты ${rowsWithPaymentTerms}` : ""}.`
|
||||
`Коротко: ${dueDateScopePrefix}на ${asOfDate} проверка просрочки по срокам оплаты выполнена, подтвержденной просрочки не найдено${rowsWithPaymentTerms !== null ? `; строк с установленным сроком оплаты ${rowsWithPaymentTerms}` : ""}.`
|
||||
);
|
||||
}
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
const headline = toNonEmptyString(draft.headline);
|
||||
const cleanHeadline = headline?.replace(/^Коротко:\s*/iu, "").trim();
|
||||
lines.push(
|
||||
cleanHeadline
|
||||
? `Коротко: ${localizeLine(cleanHeadline)}`
|
||||
: "Коротко: нельзя точно определить, какая дебиторка просрочена, по текущему срезу 1С; есть только debt-quality proxy, но нет проверенного due-date маршрута."
|
||||
: "Коротко: нельзя точно определить, какая дебиторка просрочена, по текущему срезу 1С; есть только ограниченный долговой сигнал, но нет проверки договорных сроков оплаты."
|
||||
);
|
||||
lines.push(
|
||||
"Проверить нужно отдельно: договоры, сроки оплаты, погашение и закрытие задолженности; без этого нельзя доказать overdue/due-date aging."
|
||||
"Проверить нужно отдельно: договоры, сроки оплаты, погашение и закрытие задолженности; без этого нельзя доказать просрочку по договорным срокам."
|
||||
);
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
|
||||
if (vendorRiskBoundary) {
|
||||
@@ -996,7 +1019,7 @@ function buildCompactBusinessOverviewReply(
|
||||
const totalText = totalOutgoing ? `; всего исходящих платежей в проверенном срезе ${totalOutgoing}` : "";
|
||||
if (status === "financial_institution_leads_outgoing_cash") {
|
||||
lines.push(
|
||||
`Коротко: проверенный procurement-concentration route за ${periodScope} не подтверждает зависимость от обычного поставщика: крупнейший получатель исходящих денег ${topOutgoingName ?? "не распознан"}${topOutgoingShare ? ` держит около ${topOutgoingShare}` : ""}${topOutgoingAmount ? ` (${topOutgoingAmount})` : ""}, но по названию это банк/финансовая организация${totalText}.`
|
||||
`Коротко: проверка концентрации закупок/исходящих платежей за ${periodScope} не подтверждает зависимость от обычного поставщика: крупнейший получатель исходящих денег ${topOutgoingName ?? "не распознан"}${topOutgoingShare ? ` держит около ${topOutgoingShare}` : ""}${topOutgoingAmount ? ` (${topOutgoingAmount})` : ""}, но по названию это банк/финансовая организация${totalText}.`
|
||||
);
|
||||
const financialHintText = financialFlowHintTextRuFromRecord(topOutgoingRecord);
|
||||
if (financialHintText) {
|
||||
@@ -1009,11 +1032,11 @@ function buildCompactBusinessOverviewReply(
|
||||
}
|
||||
} else if (status === "reviewed_procurement_concentration") {
|
||||
lines.push(
|
||||
`Коротко: проверенный procurement-concentration route за ${periodScope} нашел основную зависимость исходящего потока: ${topOutgoingName ?? nonFinancialName ?? "получатель не распознан"}${topOutgoingShare ? ` держит около ${topOutgoingShare}` : nonFinancialShare ? ` держит около ${nonFinancialShare}` : ""}${topOutgoingAmount ? ` (${topOutgoingAmount})` : nonFinancialAmount ? ` (${nonFinancialAmount})` : ""}${totalText}.`
|
||||
`Коротко: точный риск зависимости от одного поставщика не подтвержден полностью; проверка концентрации закупок/исходящих платежей за ${periodScope} нашла крупнейшего получателя исходящего потока: ${topOutgoingName ?? nonFinancialName ?? "получатель не распознан"}${topOutgoingShare ? ` держит около ${topOutgoingShare}` : nonFinancialShare ? ` держит около ${nonFinancialShare}` : ""}${topOutgoingAmount ? ` (${topOutgoingAmount})` : nonFinancialAmount ? ` (${nonFinancialAmount})` : ""}${totalText}.`
|
||||
);
|
||||
} else {
|
||||
lines.push(
|
||||
`Коротко: procurement-concentration route за ${periodScope} отработал, но надежной небанковской концентрации поставщика по найденным исходящим платежам не хватает${totalText}.`
|
||||
`Коротко: проверка концентрации закупок/исходящих платежей за ${periodScope} выполнена, но надежной небанковской концентрации поставщика по найденным исходящим платежам не хватает${totalText}.`
|
||||
);
|
||||
}
|
||||
const contractText =
|
||||
@@ -1023,10 +1046,9 @@ function buildCompactBusinessOverviewReply(
|
||||
: ` Договорный профиль: используется ${vendorProcurementQuality.used_contracts} договоров.`
|
||||
: "";
|
||||
lines.push(
|
||||
`Что не доказано этим маршрутом: надежность поставщика, качество поставок, договорные условия, назначение каждого платежа и полная структура всех расходов.${contractText}`
|
||||
`Что не доказано этим срезом: надежность поставщика, качество поставок, договорные условия, назначение каждого платежа и полная структура всех расходов.${contractText}`
|
||||
);
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
const supplierBasis = topSupplier
|
||||
? topSupplierLooksFinancial
|
||||
@@ -1035,7 +1057,9 @@ function buildCompactBusinessOverviewReply(
|
||||
: outgoingAmount
|
||||
? `исходящие платежи/закупочный поток в проверенном срезе: ${outgoingAmount}`
|
||||
: "есть только ограниченный срез исходящих платежей без полного vendor-risk профиля";
|
||||
const proxyLabel = topSupplierLooksFinancial ? "outgoing cash concentration proxy" : "procurement concentration proxy";
|
||||
const proxyLabel = topSupplierLooksFinancial
|
||||
? "сигнал концентрации исходящих денег"
|
||||
: "сигнал концентрации закупок/исходящих платежей";
|
||||
lines.push(
|
||||
`Коротко: точный риск зависимости от одного поставщика по текущим данным не подтвержден; есть только ${proxyLabel}: ${supplierBasis}.`
|
||||
);
|
||||
@@ -1043,27 +1067,23 @@ function buildCompactBusinessOverviewReply(
|
||||
"Это сигнал концентрации закупок/исходящих платежей, а не полный аудит надежности поставщиков, условий, качества и структуры всех расходов."
|
||||
);
|
||||
lines.push(
|
||||
"Для точного вывода нужен отдельный reviewed vendor-risk route: поставщики, договорные условия, качество поставок, сроки, доля в закупках и полная структура расходов."
|
||||
"Для точного вывода нужна отдельная проверка поставщицкого риска: поставщики, договорные условия, качество поставок, сроки, доля в закупках и полная структура расходов."
|
||||
);
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
|
||||
if (inventoryReserveBoundary) {
|
||||
const headline = toNonEmptyString(draft.headline);
|
||||
const inventoryQualityEvents = toRecordObject(overview.inventory_quality_events);
|
||||
const cleanHeadline = headline?.replace(/^Коротко:\s*/iu, "").trim();
|
||||
const reserveBasis = cleanHeadline ? localizeLine(cleanHeadline).replace(/^проверил/iu, "Проверены") : null;
|
||||
lines.push(
|
||||
cleanHeadline
|
||||
? `Коротко: ${localizeLine(cleanHeadline)}`
|
||||
reserveBasis
|
||||
? `Коротко: точно подтвердить резерв под неликвиды нельзя. ${reserveBasis}`
|
||||
: "Коротко: точно подтвердить резерв под неликвиды по текущим данным нельзя."
|
||||
);
|
||||
if (inventoryQualityEvents) {
|
||||
if (limitLine) {
|
||||
lines.push(limitLine);
|
||||
}
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
const boundaryLines = userFacingLines([
|
||||
...toStringList(draft.unknown_lines),
|
||||
@@ -1075,10 +1095,9 @@ function buildCompactBusinessOverviewReply(
|
||||
lines.push(...boundaryLines.map(localizeLine));
|
||||
}
|
||||
lines.push(
|
||||
"Проверить нужно отдельно: складской срез на дату, учетную политику резервов, списания и ликвидационную стоимость; proxy-сигналы нельзя выдавать за доказанный факт резерва."
|
||||
"Проверить нужно отдельно: складской срез на дату, учетную политику резервов, списания и ликвидационную стоимость; косвенные признаки нельзя выдавать за доказанный факт резерва."
|
||||
);
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
|
||||
if (crossScopeExecutiveSummary && separateSubject && previousCounterpartySummary && (incomingAmount || outgoingAmount || netAmount)) {
|
||||
@@ -1095,8 +1114,7 @@ function buildCompactBusinessOverviewReply(
|
||||
if (limitLine) {
|
||||
lines.push(limitLine);
|
||||
}
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
|
||||
if (rankingNeed) {
|
||||
@@ -1205,8 +1223,7 @@ function buildCompactBusinessOverviewReply(
|
||||
lines.push(limitLine);
|
||||
}
|
||||
lines.push("Для ответа именно про чистую прибыль нужно отдельно считать себестоимость, расходы и закрытие периода.");
|
||||
const reply = lines.join("\n").trim();
|
||||
return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null;
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
|
||||
function statusFrom(entryPoint: AssistantMcpDiscoveryRuntimeEntryPointContract | null): AssistantMcpDiscoveryResponseCandidateStatus {
|
||||
|
||||
@@ -154,7 +154,7 @@ describe("assistant MCP discovery response candidate", () => {
|
||||
);
|
||||
|
||||
expect(candidate.reply_text).toContain("нельзя точно подтвердить чистую прибыль");
|
||||
expect(candidate.reply_text).toContain("P&L");
|
||||
expect(candidate.reply_text).toContain("полный отчет о прибылях и убытках");
|
||||
expect(candidate.reply_text).toContain("себестоимости");
|
||||
expect(candidate.reply_text).not.toContain("47 628 853");
|
||||
});
|
||||
@@ -208,7 +208,7 @@ describe("assistant MCP discovery response candidate", () => {
|
||||
);
|
||||
|
||||
expect(candidate.reply_text).toContain("риск зависимости");
|
||||
expect(candidate.reply_text).toContain("outgoing cash concentration proxy");
|
||||
expect(candidate.reply_text).toContain("сигнал концентрации исходящих денег");
|
||||
expect(candidate.reply_text).toContain("банк/финансовая организация");
|
||||
expect(candidate.reply_text).toContain("не доказанная зависимость от обычного поставщика");
|
||||
expect(candidate.reply_text).not.toContain("крупнейший подтвержденный поставщик/получатель исходящих платежей: СБЕРБАНК");
|
||||
@@ -296,11 +296,12 @@ describe("assistant MCP discovery response candidate", () => {
|
||||
})
|
||||
);
|
||||
|
||||
expect(candidate.reply_text).toContain("procurement-concentration route");
|
||||
expect(candidate.reply_text).toContain("проверка концентрации закупок/исходящих платежей");
|
||||
expect(candidate.reply_text).toContain("банк/финансовая организация");
|
||||
expect(candidate.reply_text).toContain("Поставщик А");
|
||||
expect(candidate.reply_text).toContain("надежность поставщика");
|
||||
expect(candidate.reply_text).not.toContain("outgoing cash concentration proxy");
|
||||
expect(candidate.reply_text).not.toContain("procurement-concentration route");
|
||||
expect(candidate.reply_text).not.toContain("business_overview_route_template_v1");
|
||||
});
|
||||
|
||||
@@ -464,7 +465,7 @@ describe("assistant MCP discovery response candidate", () => {
|
||||
expect(candidate.reply_text).toContain("12 474 036,91 руб");
|
||||
expect(candidate.reply_text?.split("\n")[0]).toContain("крупнейший источник входящих денег: ГКУ УКРиС");
|
||||
expect(candidate.reply_text?.split("\n")[0]).toContain("крупнейший получатель исходящих денег: ООО Поставщик");
|
||||
expect(candidate.reply_text).toContain("денежный operating-flow proxy");
|
||||
expect(candidate.reply_text).toContain("денежный операционный показатель");
|
||||
expect(candidate.reply_text).not.toContain("Что можно сказать только как вывод:");
|
||||
expect(candidate.reply_text).not.toContain("Складской срез");
|
||||
});
|
||||
|
||||
@@ -1,4 +1,54 @@
|
||||
[
|
||||
{
|
||||
"generation_id": "gen-ag05122315-f1e27c",
|
||||
"created_at": "2026-05-12T23:15:48+00:00",
|
||||
"mode": "saved_user_sessions",
|
||||
"title": "AGENT | Phase 98 limit honesty and business-language replay",
|
||||
"count": 6,
|
||||
"domain": "address_phase98_limit_honesty_business_language",
|
||||
"questions": [
|
||||
"По ООО Альтернатива Плюс на конец 2020 можно точно понять, какая дебиторка просрочена?",
|
||||
"То есть просрочку доказать нельзя, коротко почему?",
|
||||
"НДС за 2020 по ООО Альтернатива Плюс какой?",
|
||||
"А кто принес больше всего денег за 2020?",
|
||||
"По ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?",
|
||||
"А зависимость от одного поставщика за 2020 можно точно оценить?"
|
||||
],
|
||||
"generated_by": "codex_agent",
|
||||
"saved_case_set_file": "assistant_autogen_saved_user_sessions_20260512231548_gen-ag05122315-f1e27c.json",
|
||||
"context": {
|
||||
"llm_provider": null,
|
||||
"model": null,
|
||||
"assistant_prompt_version": null,
|
||||
"decomposition_prompt_version": null,
|
||||
"prompt_fingerprint": null,
|
||||
"autogen_personality_id": null,
|
||||
"autogen_personality_prompt": null,
|
||||
"source_session_id": null,
|
||||
"saved_session_file": "assistant_saved_session_20260512231548_gen-ag05122315-f1e27c.json",
|
||||
"saved_case_set_kind": "agent_semantic_scenario",
|
||||
"agent_run": true,
|
||||
"agent_focus": "Focused semantic replay from assistant-stage1-v2qsm_R0fF: answers may be bounded, but they must stay business-readable, direct-first, and must not leak MCP/proxy/route/debug wording when explaining row limits, incomplete coverage, debt due-date proof, inventory reserve proof, supplier dependency, VAT, or bank-like counterparties.",
|
||||
"architecture_phase": "turnaround_11",
|
||||
"source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase98_limit_honesty_business_language.json",
|
||||
"scenario_id": "address_truth_harness_phase98_limit_honesty_business_language",
|
||||
"semantic_tags": [
|
||||
"business_language",
|
||||
"customer_revenue_and_payments",
|
||||
"debt_due_date_aging_quality",
|
||||
"debug_leak_guard",
|
||||
"financial_counterparty_flow_hint",
|
||||
"followup_directness",
|
||||
"inventory_reserve_liquidation_quality",
|
||||
"limit_honesty",
|
||||
"vat",
|
||||
"vendor_risk_procurement_quality"
|
||||
],
|
||||
"validation_status": "accepted_live_replay",
|
||||
"validated_run_dir": "artifacts\\domain_runs\\phase98_limit_honesty_business_language_live3",
|
||||
"saved_after_validated_replay": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"generation_id": "gen-ag05122250-4451a8",
|
||||
"created_at": "2026-05-12T22:50:23+00:00",
|
||||
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
{
|
||||
"saved_at": "2026-05-12T23:15:48+00:00",
|
||||
"generation_id": "gen-ag05122315-f1e27c",
|
||||
"mode": "saved_user_sessions",
|
||||
"title": "AGENT | Phase 98 limit honesty and business-language replay",
|
||||
"agent_run": true,
|
||||
"questions": [
|
||||
"По ООО Альтернатива Плюс на конец 2020 можно точно понять, какая дебиторка просрочена?",
|
||||
"То есть просрочку доказать нельзя, коротко почему?",
|
||||
"НДС за 2020 по ООО Альтернатива Плюс какой?",
|
||||
"А кто принес больше всего денег за 2020?",
|
||||
"По ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?",
|
||||
"А зависимость от одного поставщика за 2020 можно точно оценить?"
|
||||
],
|
||||
"metadata": {
|
||||
"assistant_prompt_version": null,
|
||||
"decomposition_prompt_version": null,
|
||||
"prompt_fingerprint": null,
|
||||
"agent_focus": "Focused semantic replay from assistant-stage1-v2qsm_R0fF: answers may be bounded, but they must stay business-readable, direct-first, and must not leak MCP/proxy/route/debug wording when explaining row limits, incomplete coverage, debt due-date proof, inventory reserve proof, supplier dependency, VAT, or bank-like counterparties.",
|
||||
"architecture_phase": "turnaround_11",
|
||||
"source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase98_limit_honesty_business_language.json",
|
||||
"scenario_id": "address_truth_harness_phase98_limit_honesty_business_language",
|
||||
"semantic_tags": [
|
||||
"business_language",
|
||||
"customer_revenue_and_payments",
|
||||
"debt_due_date_aging_quality",
|
||||
"debug_leak_guard",
|
||||
"financial_counterparty_flow_hint",
|
||||
"followup_directness",
|
||||
"inventory_reserve_liquidation_quality",
|
||||
"limit_honesty",
|
||||
"vat",
|
||||
"vendor_risk_procurement_quality"
|
||||
],
|
||||
"validation_status": "accepted_live_replay",
|
||||
"validated_run_dir": "artifacts\\domain_runs\\phase98_limit_honesty_business_language_live3",
|
||||
"saved_after_validated_replay": true,
|
||||
"save_gate": {
|
||||
"schema_version": "agent_semantic_save_gate_v1",
|
||||
"validation_status": "accepted_live_replay",
|
||||
"validated_run_dir": "artifacts\\domain_runs\\phase98_limit_honesty_business_language_live3",
|
||||
"final_status": "accepted",
|
||||
"review_overall_status": "pass",
|
||||
"business_overall_status": "pass",
|
||||
"steps_total": 6,
|
||||
"steps_passed": 6,
|
||||
"steps_failed": 0,
|
||||
"steps_with_business_failures": 0,
|
||||
"steps_with_business_warnings": 0,
|
||||
"acceptance_gate_passed": true,
|
||||
"saved_after_validated_replay": true
|
||||
}
|
||||
},
|
||||
"source_session_id": null,
|
||||
"session": {
|
||||
"session_id": null,
|
||||
"mode": "agent_semantic_run",
|
||||
"items": [
|
||||
{
|
||||
"message_id": "agent-user-001",
|
||||
"role": "user",
|
||||
"text": "По ООО Альтернатива Плюс на конец 2020 можно точно понять, какая дебиторка просрочена?",
|
||||
"created_at": "2026-05-12T23:15:48+00:00",
|
||||
"reply_type": null,
|
||||
"trace_id": null,
|
||||
"debug": null
|
||||
},
|
||||
{
|
||||
"message_id": "agent-user-002",
|
||||
"role": "user",
|
||||
"text": "То есть просрочку доказать нельзя, коротко почему?",
|
||||
"created_at": "2026-05-12T23:15:48+00:00",
|
||||
"reply_type": null,
|
||||
"trace_id": null,
|
||||
"debug": null
|
||||
},
|
||||
{
|
||||
"message_id": "agent-user-003",
|
||||
"role": "user",
|
||||
"text": "НДС за 2020 по ООО Альтернатива Плюс какой?",
|
||||
"created_at": "2026-05-12T23:15:48+00:00",
|
||||
"reply_type": null,
|
||||
"trace_id": null,
|
||||
"debug": null
|
||||
},
|
||||
{
|
||||
"message_id": "agent-user-004",
|
||||
"role": "user",
|
||||
"text": "А кто принес больше всего денег за 2020?",
|
||||
"created_at": "2026-05-12T23:15:48+00:00",
|
||||
"reply_type": null,
|
||||
"trace_id": null,
|
||||
"debug": null
|
||||
},
|
||||
{
|
||||
"message_id": "agent-user-005",
|
||||
"role": "user",
|
||||
"text": "По ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?",
|
||||
"created_at": "2026-05-12T23:15:48+00:00",
|
||||
"reply_type": null,
|
||||
"trace_id": null,
|
||||
"debug": null
|
||||
},
|
||||
{
|
||||
"message_id": "agent-user-006",
|
||||
"role": "user",
|
||||
"text": "А зависимость от одного поставщика за 2020 можно точно оценить?",
|
||||
"created_at": "2026-05-12T23:15:48+00:00",
|
||||
"reply_type": null,
|
||||
"trace_id": null,
|
||||
"debug": null
|
||||
}
|
||||
],
|
||||
"agent_run": true,
|
||||
"metadata": {
|
||||
"assistant_prompt_version": null,
|
||||
"decomposition_prompt_version": null,
|
||||
"prompt_fingerprint": null,
|
||||
"agent_focus": "Focused semantic replay from assistant-stage1-v2qsm_R0fF: answers may be bounded, but they must stay business-readable, direct-first, and must not leak MCP/proxy/route/debug wording when explaining row limits, incomplete coverage, debt due-date proof, inventory reserve proof, supplier dependency, VAT, or bank-like counterparties.",
|
||||
"architecture_phase": "turnaround_11",
|
||||
"source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase98_limit_honesty_business_language.json",
|
||||
"scenario_id": "address_truth_harness_phase98_limit_honesty_business_language",
|
||||
"semantic_tags": [
|
||||
"business_language",
|
||||
"customer_revenue_and_payments",
|
||||
"debt_due_date_aging_quality",
|
||||
"debug_leak_guard",
|
||||
"financial_counterparty_flow_hint",
|
||||
"followup_directness",
|
||||
"inventory_reserve_liquidation_quality",
|
||||
"limit_honesty",
|
||||
"vat",
|
||||
"vendor_risk_procurement_quality"
|
||||
],
|
||||
"validation_status": "accepted_live_replay",
|
||||
"validated_run_dir": "artifacts\\domain_runs\\phase98_limit_honesty_business_language_live3",
|
||||
"saved_after_validated_replay": true,
|
||||
"save_gate": {
|
||||
"schema_version": "agent_semantic_save_gate_v1",
|
||||
"validation_status": "accepted_live_replay",
|
||||
"validated_run_dir": "artifacts\\domain_runs\\phase98_limit_honesty_business_language_live3",
|
||||
"final_status": "accepted",
|
||||
"review_overall_status": "pass",
|
||||
"business_overall_status": "pass",
|
||||
"steps_total": 6,
|
||||
"steps_passed": 6,
|
||||
"steps_failed": 0,
|
||||
"steps_with_business_failures": 0,
|
||||
"steps_with_business_warnings": 0,
|
||||
"acceptance_gate_passed": true,
|
||||
"saved_after_validated_replay": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"suite_id": "assistant_saved_session_gen-ag05122315-f1e27c",
|
||||
"suite_version": "0.1.0",
|
||||
"schema_version": "assistant_saved_session_suite_v0_1",
|
||||
"generated_at": "2026-05-12T23:15:48+00:00",
|
||||
"generation_id": "gen-ag05122315-f1e27c",
|
||||
"mode": "saved_user_sessions",
|
||||
"title": "AGENT | Phase 98 limit honesty and business-language replay",
|
||||
"domain": "address_phase98_limit_honesty_business_language",
|
||||
"scenario_count": 1,
|
||||
"case_ids": [
|
||||
"SAVED-001"
|
||||
],
|
||||
"cases": [
|
||||
{
|
||||
"case_id": "SAVED-001",
|
||||
"scenario_tag": "agent_saved_user_sessions",
|
||||
"title": "AGENT | Phase 98 limit honesty and business-language replay",
|
||||
"question_type": "followup",
|
||||
"broadness_level": "medium",
|
||||
"turns": [
|
||||
{
|
||||
"user_message": "По ООО Альтернатива Плюс на конец 2020 можно точно понять, какая дебиторка просрочена?"
|
||||
},
|
||||
{
|
||||
"user_message": "То есть просрочку доказать нельзя, коротко почему?"
|
||||
},
|
||||
{
|
||||
"user_message": "НДС за 2020 по ООО Альтернатива Плюс какой?"
|
||||
},
|
||||
{
|
||||
"user_message": "А кто принес больше всего денег за 2020?"
|
||||
},
|
||||
{
|
||||
"user_message": "По ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?"
|
||||
},
|
||||
{
|
||||
"user_message": "А зависимость от одного поставщика за 2020 можно точно оценить?"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user