docs(mm-transport): закрыт инцидент 2026-09-30 — root-post thread_id ломал session_key

This commit is contained in:
Alexey Martemyanov committed 2026-09-30 11:19:40 +06:00
1 parent bfd42631e2
commit 2a6cd95355
1 file changed
+78 -2
@@ -1,10 +1,10 @@
---
title: hermes-whale — Mattermost как транспорт
created: '2026-09-29'
updated: '2026-09-29'
updated: '2026-09-30'
type: tech
namespace: personal
status: транспорт+telegram+pairing+toolsets+рестарт ✅; 🔴 открыт инцидент — бот не в канале hermes-maintenance
status: "транспорт+telegram+pairing+toolsets+рестарт ✅; \U0001F534 фикс root-post thread_id 2026-09-30 (916f2c7e4f) — ЖДЁТ РЕСТАРТА gateway; \U0001F534 открыт инцидент — бот не в канале hermes-maintenance"
tags:
- hermes
- mattermost
@@ -15,6 +15,7 @@ tags:
- telegram
- hermes-maintenance
- incident
- thread-session-split
related:
- '[[personal/projects/balda/mattermost-kraken-deploy.md]]'
- '[[personal/tech/kraken-host-resource-limits.md]]'
@@ -325,6 +326,81 @@ ssh kraken "docker exec mm-postgres psql -U mmuser -d mattermost -t -c \"...\""
| `memories/MEMORY.md` | 0 байт (глобальный fallback не используется) |
| `memories/threads/<key>/MEMORY.md` | по тред-ключу |
## 🔴 Инцидент 2026-09-30 (ЗАКРЫТ): один тред разъезжался на две сессии
**Симптом Alex:** «Какой нахуй другой? Один блять тред!» —
писал в тред, получал ответ, а следующим сообщением в ТОМ ЖЕ треде —
«в этом треде до тебя ничего не было». Контекст пропадал.
### Причина (найдена в коде, воспроизведена тестом)
Первое сообщение **нового** треда — это его корень, у него `root_id == ""`.
`adapter.py` делал:
```python
thread_id = post.get("root_id") or None # -> None для корневого поста
```
Дальше `build_session_key` (`gateway/session.py:659`):
```python
if source.thread_id and not thread_sessions_per_user:
isolate_user = False # тред-ветка НЕ срабатывает при thread_id=None
...
if isolate_user and participant_id:
key_parts.append(str(participant_id)) # -> приклеивается USER_ID
```
| Сообщение | `root_id` | session_key |
|---|---|---|
| Корень треда (первое) | `""` | `...:chat:{user_id}` ← неверно |
| Ответ в треде | `17zbmoan...` | `...:chat:{thread_id}` ← верно |
Один тред → **два ключа** → две сессии. Пока в треде одно сообщение, всё ок;
как только приходит второе — агент в новой сессии, истории нет.
⚠️ **`cbwsorzwoigbtrdnteugnx4aqo` в session_key — это user_id админа, а не тред.**
Именно на этом я сначала ошибся: прочитал его как «другой тред».
Проверять структуру постов — `GET /api/v4/channels/{id}/posts`, а не глазами по логу.
### Фикс (коммит `916f2c7e4f`, hermes-agent, ветка main)
`plugins/platforms/mattermost/adapter.py:~864`:
```python
thread_id = post.get("root_id") or post_id or None
```
Свой `post_id` корневого поста = канонический `root_id` треда в Mattermost,
поэтому отправка через `_resolve_root_id` не ломается (при пустом `root_id`
она и так возвращает `post_id`).
### Тесты (`tests/gateway/test_mattermost.py`)
Добавлены 2 регресс-теста. **Проверено, что падают на нефикшеном коде:**
```
- agent:main:mattermost:channel:chan_456:root_post_abc <- после фикса
+ agent:main:mattermost:channel:chan_456:user_123 <- что было
```
| Прогон | Результат |
|---|---|
| `test_mattermost.py` (48) | 48 passed |
| + `test_session.py`, `test_ws_auth_retry.py`, `test_base_topic_sessions.py` (138) | 138 passed |
| `tests/gateway/` целиком | ⚠️ 413 failed / 2294 errors — **предсуществующий мусор**, на baseline (stash фикса) 464 failed / 2144 errors. К правке отношения не имеет. Не гонять полный `tests/gateway/` как критерий. |
### 📌 Питфолл: session_key ≠ тред
`agent:main:mattermost:channel:{chat_id}:{thread_id}`. Если последний сегмент
выглядит как id пользователя — значит `thread_id` не долетел.
**Не считать это другим тредом.**
### 📌 Питфолл: полный прогон `tests/gateway/` бесполезен
456+ ошибок на чистом дереве — конфликт фикстур/состояния при параллельном
сборе. Гонять **только целевые файлы**, иначе результат нечитаем.
## 🔴 Питфоллы, найденные на месте
1. **`mmctl user convert --bot` требует ШЕСТЬ флагов, не один.**