feat(1c): add executive regulation to manager brief

This commit is contained in:
igor04091968
2026-05-22 16:27:19 +03:00
parent 11c0f06e0a
commit 5670ecd84b
2 changed files with 82 additions and 0 deletions
@@ -466,6 +466,33 @@ def render_manager_brief_html(payload: dict[str, Any]) -> str:
summary_items = "\n".join(f"<li>{html.escape(str(item))}</li>" for item in brief.get("summary", []))
action_items = "\n".join(f"<li>{html.escape(str(item))}</li>" for item in actions)
caveat_items = "\n".join(f"<li>{html.escape(str(item))}</li>" for item in caveats)
morning_regulation_items = "\n".join(
f"<li>{html.escape(str(item))}</li>"
for item in [
"Открыть brief, changes и weekly digest. Сначала понять: хвост кейсов растёт или сокращается.",
"Выбрать не больше 5 компаний первой очереди. Критерии: рост open cases, active locks, manual-match, повторный critical без улучшения.",
"По каждой компании требовать только 4 вещи: причина, владелец, срок, измеримый результат к вечеру.",
"Не принимать формулировки «смотрим», «разбираемся», «в работе». Принимать только конкретный план закрытия.",
]
)
evening_regulation_items = "\n".join(
f"<li>{html.escape(str(item))}</li>"
for item in [
"По каждой компании дня спросить только факт: сколько кейсов было утром и сколько стало вечером.",
"Отдельно проверить, снялись ли блокировки и исчез ли прирост новых кейсов.",
"По каждой компании зафиксировать один статус: снято, частично снято, не снято.",
"Если результата нет, менять владельца или усиливать контроль; не переносить хвост молча.",
]
)
hard_rules_items = "\n".join(
f"<li>{html.escape(str(item))}</li>"
for item in [
"Не пытаться разбирать все 41 компании сразу.",
"Не путать operational critical с финансовым крахом портфеля.",
"Не делать жёстких оргвыводов по manual-match компаниям без проверки соответствия реестру.",
"Главный KPI на сейчас: закрытые кейсы и снятые блокировки, а не количество проведённых разборов.",
]
)
return f"""<!doctype html>
<html lang="ru">
@@ -787,6 +814,27 @@ def render_manager_brief_html(payload: dict[str, Any]) -> str:
</ul>
</article>
<article class="panel span-6">
<h2>Регламент руководителя: утро</h2>
<ul class="action-list">
{morning_regulation_items}
</ul>
</article>
<article class="panel span-6">
<h2>Регламент руководителя: вечер</h2>
<ul class="action-list">
{evening_regulation_items}
</ul>
</article>
<article class="panel span-12">
<h2>Жёсткие правила управления</h2>
<ul class="action-list">
{hard_rules_items}
</ul>
</article>
<article class="panel span-12">
<h2>Свежесть источников</h2>
<table>
@@ -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",