From 5670ecd84b56f0010054340681699eaf69993a44 Mon Sep 17 00:00:00 2001 From: igor04091968 Date: Fri, 22 May 2026 16:27:19 +0300 Subject: [PATCH] feat(1c): add executive regulation to manager brief --- clickhouse-1c/ai/company_intelligence_api.py | 48 +++++++++++++++++++ .../ai/test_company_intelligence_api.py | 34 +++++++++++++ 2 files changed, 82 insertions(+) diff --git a/clickhouse-1c/ai/company_intelligence_api.py b/clickhouse-1c/ai/company_intelligence_api.py index ff30e65..dea59d4 100644 --- a/clickhouse-1c/ai/company_intelligence_api.py +++ b/clickhouse-1c/ai/company_intelligence_api.py @@ -466,6 +466,33 @@ def render_manager_brief_html(payload: dict[str, Any]) -> str: summary_items = "\n".join(f"
  • {html.escape(str(item))}
  • " for item in brief.get("summary", [])) action_items = "\n".join(f"
  • {html.escape(str(item))}
  • " for item in actions) caveat_items = "\n".join(f"
  • {html.escape(str(item))}
  • " for item in caveats) + morning_regulation_items = "\n".join( + f"
  • {html.escape(str(item))}
  • " + for item in [ + "Открыть brief, changes и weekly digest. Сначала понять: хвост кейсов растёт или сокращается.", + "Выбрать не больше 5 компаний первой очереди. Критерии: рост open cases, active locks, manual-match, повторный critical без улучшения.", + "По каждой компании требовать только 4 вещи: причина, владелец, срок, измеримый результат к вечеру.", + "Не принимать формулировки «смотрим», «разбираемся», «в работе». Принимать только конкретный план закрытия.", + ] + ) + evening_regulation_items = "\n".join( + f"
  • {html.escape(str(item))}
  • " + for item in [ + "По каждой компании дня спросить только факт: сколько кейсов было утром и сколько стало вечером.", + "Отдельно проверить, снялись ли блокировки и исчез ли прирост новых кейсов.", + "По каждой компании зафиксировать один статус: снято, частично снято, не снято.", + "Если результата нет, менять владельца или усиливать контроль; не переносить хвост молча.", + ] + ) + hard_rules_items = "\n".join( + f"
  • {html.escape(str(item))}
  • " + for item in [ + "Не пытаться разбирать все 41 компании сразу.", + "Не путать operational critical с финансовым крахом портфеля.", + "Не делать жёстких оргвыводов по manual-match компаниям без проверки соответствия реестру.", + "Главный KPI на сейчас: закрытые кейсы и снятые блокировки, а не количество проведённых разборов.", + ] + ) return f""" @@ -787,6 +814,27 @@ def render_manager_brief_html(payload: dict[str, Any]) -> str: +
    +

    Регламент руководителя: утро

    + +
    + +
    +

    Регламент руководителя: вечер

    + +
    + +
    +

    Жёсткие правила управления

    + +
    +

    Свежесть источников

    diff --git a/clickhouse-1c/ai/test_company_intelligence_api.py b/clickhouse-1c/ai/test_company_intelligence_api.py index edac27e..de19126 100644 --- a/clickhouse-1c/ai/test_company_intelligence_api.py +++ b/clickhouse-1c/ai/test_company_intelligence_api.py @@ -56,6 +56,40 @@ import company_intelligence_api as api class CompanyIntelligenceApiTests(unittest.TestCase): + def test_render_manager_brief_includes_executive_regulation(self) -> None: + payload = { + "generated_at": "2026-05-22T12:00:00+00:00", + "render_mode": "codex", + "brief": { + "headline": "Портфель 1С под давлением.", + "summary": ["Кейсы растут.", "Нужен triage.", "Manual-match требует осторожности."], + "top_risks": [], + "top_forecasts": [], + "actions": ["Разобрать 5 компаний первой очереди."], + "caveats": ["Operational severity не равна финансам."], + }, + "context": { + "portfolio_summary": { + "companies_total": 41, + "critical_total": 41, + "open_cases_total": 2744, + "activity_forecast_30d_total": 1723233.3, + }, + "freshness": [ + { + "source": "documents_ts", + "latest_ts": "2026-05-22T09:00:02+00:00", + "lag_hours": 3.84, + "stale": False, + } + ], + }, + } + html_page = api.render_manager_brief_html(payload) + self.assertIn("Регламент руководителя: утро", html_page) + self.assertIn("Регламент руководителя: вечер", html_page) + self.assertIn("Жёсткие правила управления", html_page) + def test_build_company_priority_context(self) -> None: latest_payload = { "generated_at": "2026-05-22T12:00:00+00:00",