# Humanized Stepan — CHANGELOG v2.9

**Version:** v2.9  
**Date:** 2026-02-25  
**Базується на:** v2.8 (Multi-user FarmProfile, lazy migration, PII-safe telemetry)

---

## Summary

Memory Consolidation — детермінована, ідемпотентна очистка UserProfile і FarmProfile:

- Профілі не "розростаються" нескінченно з часом.
- Запускається автоматично кожні 25 взаємодій (або раніше при hard trigger).
- Без LLM. Без зміни Light/Deep логіки і текстів відповідей.
- Fail-safe: будь-яка помилка → профіль залишається незміненим, tlog warning.
- PII-safe: всі telemetry логи через `tlog` з анонімізацією `user_id`/`chat_id`.

---

## Що обрізається і чому це safe

| Поле | Ліміт | Метод |
|---|---|---|
| `context_notes` | ≤ 20 | dedup + trim (останні N) |
| `known_intents` | ≤ 30 | dedup + trim (останні N) |
| `preferences` | whitelist keys | видалення невідомих ключів |
| `tone_constraints` | bool-ключі | нормалізація типів + видалення невідомих |
| `interaction_summary` | ≤ 220 символів | cap без обрізки посередині слова |
| `recent_topics` | ≤ 5 | dedup (вже є horizon, для безпеки) |
| `field_ids` | ≤ 200 | dedup + trim |
| `crop_ids` | ≤ 100 | dedup + trim |
| `active_integrations` | ≤ 20 | dedup + trim |

**Whitelist `preferences` keys:** `units`, `report_format`, `tone_constraints`, `language`

Consolidation зберігає останні N записів (не перші) — найновіші теми/поля мають пріоритет.

---

## Тригери

| Тип | Умова |
|---|---|
| Periodic | `interaction_count % 25 == 0` (25, 50, 75…) |
| Hard trigger (user) | `len(context_notes) > 30` або `len(known_intents) > 45` |
| Hard trigger (farm) | `len(field_ids) > 300`, `len(crop_ids) > 150`, або `len(active_integrations) > 30` |

---

## Telemetry events

```
AGX_STEPAN_METRIC memory_consolidated entity=user_profile user_id=h:... changed=true reason=periodic
AGX_STEPAN_METRIC memory_consolidated entity=farm_profile chat_id=h:... changed=false reason=hard_trigger
AGX_STEPAN_METRIC memory_consolidation_error entity=user_profile user_id=h:... error=...
```

Grep у проді:
```bash
docker logs dagi-gateway-node1 --since 60m 2>&1 | grep "AGX_STEPAN_METRIC memory_consolidated"
```

---

## Що НЕ змінюється

- `classify_depth` / `depth_classifier` — без змін
- `light_reply` банки фраз і поведінка — без змін
- `reflection_engine` — без змін
- Тексти відповідей агента — без змін
- `recent_topics` semantics (horizon 5) — без змін
- FarmProfile `chat_id` key (v2.8) — без змін

---

## Backward Compatibility

- Поля яких немає в профілі (наприклад `context_notes`) — ігноруються (не створюються)
- `preferences` без whitelist-ключів — тільки видаляються зайві, наявні зберігаються
- `tone_constraints` з невалідними типами (int замість bool) — нормалізуються до bool

---

## Tests

**Результат:** 203/203 зелених

| Файл | Нових тестів | Опис |
|---|---|---|
| `tests/test_stepan_v29_consolidation.py` | 42 | Limits, dedup, triggers, idempotency, fail-safe, telemetry |

```bash
# Тільки v2.9 consolidation тести
python3 -m pytest tests/test_stepan_v29_consolidation.py -v

# Всі Stepan тести (203)
python3 -m pytest tests/test_stepan_v29_consolidation.py tests/test_stepan_v28_farm.py \
  tests/test_stepan_telemetry.py tests/test_stepan_invariants.py \
  tests/test_stepan_acceptance.py tests/test_stepan_light_reply.py \
  tests/test_stepan_memory_followup.py -v
```

---

## Rollback

```bash
git checkout HEAD~1 -- crews/agromatrix_crew/memory_manager.py
docker compose -f docker-compose.node1.yml up -d --build dagi-gateway-node1
```

Після rollback: consolidation не запускається, профілі накопичуються як раніше. Існуючі профілі не ламаються.
