docs(platform): add policy configs, runbooks, ops scripts and platform documentation
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
This commit is contained in:
123
docs/HUMANIZED_STEPAN_v2.8_CHANGELOG.md
Normal file
123
docs/HUMANIZED_STEPAN_v2.8_CHANGELOG.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# Humanized Stepan — CHANGELOG v2.8
|
||||
|
||||
**Version:** v2.8
|
||||
**Date:** 2026-02-25
|
||||
**Базується на:** v2.7.2 (PII-safe telemetry, recent_topics horizon, invariant tests)
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
- **Multi-user farm model**: `FarmProfile` тепер зберігається під ключем `farm_profile:agromatrix:chat:{chat_id}` — shared для всіх операторів в одному чаті.
|
||||
- **UserProfile** залишається per-user (`user_profile:agromatrix:{user_id}`) — стиль, recent_topics, interaction_summary окремі для кожного.
|
||||
- **Lazy migration**: перший запит з `user_id` автоматично мігрує старий legacy-ключ `farm_profile:agromatrix:{user_id}` у новий chat-ключ (write-through, без ручного втручання).
|
||||
- **Conflict policy**: якщо chat-profile вже існує і відрізняється від legacy — не перезаписуємо; лише tlog `farm_profile_conflict`.
|
||||
- **FarmProfile v5**: додані нові поля (`farm_name`, `field_ids`, `crop_ids`, `active_integrations`, `iot_sensors`, `alert_thresholds`, `seasonal_context`).
|
||||
- **Backward-compat**: `load_farm_profile(chat_id)` без `user_id` — не крашить, повертає default.
|
||||
|
||||
---
|
||||
|
||||
## Key features (деталі)
|
||||
|
||||
### Нові fact-ключі
|
||||
|
||||
| Тип | Ключ | Scope |
|
||||
|---|---|---|
|
||||
| UserProfile | `user_profile:agromatrix:{user_id}` | per-user (без змін) |
|
||||
| FarmProfile (v2.8) | `farm_profile:agromatrix:chat:{chat_id}` | per-chat (новий) |
|
||||
| FarmProfile (legacy) | `farm_profile:agromatrix:{user_id}` | deprecated, мігрується lazy |
|
||||
|
||||
### Lazy Migration Flow
|
||||
|
||||
```
|
||||
load_farm_profile(chat_id, user_id)
|
||||
│
|
||||
├── cache hit (chat-key)? → return
|
||||
├── memory-service chat-key? → return + cache
|
||||
├── memory-service legacy-key (user_id)?
|
||||
│ ├── YES → copy to chat-key (write-through) + return migrated profile
|
||||
│ │ tlog: farm_profile_migrated
|
||||
│ └── NO → default farm_profile(chat_id)
|
||||
```
|
||||
|
||||
### Conflict Policy
|
||||
|
||||
При явній міграції через `migrate_farm_profile_legacy_to_chat()`:
|
||||
- Якщо chat-profile існує і **суттєво відрізняється** (crops/field_ids/region/season_state) → NOT overwritten
|
||||
- `tlog: farm_profile_conflict reason=legacy_diff`
|
||||
- Повертається існуючий chat-profile
|
||||
|
||||
Критерій суттєвої відмінності (`_farm_profiles_differ`): порівнює `crops`, `field_ids`, `fields`, `region`, `season_state`, `active_integrations`.
|
||||
|
||||
### FarmProfile v5 — нові поля
|
||||
|
||||
```json
|
||||
{
|
||||
"_version": 5,
|
||||
"chat_id": "...",
|
||||
"farm_name": null,
|
||||
"field_ids": [],
|
||||
"crop_ids": [],
|
||||
"active_integrations": [],
|
||||
"iot_sensors": [],
|
||||
"alert_thresholds": {},
|
||||
"seasonal_context": {},
|
||||
"region": null,
|
||||
"crops": [],
|
||||
"fields": [],
|
||||
"season_state": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
| Аспект | Деталі |
|
||||
|---|---|
|
||||
| `load_farm_profile(chat_id)` | Без `user_id` — не крашить (legacy path пропускається) |
|
||||
| `load_farm_profile(chat_id, user_id)` | Новий API; `user_id` потрібен тільки для lazy migration |
|
||||
| `save_farm_profile(chat_id, profile)` | API без змін (тепер під chat-key автоматично) |
|
||||
| Legacy ключ | Не видаляється, існує в memory-service до явного очищення |
|
||||
| `_version` FarmProfile | 1 → 5; non-breaking (нові поля, старі залишаються) |
|
||||
|
||||
---
|
||||
|
||||
## Non-goals / not included
|
||||
|
||||
- Немає автоматичного merge при конфлікті.
|
||||
- Немає видалення legacy ключів (тільки read-migrate).
|
||||
- Немає зміни light/deep логіки, тональності, банків фраз.
|
||||
- Немає нових ендпоінтів або інфра-змін.
|
||||
|
||||
---
|
||||
|
||||
## Tests
|
||||
|
||||
**Результат:** 161/161 зелених (без регресій з v2.7.2)
|
||||
|
||||
| Файл | Нових тестів | Опис |
|
||||
|---|---|---|
|
||||
| `tests/test_stepan_v28_farm.py` | 24 | Multi-user farm: ключі, міграція, конфлікт, acceptance |
|
||||
|
||||
```bash
|
||||
# Тільки v2.8 farm тести
|
||||
python3 -m pytest tests/test_stepan_v28_farm.py -v
|
||||
|
||||
# Всі Stepan тести
|
||||
python3 -m pytest 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 \
|
||||
crews/agromatrix_crew/run.py
|
||||
docker compose -f docker-compose.node1.yml up -d --build dagi-gateway-node1
|
||||
```
|
||||
|
||||
Після rollback до v2.7.x: farm_profile знову читатиметься зі старого legacy-ключа (якщо є в cache/memory-service). Новий chat-ключ залишиться в memory-service, але не буде використовуватись.
|
||||
Reference in New Issue
Block a user