[2026-09-29] eagle: personal/plans/mattermost-mention-thread-autoresponse.md personal/plans/mattermost-mention-thread-autoresponse.md.bak-mention-result personal/tech/hermes-whale-mattermost-transport.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-29 12:46:04 +06:00
1 parent b30684ecfb
commit e75cf79e79
3 files changed
+273

No files matched your search

@@ -0,0 +1,135 @@
---
tags:
- hermes
- mattermost
- mention
- adapter
- whale
type: plan
namespace: personal
status: implemented — awaiting gateway restart
created: '2026-09-29'
updated: '2026-09-29'
---
# План: MM mention-gating — авто-ответ в треде с ботом
**Дата:** 2026-09-29
**Статус:** Реализовано, ждёт рестарта gateway (приёмка Alex в UI)
## Итог
| Что | Значение |
|---|---|
| Файл | `~/.hermes/hermes-agent/plugins/platforms/mattermost/adapter.py` |
| md5 до | `9f3def29d90d00287cdbca3db000c513` |
| md5 после | `ed8c4b7735e3371f697c20cfbd11e421` |
| Бэкап | `~/.hermes/hermes-whale/backups/20260929-mm-mention/adapter.py` |
| Скрипт | `/tmp/mm-thread-mention.py` (идемпотентный) |
| Тесты | `tests/gateway/test_mattermost.py` — 46 passed (было 43, +3) |
| Коммит hermes-agent | `9b46ba791a` feat(mattermost): allow thread replies without @mention |
| Push | `207a1de16c..9b46ba791a main -> main` → github.com:mallexxx/hermes-agent.git |
### Что именно изменено
`_handle_ws_event`, перед mention-гейтом:
```python
is_thread_reply = bool(post.get("root_id"))
...
if (
require_mention
and not is_free_channel
and not has_mention
and not is_thread_reply
):
return
```
Три новых теста:
- `test_thread_reply_without_mention_responds` — тред без меншна → ответ есть
- `test_channel_root_without_mention_still_skipped` — корень канала без меншна → тишина
- `test_thread_reply_with_mention_strips_mention` — меншн в треде всё ещё убирается из текста
Остаток: рестарт gateway. Без него патч не подхватится (адаптер импортируется при старте).
`gateway run --replace` из активной сессии её убьёт — рестарт делает Alex.
## Задача (Alex, дословно)
> «в канале — меншен обязателен, в треде где только с ботом переписка — авто, без меншена»
## Проблема (подтверждена фактами)
`plugins/platforms/mattermost/adapter.py:734` — гейт применяется к **любому** не-DM:
```python
if channel_type_raw != "D": # тред = channel_type "O" → гейт срабатывает
...
if require_mention and not is_free_channel and not has_mention:
return # молча дроп, inbound не создаётся
```
**Доказательство (2026-09-29, канал `hermes-maintenance` = `a6nyh77eyjbn5c1owh1i8eebee`):**
| Время | Пост | Меншн | inbound в gateway.log |
|---|---|---|---|
| 12:38:01 | `@whale` | ✅ | ✅ есть |
| 12:38:40 | `тут, отлично. как нам сделать бэкап...` | ❌ | ❌ **нет** (ответа не было) |
Пост 12:38:40 — в треде `pcoiddzrqty3ipqtozgcs9ttte`, начатом ботом. Меншн не нужен, но требуется.
## Решение
Пропускать mention-гейт, когда пост находится **в треде** (`root_id` задан).
В корне канала меншн остаётся обязательным.
### Критерий (выбран)
**Тред = `root_id` непустой.** Просто, детерминированно, не требует API-запросов.
Обоснование: чтобы ответить в треде, бот должен быть в канале. Треды канала — общие
рабочие ветки; вовлечение в тред человеком = приглашение. Дополнительный критерий
«бот уже отвечал в этом треде» требует запроса к API на каждое сообщение (латентность +
зависимость от прав) и не даёт выигрыша: в канале бот и так отвечает на `@whale`.
### Правка
В `_handle_ws_event` перед mention-гейтом вычислить `root_id` и добавить его в условие:
```python
is_thread_reply = bool(post.get("root_id"))
...
if require_mention and not is_free_channel and not has_mention and not is_thread_reply:
return
```
Плюс: стрип меншна выполнять как раньше (если меншн есть — убрать из текста).
### Что НЕ меняется
- Корень канала без `@whale` → по-прежнему молчит.
- `MATTERMOST_FREE_RESPONSE_CHANNELS` — не трогаем.
- DM — не затронуты.
- `MATTERMOST_REQUIRE_MENTION=true` — остаётся.
## Шаги
1. Коммит ДО (`hermes-agent`, ветка `main`, HEAD `207a1de16c`).
2. Правка adapter.py — скрипт `python3 /tmp/<name>.py`, не sed.
3. Тест: `pytest plugins/platforms/mattermost/ tests/ -k mattermost -o "addopts="` (если есть).
4. Коммит ПОСЛЕ.
5. Рестарт gateway — **делает Alex** (`gateway run --replace` из этой сессии её убьёт).
6. Приёмка Alex в UI: пост в треде без меншна → ответ есть; пост в корне канала без меншна → ответа нет.
## Питфоллы
- 🔴 `gateway run --replace` из этой сессии убивает саму сессию (инцидент 2026-09-29 11:31).
- 🔴 Логи читать из `~/.hermes/hermes-whale/logs/`, не из `~/.hermes/logs/`.
- Адаптер читает `config.extra.*` ИЛИ env — при правке поведение env перебивает config
(см. `_apply_yaml_config`, строки 1108-1114).
- Логи уровня DEBUG не пишутся — `skipping non-DM message without @mention` в `gateway.log`
не виден (`grep -c` вернул 0 при 1.6 МБ лога). Судить по наличию/отсутствию `inbound message`.
## Связанные заметки
- [[personal/tech/hermes-whale-mattermost-transport.md]] — транспорт, env-ключи, инцидент с рестартом, диагностика «бот молчит в канале»
- [[personal/tech/hermes-pairing-multi-profile.md]] — pairing
@@ -0,0 +1,98 @@
---
tags:
- hermes
- mattermost
- mention
- adapter
- whale
type: plan
namespace: personal
status: plan approved — in progress
created: '2026-09-29'
updated: '2026-09-29'
---
# План: MM mention-gating — авто-ответ в треде с ботом
**Дата:** 2026-09-29
**Статус:** план утверждён Alex, выполняется
## Задача (Alex, дословно)
> «в канале — меншен обязателен, в треде где только с ботом переписка — авто, без меншена»
## Проблема (подтверждена фактами)
`plugins/platforms/mattermost/adapter.py:734` — гейт применяется к **любому** не-DM:
```python
if channel_type_raw != "D": # тред = channel_type "O" → гейт срабатывает
...
if require_mention and not is_free_channel and not has_mention:
return # молча дроп, inbound не создаётся
```
**Доказательство (2026-09-29, канал `hermes-maintenance` = `a6nyh77eyjbn5c1owh1i8eebee`):**
| Время | Пост | Меншн | inbound в gateway.log |
|---|---|---|---|
| 12:38:01 | `@whale` | ✅ | ✅ есть |
| 12:38:40 | `тут, отлично. как нам сделать бэкап...` | ❌ | ❌ **нет** (ответа не было) |
Пост 12:38:40 — в треде `pcoiddzrqty3ipqtozgcs9ttte`, начатом ботом. Меншн не нужен, но требуется.
## Решение
Пропускать mention-гейт, когда пост находится **в треде** (`root_id` задан).
В корне канала меншн остаётся обязательным.
### Критерий (выбран)
**Тред = `root_id` непустой.** Просто, детерминированно, не требует API-запросов.
Обоснование: чтобы ответить в треде, бот должен быть в канале. Треды канала — общие
рабочие ветки; вовлечение в тред человеком = приглашение. Дополнительный критерий
«бот уже отвечал в этом треде» требует запроса к API на каждое сообщение (латентность +
зависимость от прав) и не даёт выигрыша: в канале бот и так отвечает на `@whale`.
### Правка
В `_handle_ws_event` перед mention-гейтом вычислить `root_id` и добавить его в условие:
```python
is_thread_reply = bool(post.get("root_id"))
...
if require_mention and not is_free_channel and not has_mention and not is_thread_reply:
return
```
Плюс: стрип меншна выполнять как раньше (если меншн есть — убрать из текста).
### Что НЕ меняется
- Корень канала без `@whale` → по-прежнему молчит.
- `MATTERMOST_FREE_RESPONSE_CHANNELS` — не трогаем.
- DM — не затронуты.
- `MATTERMOST_REQUIRE_MENTION=true` — остаётся.
## Шаги
1. Коммит ДО (`hermes-agent`, ветка `main`, HEAD `207a1de16c`).
2. Правка adapter.py — скрипт `python3 /tmp/<name>.py`, не sed.
3. Тест: `pytest plugins/platforms/mattermost/ tests/ -k mattermost -o "addopts="` (если есть).
4. Коммит ПОСЛЕ.
5. Рестарт gateway — **делает Alex** (`gateway run --replace` из этой сессии её убьёт).
6. Приёмка Alex в UI: пост в треде без меншна → ответ есть; пост в корне канала без меншна → ответа нет.
## Питфоллы
- 🔴 `gateway run --replace` из этой сессии убивает саму сессию (инцидент 2026-09-29 11:31).
- 🔴 Логи читать из `~/.hermes/hermes-whale/logs/`, не из `~/.hermes/logs/`.
- Адаптер читает `config.extra.*` ИЛИ env — при правке поведение env перебивает config
(см. `_apply_yaml_config`, строки 1108-1114).
- Логи уровня DEBUG не пишутся — `skipping non-DM message without @mention` в `gateway.log`
не виден (`grep -c` вернул 0 при 1.6 МБ лога). Судить по наличию/отсутствию `inbound message`.
## Связанные заметки
- [[personal/tech/hermes-whale-mattermost-transport.md]] — транспорт, env-ключи, инцидент с рестартом
- [[personal/tech/hermes-pairing-multi-profile.md]] — pairing
@@ -260,6 +260,46 @@ ssh kraken "docker exec mm-postgres psql -U mmuser -d mattermost -t -c \
⚠️ Без членства в канале `@whale` не работает даже при `REQUIRE_MENTION=true` —
упоминание не создаёт доставку, оно лишь фильтр поверх уже приходящих событий.
### ✅ Тред-посты больше не требуют меншна (патч 2026-09-29)
**Проблема:** mention-гейт применялся к **любому** не-DM, включая треды. Пост в треде,
начатом ботом, без `@whale` молча дропался (подтверждено: пост 12:38:40 в треде
`pcoiddzrqty3ipqtozgcs9ttte` не попал в `gateway.log`).
**Решение (коммит `9b46ba791a`, hermes-agent):**
```python
# plugins/platforms/mattermost/adapter.py, _handle_ws_event
is_thread_reply = bool(post.get("root_id"))
...
if (
require_mention
and not is_free_channel
and not has_mention
and not is_thread_reply
):
return
```
**Правило после патча:**
| Место поста | Меншн `@whale` |
|---|---|
| Корень канала | ✅ обязателен |
| Тред (`root_id` непустой) | ❌ не нужен |
| DM | ❌ не нужен (был и раньше) |
`MATTERMOST_REQUIRE_MENTION=true` остаётся; `FREE_RESPONSE_CHANNELS` не тронут.
Если меншн в треде всё же написан — он убирается из текста перед отправкой агенту.
⚠️ **Патч активен только после рестарта gateway** — адаптер импортируется при старте.
Рестарт делает Alex (`gateway run --replace` из активной сессии её убивает, см. §Инцидент).
**Файлы:**
- План + итог: [[personal/plans/mattermost-mention-thread-autoresponse.md]]
- Бэкап адаптера: `~/.hermes/hermes-whale/backups/20260929-mm-mention/adapter.py`
- Тесты: `tests/gateway/test_mattermost.py` — 46 passed (3 новых)
### 📌 Питфолл диагностики: `mattermost psql`
В контейнере `mattermost` **нет `psql`** (`exec: "psql": executable file not found`).