Config policies (16 files): alert_routing, architecture_pressure, backlog, cost_weights, data_governance, incident_escalation, incident_intelligence, network_allowlist, nodes_registry, observability_sources, rbac_tools_matrix, release_gate, risk_attribution, risk_policy, slo_policy, tool_limits, tools_rollout Ops (22 files): Caddyfile, calendar compose, grafana voice dashboard, deployments/incidents logs, runbooks for alerts/audit/backlog/incidents/sofiia/voice, cron jobs, scripts (alert_triage, audit_cleanup, migrate_*, governance, schedule), task_registry, voice alerts/ha/latency/policy Docs (30+ files): HUMANIZED_STEPAN v2.7-v3 changelogs and runbooks, NODA1/NODA2 status and setup, audit index and traces, backlog, incident, supervisor, tools, voice, opencode, release, risk, aistalk, spacebot Made-with: Cursor
7.8 KiB
Humanized Stepan — CHANGELOG v2.7
Version: v2.7
Date: 2026-02-25
Базується на: v2.6 (Jaccard guard, tone_constraints, 3-рівневі привітання, seeded RNG)
Summary
- Додано memory horizon:
recent_topics(до 5 записів) замість єдиногоlast_topic. - Додано human topic labels (
last_topic_label) — Степан оперує "план на завтра поле 12", а не "plan_day". - Додано
summarize_topic_label()— rule-based витяг 6–8 слів з тексту без дієслів-тригерів і стоп-слів. - Light follow-up (≤6 слів + last_topic) не додає шум до
recent_topics(depth="light"→pushне відбувається). - Contextual greeting (
interaction_count ≥ 8) тепер: з ймовірністю 20% (seeded rng) підхоплюєrecent_topics[-2]— Степан "пам'ятає" більше однієї теми без подвійного згадування. - ZZR safety disclaimer: якщо погодний тригер + обприскування/гербіцид/ЗЗР — автоматично додається
"Дозування та вікна застосування — за етикеткою препарату та регламентом.". - Додано
tests/test_stepan_invariants.py— 25 тестів-інваріантів проти "повзучої ботячості".
Key features (деталі)
Memory horizon — recent_topics
"recent_topics": [
{"label": "план на завтра поле 12", "intent": "plan_day", "ts": "2026-02-25T..."},
{"label": "датчики вологості поле 7", "intent": "iot_sensors", "ts": "2026-02-25T..."}
]
- Максимум 5 записів; старіші витісняються.
last_topicіlast_topic_label— backward-compat aliases наrecent_topics[-1].- Dedup: якщо той самий
intent+labelпідряд — не дублюється.
summarize_topic_label
| Вхід | Вихід |
|---|---|
"зроби план на завтра по полю 12" |
"План на завтра по полю 12" |
"перевір датчики вологості поле 7" |
"Датчики вологості поле 7" |
"сплануй тижневий збір по полях" |
"Тижневий збір по полях" |
Правила: прибирається leading action verb (зроби/перевір/порахуй/…), стоп-слова, обрізка до 8 слів. Числа, поля, культури, дати зберігаються.
ZZR disclaimer
Regex _ZZR_RE спрацьовує на: обробк|обприскування|гербіцид|фунгіцид|ЗЗР|пестицид|інсектицид|протруювач.
Застереження додається лише коли є і погодний тригер і ZZR-тригер в одному повідомленні.
Invariant tests (anti-regression)
| Інваріант | Обмеження |
|---|---|
| INV-1: Greeting | ≤ 80 символів |
| INV-2: Thanks/Ack | ≤ 40 символів |
| INV-3: Заборонені фрази | "чим можу допомогти", "оберіть", "я як агент", "я бот" |
| INV-4: Технічні слова | container, uvicorn, trace_id, STEPAN_IMPORTS_OK |
| INV-5: ZZR disclaimer | при ZZR+погода → "за етикеткою" або "за регламентом" |
| INV-6: Horizon | len(recent_topics) ≤ 5 після 7+ push |
| INV-7: Міграція | lazy, idempotent, backward-compat |
Backward compatibility
| Аспект | Деталі |
|---|---|
_version |
3 → 4 (нові поля recent_topics, last_topic_label) |
| Міграція | Lazy при load_user_profile() — виконується автоматично при першому зверненні |
last_topic |
Залишається як alias, завжди синхронізований з recent_topics[-1].intent |
last_topic_label |
Новий alias на recent_topics[-1].label; якщо нема — встановлюється під час міграції |
tone_constraints |
Вже в v2.6; міграція додає якщо відсутній |
update_profile_if_needed |
Новий параметр depth="deep" (default) — backward-compat, старі виклики не ламаються |
recent_topics відсутній |
Якщо профіль v3 без recent_topics — migrate_profile_topics() створює 1 елемент з last_topic |
Міграція migrate_profile_topics() — idempotent: повторний виклик не змінює вже мігрований профіль.
Non-goals / not included
- Немає LLM у light mode або reflection.
- Немає змін в інфраструктурі (Dockerfile, compose, env).
- Немає змін у Gateway/http_api.py.
- Немає нових API ендпоінтів.
- Немає змін у поведінці deep mode orchestration.
- Немає змін у системному промпті (тільки хедер-версія).
Tests
Результат: 101/101 зелених (без регресій з v2.6)
| Файл | Тестів | Опис |
|---|---|---|
tests/test_stepan_invariants.py |
25 | Нові інваріанти anti-regression |
tests/test_stepan_acceptance.py |
28 | Acceptance + v2.7 сесійні сценарії |
tests/test_stepan_light_reply.py |
~26 | Light reply юніт-тести |
tests/test_stepan_memory_followup.py |
~22 | Memory + follow-up класифікація |
# Тільки інваріанти
python3 -m pytest tests/test_stepan_invariants.py -v
# Acceptance
python3 -m pytest tests/test_stepan_acceptance.py -v
# Всі Stepan тести
python3 -m pytest tests/test_stepan_invariants.py tests/test_stepan_acceptance.py \
tests/test_stepan_light_reply.py tests/test_stepan_memory_followup.py -v
Known limitations
Timezone і daily seed
date.today() використовує локаль контейнера. Контейнер має бути в Europe/Kyiv (TZ=Europe/Kyiv), інакше "новий день" Степана настане о 22:00 або 23:00 за Київським часом. Перевірка:
docker exec dagi-gateway-node1 date
Memory-service downtime
При недоступності — деградація до локального in-memory кешу (TTL 30 хв). Кеш не переживає рестарт контейнера. Профілі не зберігаються між сесіями якщо memory-service down > 30 хв.
ZZR regex — можливий overreach
Слово "обробка" без агрохімічного контексту (напр. "обробка ґрунту") може спрацювати. Якщо в проді виявиться шум — звузити regex: вимагати ще одне слово з [препарат|норма|л/га|кг/га|концентрат].
Rollback
# Відкатити зміни у конкретних файлах
git checkout HEAD~1 -- crews/agromatrix_crew/memory_manager.py
git checkout HEAD~1 -- crews/agromatrix_crew/light_reply.py
git checkout HEAD~1 -- crews/agromatrix_crew/run.py
# Rebuild gateway (без секретів)
cd /opt/microdao-daarion
docker compose -f docker-compose.node1.yml up -d --build dagi-gateway-node1
# Перевірка
docker logs dagi-gateway-node1 --since 5m 2>&1 | grep -E "Stepan mode|STEPAN_IMPORTS_OK|error|Error" | tail -30