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
9.9 KiB
Voice Incidents Runbook
Version: 1.0 | Node: NODA2 | SLO doc: config/slo_policy.yml
Перший крок для БУДЬ-ЯКОГО алерту (30 секунд)
# 1. Репро пакет — весь контекст в одному запиті
curl -s http://localhost:8002/api/voice/degradation_status | python3 -m json.tool
# 2. Canary живий синтез
python3 ops/scripts/voice_canary.py --mode preflight --memory-url http://localhost:8000
# 3. Логи останніх 2 хвилин
docker logs sofiia-console --since 2m 2>&1 | grep -E "ERROR|WARNING|TTS|LLM|502|429|503"
docker logs dagi-memory-service-node2 --since 2m 2>&1 | grep -E "ERROR|403|edge.tts|synthesiz"
Поля repro у відповіді дають: last_5_tts_errors, last_5_llm_errors, node_id, last_model, concurrent_tts_slots_free.
Alert 1: VoiceTTFA_P95_Breach_Fast
Умова: TTFA p95 > 5000ms за 10 хвилин | Severity: warning
Що значить: LLM відповідає повільно — черга Ollama переповнена, модель cold-start, або qwen3.5 вибрана замість gemma3.
Крок 1 — Діагностика (2 хв)
# Ollama поточний стан
curl -s http://localhost:11434/api/ps | python3 -m json.tool
# Метрики LLM по моделях (якщо є Prometheus)
# promql: histogram_quantile(0.95, rate(voice_llm_ms_bucket[5m])) by (model)
# Деградаційний стан
curl -s http://localhost:8002/api/voice/degradation_status | python3 -c \
"import sys,json; d=json.load(sys.stdin); print(d['repro']['last_model'], d['p95'])"
Крок 2 — Mitigation
# A. Примусово переключити на gemma3 (якщо qwen3.5 завантажений)
# В UI: зняти галочку "Якісно" → fast profile автоматично обере gemma3
# B. Якщо Ollama завантажений запитами — зупинити важкі моделі
curl -s -X POST http://localhost:11434/api/generate \
-d '{"model":"qwen3.5:35b-a3b","keep_alive":0}' # вивантажити з GPU
# C. Якщо Ollama не відповідає — перезапуск
docker restart ollama && sleep 10
curl -s http://localhost:11434/api/tags | python3 -m json.tool
Крок 3 — Verify
python3 ops/scripts/voice_canary.py --mode runtime --memory-url http://localhost:8000
# Очікування: overall=ok, Polina/Ostap < 3000ms
Alert 2: VoiceTTFA_P95_Breach_Quality
Умова: quality profile TTFA p95 > 7000ms | Severity: warning
Що значить: qwen3.5 або qwen3:14b надто повільні. Часто — конкурентні запити або cold token generation.
Дії
- Перевірити
degradation_status.repro.last_model— підтвердити що це quality profile. - Якщо це ізольована сесія — ігнорувати (quality SLO м'якший).
- Якщо 5+ хвилин стабільно → переключити всіх на fast: в
router-config.ymlтимчасово видалитиvoice_quality_ukзagent_voice_profiles.sofiia.quality_option. - Після нормалізації — повернути.
# Підтвердити що fast profile нормальний
curl -s -X POST http://localhost:8002/api/voice/chat/stream \
-H "Content-Type: application/json" \
-d '{"message":"ping","model":"ollama:gemma3:latest","voice_profile":"voice_fast_uk"}' \
| python3 -c "import sys,json; d=json.load(sys.stdin); print('llm_ms:', d['meta']['llm_ms'])"
Alert 3: VoiceQueueUnderflow_Spike
Умова: underflow rate > 1/хв за 5 хвилин | Severity: warning
Що значить: браузер відтворює аудіо швидше ніж BFF синтезує rest_chunks. Користувач чує тишу між реченнями.
Діагностика
# Перевірити TTS latency (чи сповільнилось edge-tts?)
curl -s http://localhost:8000/voice/health | python3 -c \
"import sys,json; d=json.load(sys.stdin); [print(v['voice'], v['ms'],'ms') for v in d['voices']]"
# Перевірити concurrent TTS slots
curl -s http://localhost:8002/api/voice/degradation_status | python3 -c \
"import sys,json; d=json.load(sys.stdin); print('free slots:', d['repro']['concurrent_tts_slots_free'])"
Mitigation
- Якщо TTS slow (> 2s) → Alert 4 (edge-tts). Дивись нижче.
- Якщо concurrent slots = 0 → TTS DOS. Перевірити
docker stats dagi-memory-service-node2. ЗбільшитиMAX_CONCURRENT_TTSабо перезапустити memory-service. - Якщо slots OK → перший чанк надто короткий (~1 речення). Тимчасове рішення — зменшити
MIN_CHUNK_CHARSуvoice_utils.pyщоб більше тексту йшло у перший чанк.
Alert 4: VoiceTTS_P95_Degraded
Умова: TTS synthesis p95 > 2000ms за 10 хвилин | Severity: critical
Що значить: edge-tts сповільнився або починає отримувати 403. Типова причина — Microsoft endpoint зміна auth або rate limiting.
Крок 1 — Визначити тип помилки (1 хв)
# Подивитись last_5_tts_errors
curl -s http://localhost:8002/api/voice/degradation_status | python3 -c \
"import sys,json; d=json.load(sys.stdin); [print(e) for e in d['repro']['last_5_tts_errors']]"
# Живий тест
python3 ops/scripts/voice_canary.py --mode preflight --memory-url http://localhost:8000
Якщо 403 errors:
# Перевірити версію edge-tts
docker exec dagi-memory-service-node2 pip show edge-tts | grep Version
# Очікується: 7.2.7
# Якщо версія не 7.2.7 — оновити
docker exec dagi-memory-service-node2 pip install edge-tts==7.2.7
docker restart dagi-memory-service-node2
sleep 10 && python3 ops/scripts/voice_canary.py --mode preflight
Якщо timeout / network:
# Тест від сервера до Microsoft endpoint
docker exec dagi-memory-service-node2 python3 -c \
"import asyncio, edge_tts; asyncio.run(edge_tts.list_voices())"
# Якщо мережева проблема — тимчасово переключити на espeak (fallback)
# В memory-service env: TTS_FALLBACK_ENGINE=espeak
# Увага: якість значно гірша, але голос є
Нотувати в incident log:
curl -s -X POST http://localhost:9102/v1/tools/execute \
-H "Content-Type: application/json" \
-d '{"tool":"oncall_tool","action":"incident_log_append","params":{"severity":"sev2","title":"TTS degraded — edge-tts","body":"VoiceTTS_P95_Degraded alert fired. Last errors: ..."}}'
Alert 5: VoiceTTS_ErrorRate_High
Умова: TTS errors > 0.05/s за 3 хвилини | Severity: critical
Що значить: масові відмови TTS синтезу. Користувачі або не чують нічого, або чують espeak-fallback.
Перший крок (30 секунд)
# Скільки помилок і якого типу
docker logs dagi-memory-service-node2 --since 5m 2>&1 | grep -c "ERROR\|403\|edge.tts"
docker logs dagi-memory-service-node2 --since 5m 2>&1 | grep "ERROR" | tail -5
Mitigation tree:
error_type = 403 → Крок "Якщо 403 errors" з Alert 4
error_type = timeout → Перевірити мережу, перезапустити memory-service
error_type = synthesis → pip install edge-tts==7.2.7 --force-reinstall
error_type = OOM → docker stats → перезапустити memory-service з більшим RAM limit
Аварійний fallback (якщо нічого не допомогло):
# Вимкнути автоспік у UI — щоб не показувало помилки
# Або тимчасово вимкнути streaming
docker exec sofiia-console env VOICE_STREAM_ENABLED=false \
uvicorn app.main:app --host 0.0.0.0 --port 8002 &
# (не рекомендовано на prod без rebuild, але як аварійний захід)
Повідомити користувачів (якщо > 10 хвилин):
- Додати banner у UI: змінна
VOICE_DEGRADED_BANNERу env → відобразити через degradation badge "🔴 TTS DEGRADED"
Escalation
| Тривалість | Дія |
|---|---|
| < 10 хв | Автоматичний деградаційний badge у UI, моніторинг |
| 10–30 хв | Mitigation з цього runbook, canary preflight |
| > 30 хв | Escalate до @IvanTytar, записати incident в ops/incidents.jsonl |
| > 2 год | Post-mortem draft (Sofiia-supervisor postmortem_draft_graph) |
# Записати incident
echo '{"ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","sev":"sev2","title":"Voice TTS degraded","status":"open"}' \
>> ops/incidents.jsonl
Корисні команди (bookmark)
# Швидкий статус всього voice стеку
curl -s http://localhost:8002/api/voice/degradation_status | python3 -m json.tool
curl -s http://localhost:8000/voice/health | python3 -c "import sys,json; d=json.load(sys.stdin); print('TTS:', d['edge_tts'], '| Polina:', [v for v in d['voices'] if 'Polina' in v['voice']][0]['ms'], 'ms')"
python3 ops/scripts/voice_canary.py --mode preflight
# Browser console для активних сесій
# _voiceStats() — p50/p95 по останніх 20 турнах
# _voice_degradation_sm — поточний стан на сервері
# Prometheus queries (якщо є)
# histogram_quantile(0.95, rate(voice_ttfa_ms_bucket[5m])) by (voice_profile)
# rate(voice_tts_errors_total[5m])
# rate(voice_queue_underflows_total[5m]) * 60