# Humanized Stepan v3 — Changelog

**Version:** v3  
**Date:** 2026-02-24  
**Base:** v2.9 (Memory Consolidation)  
**Type:** Additive — нова функціональність без змін v2.9-ядра

---

## Summary

v3 додає три ізольованих шари поверх v2.9, не торкаючись:
- light_reply банків фраз
- memory consolidation логіки
- telemetry/PII-safe механіки (AGX_STEPAN_METRIC, anonymize_id)
- FarmProfile v2.8 міграції
- reflection engine
- depth classifier основної логіки (тільки новий опціональний param)

---

## Що додано

### 1. Session Context Layer (`session_context.py`)

- In-memory кеш `dict[chat_id → SessionContext]`, TTL = 900s (15 хв).
- Структура `SessionContext`:
  ```json
  {
    "last_messages":  ["...", "...", "..."],
    "last_depth":     "light" | "deep" | null,
    "last_agents":    ["ops", "iot", ...],
    "last_question":  "Уточни поле?" | null,
    "updated_at":     1234567890.0
  }
  ```
- API: `load_session(chat_id)` / `update_session(chat_id, ...)` / `clear_session(chat_id)`.
- `load_session` при протуханні повертає default без виключень (fail-safe).
- Telemetry: `session_loaded`, `session_expired`, `session_updated` — PII-safe `chat_id=h:...`.

### 2. Intent Stability Guard (розширення `depth_classifier.py`)

- Новий опціональний параметр `session: dict | None` у `classify_depth(...)`.
- Guard на початку класифікації: якщо `session.last_depth == "light"` і поточне повідомлення ≤ 6 слів без action verbs і без urgent → одразу повертає `"light"`.
- Action verbs або urgent слово перебивають guard → звичайна класифікація.
- Без `session` (або `session=None`) поведінка ідентична v2.9.
- Telemetry: `stability_guard_triggered`.

### 3. Soft Proactivity Layer (`proactivity.py`)

- `maybe_add_proactivity(response, user_profile, depth, reflection) -> (str, bool)`.
- Додає рівно 1 речення ≤ 120 символів без `!` в кінець відповіді.
- Умови спрацювання (всі одночасно):
  1. `depth == "deep"`
  2. `reflection.confidence >= 0.7` або `reflection is None`
  3. `interaction_count % 10 == 0`
  4. Один intent у `known_intents` зустрівся ≥ 3 рази
  5. Не `(style == "concise"/"brief" AND "?" в response)`
- Чотири банки фраз: generic, iot, plan, sustainability — seeded вибір.
- Telemetry: `proactivity_added`, `proactivity_skipped`.

---

## Зміни в існуючих файлах

| Файл | Зміна |
|---|---|
| `depth_classifier.py` | Новий `session=None` param + stability guard на початку `classify_depth` |
| `run.py` | 3 гачки: `load_session` → `classify_depth(session=)` → `update_session` + `maybe_add_proactivity` |

---

## Backward Compatibility

- `classify_depth(session=None)` — поведінка ідентична v2.9.
- Усі v2.9 тести (203 шт.) без змін, зелені.
- Нові тести: 29 тестів у `test_stepan_v3_session_proactivity_stability.py`.
- Загальний suite: 232/232.

---

## Telemetry Events (нові у v3)

| Event | Файл | PII-safe ключі |
|---|---|---|
| `session_loaded` | `session_context.py` | `chat_id=h:...` |
| `session_expired` | `session_context.py` | `chat_id=h:...` |
| `session_updated` | `session_context.py` | `chat_id=h:...` |
| `stability_guard_triggered` | `depth_classifier.py` | — |
| `proactivity_added` | `proactivity.py` | `user_id=h:...` |
| `proactivity_skipped` | `proactivity.py` | `user_id=h:...` |

---

## Known Limitations

1. **Session скидається при рестарті контейнера** — очікувано. TTL 15 хв — це сесія в рамках активного діалогу, не довготривала пам'ять (для неї є UserProfile в memory-service).
2. **Stability guard працює тільки з `last_depth`** — не враховує зміст попереднього повідомлення. Якщо потрібна складніша логіка (наприклад, "попереднє було deep з темою X") — треба розширити `SessionContext`.
3. **Proactivity банки фраз — rule-based, не персоналізовані** — фрази обираються за top intent, а не за конкретним контентом відповіді. Для глибшої персоналізації потрібно або LLM, або значно більші банки.
4. **`stability_guard_triggered` логить `chat_id=n/a`** — тимчасово, оскільки `depth_classifier` не приймає `chat_id` напряму. Можна виправити у v3.1, передавши `chat_id` через `session`.

---

## Команди запуску тестів

```bash
# Тільки v3
python3 -m pytest tests/test_stepan_v3_session_proactivity_stability.py -v

# Повний Stepan suite (v2.5 – v3)
python3 -m pytest \
  tests/test_stepan_light_reply.py \
  tests/test_stepan_memory_followup.py \
  tests/test_stepan_acceptance.py \
  tests/test_stepan_invariants.py \
  tests/test_stepan_telemetry.py \
  tests/test_stepan_v28_farm.py \
  tests/test_stepan_v29_consolidation.py \
  tests/test_stepan_v3_session_proactivity_stability.py \
  -v
```

---

## Rollback

```bash
cd /opt/microdao-daarion

# Мінімальний rollback (прибрати гачки, залишити нові файли неактивними)
git checkout HEAD~1 -- crews/agromatrix_crew/run.py
git checkout HEAD~1 -- crews/agromatrix_crew/depth_classifier.py

# Повний rollback (включно з новими модулями)
git checkout HEAD~1 -- \
  crews/agromatrix_crew/run.py \
  crews/agromatrix_crew/depth_classifier.py \
  crews/agromatrix_crew/session_context.py \
  crews/agromatrix_crew/proactivity.py

docker compose -f docker-compose.node1.yml up -d --build dagi-gateway-node1
```
