Guard rails (mixed_routing.py):
- MAX_AGENTS_PER_MIXED_ROOM (default 5): fail-fast at parse time
- MAX_SLASH_LEN (default 32): reject garbage/injection slash tokens
- Unified rejection reasons: unknown_agent, slash_too_long, no_mapping
- REASON_REJECTED_* constants (separate from success REASON_*)
Ingress (ingress.py):
- per-room-agent concurrency semaphore (MIXED_CONCURRENCY_CAP, default 1)
- active_lock_count property for /health + prometheus
- UNKNOWN_AGENT_BEHAVIOR: "ignore" (silent) | "reply_error" (inform user)
- on_routed(agent_id, reason) callback for routing metrics
- on_route_rejected(room_id, reason) callback for rejection metrics
- matrix.route.rejected audit event on every rejection
Config + main:
- max_agents_per_mixed_room, max_slash_len, unknown_agent_behavior, mixed_concurrency_cap
- matrix_bridge_routed_total{agent_id, reason} counter
- matrix_bridge_route_rejected_total{room_id, reason} counter
- matrix_bridge_active_room_agent_locks gauge
- /health: mixed_guard_rails section + total_agents_in_mixed_rooms
- docker-compose: all 4 new guard rail env vars
Runbook: section 9 — mixed room debug guide (6 acceptance tests, routing metrics, session isolation, lock hang, config guard)
Tests: 108 pass (94 → 108, +14 new tests for guard rails + callbacks + concurrency)
Made-with: Cursor
531 lines
19 KiB
Markdown
531 lines
19 KiB
Markdown
# Matrix Bridge DAGI — Ops Runbook (H4)
|
||
|
||
**Сервіс:** `matrix-bridge-dagi` | **Нода:** NODA1 | **Порт:** 7030 (localhost)
|
||
**Stack:** Matrix (Synapse) → bridge → Router `/v1/agents/{id}/infer` → Matrix reply
|
||
**Фаза:** M2.2 (N rooms + mixed room routing), H1/H2/H3 hardening активний
|
||
|
||
---
|
||
|
||
## 0. Purpose
|
||
|
||
Операційні перевірки та troubleshooting для `matrix-bridge-dagi` на NODA1:
|
||
|
||
- Matrix ↔ Bridge ↔ Router ↔ Agent ↔ Matrix
|
||
- Audit events в sofiia-console (`POST /api/audit/internal`)
|
||
- Rate limit (room/sender RPM)
|
||
- Backpressure queue (drops/queue wait)
|
||
|
||
---
|
||
|
||
## 1. Quick Status (30 секунд)
|
||
|
||
### 1.1 Health
|
||
|
||
```bash
|
||
curl -sS http://127.0.0.1:7030/health | python3 -m json.tool
|
||
```
|
||
|
||
Очікування:
|
||
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"matrix_reachable": true,
|
||
"gateway_reachable": true,
|
||
"mappings_count": 1,
|
||
"queue": {"size": 0, "max": 100, "workers": 2},
|
||
"rate_limiter": {"room_rpm_limit": 20, "sender_rpm_limit": 10, "active_rooms": 0, "active_senders": 0}
|
||
}
|
||
```
|
||
|
||
| Поле | Норма | Тривога |
|
||
|------|-------|---------|
|
||
| `ok` | `true` | `false` → дивитись `error` |
|
||
| `matrix_reachable` | `true` | `false` → I4 |
|
||
| `gateway_reachable` | `true` | `false` → I1 |
|
||
| `queue.size` | ≈0 idle | >50 → I3 |
|
||
| `mappings_count` | ≥1 | 0 → перевірити `BRIDGE_ROOM_MAP` |
|
||
|
||
### 1.2 Mappings
|
||
|
||
```bash
|
||
curl -sS http://127.0.0.1:7030/bridge/mappings | python3 -m json.tool
|
||
```
|
||
|
||
### 1.3 Logs (останні 30 рядків)
|
||
|
||
```bash
|
||
docker logs matrix-bridge-dagi-node1 --tail 30
|
||
```
|
||
|
||
Шукати: `ERROR`, `Rate limited`, `Queue full`, `Invoke ok`, `Reply sent`
|
||
|
||
---
|
||
|
||
## 2. Smoke Test (2–3 хв)
|
||
|
||
### 2.1 E2E через Element (рекомендовано)
|
||
|
||
1. Element → "Change homeserver" → `matrix.daarion.space`
|
||
2. Логін: `test_user` / `TestUser_2026!`
|
||
3. Room: **DAGI — Sofiia**
|
||
4. Відправити: `ping`
|
||
5. Очікування: reply ≤ 5s (Mistral/DeepSeek залежний)
|
||
|
||
### 2.2 Smoke через curl (без Element)
|
||
|
||
```bash
|
||
# Логін як test_user
|
||
TOKEN=$(curl -sS -X POST http://localhost:8008/_matrix/client/v3/login \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"type":"m.login.password","identifier":{"type":"m.id.user","user":"test_user"},"password":"TestUser_2026!"}' \
|
||
| python3 -c 'import sys,json; print(json.load(sys.stdin)["access_token"])')
|
||
|
||
# Відправити повідомлення
|
||
ROOM_ID=$(grep 'SOFIIA_ROOM_ID' /opt/microdao-daarion/.env | cut -d= -f2)
|
||
TXN_ID="smoke-$(date +%s)"
|
||
curl -sS -X PUT "http://localhost:8008/_matrix/client/v3/rooms/$ROOM_ID/send/m.room.message/$TXN_ID" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"msgtype":"m.text","body":"smoke test ping"}' | python3 -c 'import sys,json; print("sent:", json.load(sys.stdin).get("event_id","ERROR"))'
|
||
|
||
# Чекати reply (~15-30s залежить від sync cycle)
|
||
sleep 30
|
||
|
||
# Перевірити health metrics
|
||
curl -sS http://127.0.0.1:7030/metrics | grep -E 'matrix_bridge_(messages_received|messages_replied)_total'
|
||
```
|
||
|
||
### 2.3 Перевірити .well-known (для Element auto-discovery)
|
||
|
||
```bash
|
||
curl -sS https://matrix.daarion.space/.well-known/matrix/client
|
||
# Очікування: {"m.homeserver":{"base_url":"https://matrix.daarion.space"}}
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Операційні Метрики
|
||
|
||
### 3.1 Traffic counters
|
||
|
||
```bash
|
||
curl -sS http://127.0.0.1:7030/metrics | grep -E \
|
||
"matrix_bridge_messages_(received|replied)_total|matrix_bridge_rate_limited_total|matrix_bridge_queue_dropped_total"
|
||
```
|
||
|
||
| Метрика | Значення | Що означає |
|
||
|---------|----------|------------|
|
||
| `messages_received_total` | росте | повідомлення надходять |
|
||
| `messages_replied_total{status="ok"}` | росте | агент відповідає |
|
||
| `messages_replied_total{status="error"}` | >0 | проблема send_text → I1 |
|
||
| `rate_limited_total` | ≈0 | норма; >0 → I2 |
|
||
| `queue_dropped_total` | 0 | норма; >0 → I3 |
|
||
|
||
### 3.2 Latency histograms
|
||
|
||
```bash
|
||
curl -sS http://127.0.0.1:7030/metrics | grep -E \
|
||
"(invoke_duration|send_duration|queue_wait)_seconds_(bucket|count|sum)"
|
||
```
|
||
|
||
Орієнтири:
|
||
|
||
| Histogram | Норма (p95) | Тривога |
|
||
|-----------|-------------|---------|
|
||
| `invoke_duration_seconds` | 1–5s | >20s → LLM деградація |
|
||
| `send_duration_seconds` | <200ms | >2s → Synapse проблема |
|
||
| `queue_wait_seconds` | <50ms idle | >5s → I3 (workers перевантажені) |
|
||
|
||
### 3.3 Queue state
|
||
|
||
```bash
|
||
curl -sS http://127.0.0.1:7030/health | python3 -c \
|
||
'import sys,json; d=json.load(sys.stdin); print("queue:", d.get("queue"))'
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Audit Events (sofiia-console)
|
||
|
||
### 4.1 Перевірити audit ingest (internal endpoint)
|
||
|
||
```bash
|
||
INT_TOKEN=$(grep 'SOFIIA_INTERNAL_TOKEN' /opt/microdao-daarion/.env | cut -d= -f2)
|
||
curl -sS -X POST http://127.0.0.1:8002/api/audit/internal \
|
||
-H 'Content-Type: application/json' \
|
||
-H "X-Internal-Service-Token: $INT_TOKEN" \
|
||
-d '{"event":"matrix.smoke_check","agent_id":"sofiia","node_id":"NODA1","status":"ok"}' | python3 -m json.tool
|
||
# Очікування: {"ok": true, "event": "matrix.smoke_check"}
|
||
```
|
||
|
||
### 4.2 Події для пошуку в audit log
|
||
|
||
| Event | Коли | Норма |
|
||
|-------|------|-------|
|
||
| `matrix.message.received` | при кожному вхідному | завжди |
|
||
| `matrix.agent.replied` | при успішній відповіді | завжди |
|
||
| `matrix.rate_limited` | при перевищенні RPM | рідко/ніколи |
|
||
| `matrix.queue_full` | при переповненні черги | ніколи |
|
||
| `matrix.error` | при помилці invoke/send | ніколи |
|
||
|
||
---
|
||
|
||
## 5. Common Incidents
|
||
|
||
### I1: "Element підключений, але Sofiia не відповідає"
|
||
|
||
```bash
|
||
# Step 1: health check
|
||
curl -sS http://127.0.0.1:7030/health | python3 -c 'import sys,json; d=json.load(sys.stdin); print("matrix:", d.get("matrix_reachable"), "gw:", d.get("gateway_reachable"), "maps:", d.get("mappings_count"))'
|
||
|
||
# Step 2: metrics — received vs replied
|
||
curl -sS http://127.0.0.1:7030/metrics | grep -E 'matrix_bridge_messages_(received|replied)_total'
|
||
|
||
# Step 3: logs
|
||
docker logs matrix-bridge-dagi-node1 --tail 50 | grep -E 'ERROR|invoke|reply|error'
|
||
|
||
# Step 4: router direct test
|
||
curl -sS -X POST http://127.0.0.1:9102/v1/agents/sofiia/infer \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"prompt":"ping","session_id":"smoke-check","user_id":"ops"}' | python3 -c 'import sys,json; d=json.load(sys.stdin); print("router:", d.get("response","ERROR")[:80])'
|
||
```
|
||
|
||
**Фікс:**
|
||
- `gateway_reachable: false` → перевірити `DAGI_GATEWAY_URL=http://dagi-router-node1:8000`
|
||
- `mappings_count: 0` → перевірити `BRIDGE_ROOM_MAP` в env
|
||
- received росте, replied ні → router або send_text проблема (Step 4)
|
||
|
||
---
|
||
|
||
### I2: "Bagato rate_limited в metrics"
|
||
|
||
```bash
|
||
curl -sS http://127.0.0.1:7030/metrics | grep rate_limited_total
|
||
curl -sS http://127.0.0.1:7030/health | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("rate_limiter"))'
|
||
```
|
||
|
||
**Причина:** RPM занадто низький або room flood (bot/скрипт).
|
||
|
||
**Фікс** (тимчасово, через env):
|
||
```bash
|
||
# На NODA1:
|
||
cd /opt/microdao-daarion
|
||
# Відредагувати .env:
|
||
# RATE_LIMIT_ROOM_RPM=40
|
||
# RATE_LIMIT_SENDER_RPM=20
|
||
docker compose -f docker-compose.matrix-bridge-node1.yml up -d
|
||
```
|
||
|
||
---
|
||
|
||
### I3: "Queue drops ростуть / queue.size велике"
|
||
|
||
```bash
|
||
curl -sS http://127.0.0.1:7030/metrics | grep queue_dropped_total
|
||
curl -sS http://127.0.0.1:7030/metrics | grep 'invoke_duration_seconds_bucket'
|
||
```
|
||
|
||
**Причина:** модель/Router повільні або `WORKER_CONCURRENCY` малий.
|
||
|
||
**Фікс:**
|
||
```bash
|
||
# Збільшити workers і queue (в .env):
|
||
# WORKER_CONCURRENCY=4
|
||
# QUEUE_MAX_EVENTS=300
|
||
docker compose -f docker-compose.matrix-bridge-node1.yml up -d
|
||
```
|
||
|
||
Паралельно перевірити latency histogram — якщо `invoke_duration` >20s, проблема на стороні LLM.
|
||
|
||
---
|
||
|
||
### I4: "matrix_reachable: false у /health"
|
||
|
||
```bash
|
||
# Synapse публічний ендпоінт
|
||
curl -sS https://matrix.daarion.space/_matrix/client/versions | python3 -c 'import sys,json; d=json.load(sys.stdin); print("ok, versions:", list(d.get("versions",[]))[:3])'
|
||
|
||
# Synapse внутрішній (з NODA1)
|
||
curl -sS http://localhost:8008/_matrix/client/versions
|
||
|
||
# Synapse контейнер
|
||
docker ps | grep synapse
|
||
docker logs dagi-synapse-node1 --tail 20
|
||
|
||
# Nginx
|
||
curl -sI https://matrix.daarion.space/_matrix/client/versions | head -3
|
||
```
|
||
|
||
**Фікс:**
|
||
- Synapse контейнер впав → `docker compose -f docker-compose.synapse-node1.yml up -d`
|
||
- TLS / .well-known → перевірити nginx (`nginx -t && nginx -s reload`)
|
||
- Токен невалідний → I5 (rotation)
|
||
|
||
---
|
||
|
||
### I5: "Замінити MATRIX_ACCESS_TOKEN"
|
||
|
||
```bash
|
||
# 1. Отримати новий токен (з NODA1)
|
||
NEW_TOKEN=$(curl -sS -X POST http://localhost:8008/_matrix/client/v3/login \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"type":"m.login.password","identifier":{"type":"m.id.user","user":"dagi_bridge"},"password":"DAGIbr1dge_M4tr1x_2026!"}' \
|
||
| python3 -c 'import sys,json; print(json.load(sys.stdin)["access_token"])')
|
||
echo "New token: ${#NEW_TOKEN} chars"
|
||
|
||
# 2. Оновити в .env
|
||
sed -i "s/^MATRIX_ACCESS_TOKEN=.*/MATRIX_ACCESS_TOKEN=$NEW_TOKEN/" /opt/microdao-daarion/.env
|
||
|
||
# 3. Restart bridge
|
||
cd /opt/microdao-daarion
|
||
docker compose -f docker-compose.matrix-bridge-node1.yml up -d
|
||
|
||
# 4. Verify
|
||
sleep 10
|
||
curl -sS http://127.0.0.1:7030/health | python3 -c 'import sys,json; d=json.load(sys.stdin); print("matrix:", d.get("matrix_reachable"))'
|
||
```
|
||
|
||
---
|
||
|
||
### I6: "Замінити SOFIIA_INTERNAL_TOKEN"
|
||
|
||
```bash
|
||
# 1. Генерувати новий токен
|
||
NEW_INT_TOKEN=$(openssl rand -base64 32 | tr -d '/+=')
|
||
|
||
# 2. Оновити в .env
|
||
sed -i "s/^SOFIIA_INTERNAL_TOKEN=.*/SOFIIA_INTERNAL_TOKEN=$NEW_INT_TOKEN/" /opt/microdao-daarion/.env
|
||
|
||
# 3. Restart обох сервісів
|
||
cd /opt/microdao-daarion
|
||
docker compose -f docker-compose.node1.yml up -d dagi-sofiia-console-node1
|
||
docker compose -f docker-compose.matrix-bridge-node1.yml up -d
|
||
sleep 15
|
||
|
||
# 4. Verify audit ingest
|
||
INT_TOKEN=$(grep 'SOFIIA_INTERNAL_TOKEN' .env | cut -d= -f2)
|
||
curl -sS -X POST http://127.0.0.1:8002/api/audit/internal \
|
||
-H 'Content-Type: application/json' \
|
||
-H "X-Internal-Service-Token: $INT_TOKEN" \
|
||
-d '{"event":"matrix.token_rotated","agent_id":"sofiia","node_id":"NODA1","status":"ok"}' | python3 -c 'import sys,json; print("audit ok:", json.load(sys.stdin).get("ok"))'
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Restart / Rollback
|
||
|
||
### Restart bridge
|
||
|
||
```bash
|
||
cd /opt/microdao-daarion
|
||
docker compose -f docker-compose.matrix-bridge-node1.yml up -d --force-recreate
|
||
sleep 15
|
||
curl -sS http://127.0.0.1:7030/health | python3 -c 'import sys,json; d=json.load(sys.stdin); print("ok:", d["ok"])'
|
||
```
|
||
|
||
### Restart Synapse
|
||
|
||
```bash
|
||
docker compose -f docker-compose.synapse-node1.yml up -d
|
||
sleep 20
|
||
curl -sS http://localhost:8008/_matrix/client/versions | python3 -c 'import sys,json; print("synapse ok:", "versions" in json.load(sys.stdin))'
|
||
```
|
||
|
||
### Мінімальний smoke після restart
|
||
|
||
```bash
|
||
curl -sS http://127.0.0.1:7030/health | python3 -c \
|
||
'import sys,json; d=json.load(sys.stdin); print("bridge ok:", d["ok"], "| matrix:", d.get("matrix_reachable"), "| gw:", d.get("gateway_reachable"))'
|
||
# Потім: 1 повідомлення в Element → reply
|
||
```
|
||
|
||
---
|
||
|
||
## 7. Release Checklist (перед деплоєм bridge)
|
||
|
||
```
|
||
[ ] health ok (ok: true, matrix: true, gw: true)
|
||
[ ] queue drops == 0 (curl /metrics | grep queue_dropped_total → 0)
|
||
[ ] rate_limited == 0 (curl /metrics | grep rate_limited_total → 0)
|
||
[ ] smoke test: Element → ping → reply ≤ 5s
|
||
[ ] audit events з'являються (matrix.message.received, matrix.agent.replied)
|
||
[ ] .well-known → JSON з base_url
|
||
[ ] TLS cert valid (не <7 days до expiry)
|
||
```
|
||
|
||
### Перевірка TLS cert (термін дії)
|
||
|
||
```bash
|
||
echo | openssl s_client -connect matrix.daarion.space:443 -servername matrix.daarion.space 2>/dev/null \
|
||
| openssl x509 -noout -dates
|
||
# notAfter — запас не менше 7 днів (auto-renew certbot)
|
||
```
|
||
|
||
---
|
||
|
||
---
|
||
|
||
## 9. Mixed Room Debug Guide (M2.2)
|
||
|
||
### 9.1 Перевірка конфігурації mixed rooms
|
||
|
||
```bash
|
||
# Поточний mapping (regular + mixed)
|
||
curl -sS http://127.0.0.1:7030/bridge/mappings | python3 -m json.tool
|
||
|
||
# Guard rail параметри (з /health)
|
||
curl -sS http://127.0.0.1:7030/health | python3 -m json.tool | python3 -c "
|
||
import sys, json; h=json.load(sys.stdin)
|
||
print('mixed_rooms:', h.get('mixed_rooms_count',0))
|
||
print('total_agents:', h.get('total_agents_in_mixed_rooms',0))
|
||
print('guard_rails:', json.dumps(h.get('mixed_guard_rails',{}), indent=2))
|
||
"
|
||
```
|
||
|
||
### 9.2 Smoke test для mixed room (6 acceptance test cases)
|
||
|
||
Відправляємо з `test_user` у mixed room `!roomX:daarion.space`:
|
||
|
||
```bash
|
||
# Змінна для зручності
|
||
ROOM_ID="!roomX:daarion.space"
|
||
TOKEN="@test_user_token" # або через Element UI
|
||
|
||
# 1. Slash → Sofiia
|
||
curl -sX POST "https://matrix.daarion.space/_matrix/client/v3/rooms/${ROOM_ID}/send/m.room.message/txn1" \
|
||
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
||
-d '{"msgtype":"m.text","body":"/sofiia ping"}' | jq '.event_id'
|
||
|
||
# 2. Slash → Helion
|
||
curl -sX POST "...txn2" -d '{"msgtype":"m.text","body":"/helion ping"}' | jq '.event_id'
|
||
|
||
# 3. @mention → Sofiia
|
||
curl -sX POST "...txn3" -d '{"msgtype":"m.text","body":"@sofiia status"}' | jq '.event_id'
|
||
|
||
# 4. colon-mention → Sofiia
|
||
curl -sX POST "...txn4" -d '{"msgtype":"m.text","body":"sofiia: status"}' | jq '.event_id'
|
||
|
||
# 5. Plain text → default agent
|
||
curl -sX POST "...txn5" -d '{"msgtype":"m.text","body":"ping"}' | jq '.event_id'
|
||
|
||
# 6. Unknown slash → audit matrix.route.rejected
|
||
curl -sX POST "...txn6" -d '{"msgtype":"m.text","body":"/unknown test"}' | jq '.event_id'
|
||
```
|
||
|
||
**Очікувана поведінка у кімнаті:**
|
||
| Команда | Reply prefix | Router agent |
|
||
|---------|-------------|--------------|
|
||
| `/sofiia ping` | `Sofiia: ...` | sofiia |
|
||
| `/helion ping` | `Helion: ...` | helion |
|
||
| `@sofiia status` | `Sofiia: ...` | sofiia |
|
||
| `sofiia: status` | `Sofiia: ...` | sofiia |
|
||
| `ping` (plain) | `<DefaultAgent>: ...` | перший у списку |
|
||
| `/unknown test` | `⚠️ Unknown agent...` або тиша (залежно від `UNKNOWN_AGENT_BEHAVIOR`) | — |
|
||
|
||
### 9.3 Перевірка routing метрик
|
||
|
||
```bash
|
||
# Successful routing breakdown by reason
|
||
curl -sS http://127.0.0.1:7030/metrics | grep 'matrix_bridge_routed_total'
|
||
# Очікування:
|
||
# matrix_bridge_routed_total{agent_id="sofiia",reason="slash_command"} N
|
||
# matrix_bridge_routed_total{agent_id="helion",reason="slash_command"} N
|
||
# matrix_bridge_routed_total{agent_id="sofiia",reason="at_mention"} N
|
||
# matrix_bridge_routed_total{agent_id="sofiia",reason="default"} N
|
||
|
||
# Rejections
|
||
curl -sS http://127.0.0.1:7030/metrics | grep 'matrix_bridge_route_rejected_total'
|
||
# Очікується > 0 лише якщо були /unknown або занадто довгі токени
|
||
|
||
# Active concurrency locks
|
||
curl -sS http://127.0.0.1:7030/metrics | grep 'active_room_agent_locks'
|
||
# Зазвичай 0 (між повідомленнями)
|
||
```
|
||
|
||
### 9.4 Debug: "Wrong agent responds"
|
||
|
||
**Симптом:** У mixed room `/helion ...` → відповідає sofiia, або відповідає не той агент.
|
||
|
||
**Діагностика:**
|
||
|
||
```bash
|
||
# 1. Перевірити audit events в sofiia-console
|
||
# (через psql або API)
|
||
curl -sS http://127.0.0.1:8002/api/audit \
|
||
| python3 -m json.tool | grep -A5 '"event":"matrix.message.received"' \
|
||
| grep '"routing_reason"'
|
||
# routing_reason має бути "slash_command", "at_mention", "colon_mention" або "default"
|
||
|
||
# 2. Перевірити логи bridge
|
||
docker logs matrix-bridge-dagi-node1 --tail 100 2>&1 | grep -E 'route|Route|routing'
|
||
# Очікування: "Slash route: /helion → helion" або "Default route: → sofiia"
|
||
|
||
# 3. Перевірити BRIDGE_MIXED_ROOM_MAP в .env
|
||
grep BRIDGE_MIXED_ROOM_MAP /opt/microdao-daarion/.env
|
||
# Формат: "!roomX:server=sofiia,helion"
|
||
# Перший у списку = default agent
|
||
```
|
||
|
||
**Виправлення:**
|
||
- Якщо порядок агентів неправильний — змінити `BRIDGE_MIXED_ROOM_MAP` або встановити `BRIDGE_MIXED_DEFAULTS`
|
||
- Перезапустити bridge: `docker restart matrix-bridge-dagi-node1`
|
||
|
||
### 9.5 Debug: "Session context змішується між агентами"
|
||
|
||
**Симптом:** Helion "пам'ятає" контекст розмови sofiia.
|
||
|
||
**Перевірка:** Session key у логах (`session_id` у invoke payload)
|
||
|
||
```bash
|
||
docker logs matrix-bridge-dagi-node1 --tail 50 2>&1 | grep session_id
|
||
# Очікування для mixed room:
|
||
# session_id = "matrix:roomX_daarion_space:sofiia" ← ізольований per-agent
|
||
# session_id = "matrix:roomX_daarion_space:helion" ← окремий контекст
|
||
```
|
||
|
||
Якщо обидва агенти мають однаковий `session_id` — це баг рефакторингу, відкати на M2.0.
|
||
|
||
### 9.6 Debug: Concurrency lock "застрявання"
|
||
|
||
**Симптом:** Запит зависає, не відповідає, active_lock_count > 0 протягом >60s.
|
||
|
||
```bash
|
||
# Перевірити active locks
|
||
curl -sS http://127.0.0.1:7030/health | python3 -m json.tool | python3 -c \
|
||
"import sys,json; h=json.load(sys.stdin); print(h.get('mixed_guard_rails',{}).get('active_room_agent_locks',0))"
|
||
|
||
# Якщо > 0 протягом довгого часу — Router застряг
|
||
curl -sS http://127.0.0.1:9102/health | jq '.status'
|
||
|
||
# Якщо Router недоступний — перезапуск bridge звільнить locks (graceful shutdown + cancel)
|
||
docker restart matrix-bridge-dagi-node1
|
||
```
|
||
|
||
### 9.7 Guard rail: перевірка MAX_AGENTS_PER_MIXED_ROOM
|
||
|
||
Якщо у `.env` є рядок з 6+ агентами і `MAX_AGENTS_PER_MIXED_ROOM=5`:
|
||
|
||
```bash
|
||
docker logs matrix-bridge-dagi-node1 --tail 20 2>&1 | grep 'Config error\|MAX_AGENTS'
|
||
# Очікується: "❌ Config error: BRIDGE_MIXED_ROOM_MAP parse errors: Room ... has 6 agents > MAX..."
|
||
# Bridge не стартує → /health поверне {"ok":false,"error":"..."}
|
||
```
|
||
|
||
**Виправлення:** Зменшити кількість агентів або збільшити `MAX_AGENTS_PER_MIXED_ROOM`.
|
||
|
||
---
|
||
|
||
## 8. Що прикріпити до інциденту
|
||
|
||
```bash
|
||
echo "=== /health ===" && curl -sS http://127.0.0.1:7030/health | python3 -m json.tool
|
||
echo "=== /bridge/mappings ===" && curl -sS http://127.0.0.1:7030/bridge/mappings | python3 -m json.tool
|
||
echo "=== /metrics traffic ===" && curl -sS http://127.0.0.1:7030/metrics \
|
||
| grep -E 'matrix_bridge_(messages|rate_limited|queue_dropped|gateway_errors|routed|route_rejected)'
|
||
echo "=== /metrics latency ===" && curl -sS http://127.0.0.1:7030/metrics \
|
||
| grep -E '(invoke|send|queue_wait)_duration_seconds_(count|sum)'
|
||
echo "=== logs ===" && docker logs matrix-bridge-dagi-node1 --tail 50 2>&1 \
|
||
| grep -E 'ERROR|WARN|rate_limited|queue_full|Reply sent|invoke ok|route|rejected'
|
||
```
|