diff --git a/personal/tech/hermes-whale-mattermost-transport.md b/personal/tech/hermes-whale-mattermost-transport.md index 75dd6e8e..44a98981 100755 --- a/personal/tech/hermes-whale-mattermost-transport.md +++ b/personal/tech/hermes-whale-mattermost-transport.md @@ -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//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` требует ШЕСТЬ флагов, не один.**