Files
microdao-daarion/ops/runbook-voice-incidents.md
Apple 67225a39fa 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
2026-03-03 07:14:53 -08:00

9.9 KiB
Raw Permalink Blame History

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.

Дії

  1. Перевірити degradation_status.repro.last_model — підтвердити що це quality profile.
  2. Якщо це ізольована сесія — ігнорувати (quality SLO м'якший).
  3. Якщо 5+ хвилин стабільно → переключити всіх на fast: в router-config.yml тимчасово видалити voice_quality_uk з agent_voice_profiles.sofiia.quality_option.
  4. Після нормалізації — повернути.
# Підтвердити що 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, моніторинг
1030 хв 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