Files
obsidian-vault/personal/plans/balda-mm-pr-plan.md
T

8.0 KiB
Raw Blame History

Balda — Mattermost connector: PR-подготовка (закрыто)

Создан 2026-09-26. Обновлён 2026-09-26 (PR-проход). Статус: ✅ ЗАКРЫТО — код, тесты, доки, коммиты готовы. Команда Alex: «Коммит текущего стейта и продолжай пока не стыдно будет открывать PR mattermost connector. Со всеми поддерживаемыми фичами и тестами. Вперёд! Без вопросов и требующих апрува команд.» Часть personal/projects/balda/balda-mm-delegation-plan (Фаза 2 → PR в апстрим).

Итог

Ветка feat/mattermost-channel, 6 коммитов (базовый 004fda2f + 5 новых). Готово к git push и PR.

58f27120 docs(mattermost): document the transport setup and behavior
80d4f41d test(mattermost): cover the transport, the ingress and the handler
c7f18654 fix(mattermost): send a monotonic seq on every client frame
6dc3077a feat(mattermost): add the inbound handler and wire it into DI
fa1a2855 feat(auth): support the Mattermost channel subject
004fda2f feat(mattermost): add Mattermost transport adapter   ← база

Quality gates — все зелёные (проверено на закоммиченном дереве)

go build ./...                               → exit 0
go vet ./...                                 → exit 0
go tool golangci-lint run                    → 0 issues
go tool go-arch-lint check --project-path .  → OK - No warnings found
go test -race ./channel/mattermost/ ./handlersfx/ ./auth/ ./deliveryfmt/
                 ./actors/command/...        → все ok, включая start и auth

Что сделано в этом проходе

1. Дефект двойного префикса — починен В КОДЕ, а не в БД (главное)

Прошлый фикс был прямым UPDATE в state.db, поэтому дефект вернулся. Теперь источник закрыт:

  • auth.MattermostSubject() идемпотентен — срезает уже имеющийся префикс mattermost: перед повторной квалификацией;
  • из actors/command/start/handler.go убран локальный TrimPrefix-костыль, ветка стала как у остальных транспортов: auth.MattermostSubject(trimmed).

Почему это ломало прод: canonicalSubject режет subject по первому :, а GetUserByBinding сравнивает точно. Значение mattermost:mattermost:<id> в principal не совпадает ни с чем → каждый пост Alex отбивался settlement_stage=unauthorized. Тест-регрессия: TestMattermostSubjectIsIdempotent (handlersfx/mattermost_ingress_test.go) + TestMattermostHandlerSendsChannelQualifiedPrincipalExactlyOnce.

2. Исправлено противоречие ProgressPolicy.Typing

Command-путь ставил Typing: true, тогда как inbound-путь — false, а SendTyping у MM-адаптера осознанный no-op (у ботов MM нет typing API). Мёртвая ветка + warn-шум на каждом ходу. Приведено к false.

3. Тесты транспорта — 6 новых файлов (~90 тестов)

Файл Покрытие
channel/mattermost/locator_codec_test.go локаторы, thread↔channel изоляция, LocatorFromAddressKey, scope, UserID
channel/mattermost/inbound_test.go NormalizeInbound, mention-фильтр, ParseCommand, whitelist команд, PostIDFromWebSocket
channel/mattermost/adapter_test.go все deliverycmd.Operation, plain-fallback только на content-rejection, draft-as-post, typing no-op без сети, root_id в треде
channel/mattermost/client_test.go ws/wss derivation, Bearer, APIError, isContentRejectedError, контекст
channel/mattermost/ingress_test.go 🔴 bad_seq-регрессия, монотонность и уникальность seq под 16 горутинами, фильтры, panic-recovery, семафор
handlersfx/mattermost_ingress_test.go публикация всех команд, одиночный префикс principal, /start до авторизации, отказ чужим, nil-safety

4. Доки — README.md, docs/balda.md, новый docs/mattermost.md

docs/mattermost.md — полный гайд: создание бота, минтинг токена (отдаётся ОДИН раз), membership в команде/канале, 5 ключей конфига, поведение в DM/канале/треде, troubleshooting (bad_seq, unauthorized, x509).

Уроки метода (дополнить balda-go-fx-pitfalls)

  1. Тест-ассерт — это гипотеза, а не истина. Дважды падал тест, и оба раза неверным был ассерт, а не код: (а) «тред и корневой пост = одна сессия» — на самом деле тред отдельная сессия от канала (проверено пробником: mm-c-a4aa02ef vs mm-t-89bbf64f, два разных ответа в треде дают ОДНУ сессию); (b) «NewIngress фолбэчит botUserID из клиента» — на самом деле onStart отказывается стартовать без bot_user_id. Прежде чем править код под падающий тест — проверить, чему код обязан соответствовать.
  2. goconst в тестах — повторяющиеся строковые литералы ("channel-1" ×15) валят линтер. Заводить константы (testChannelID и т.п.) сразу.
  3. dupword — сообщение "thread channel = %q, channel channel = %q" поймано линтером как повтор слова. Формулировать иначе.
  4. write_file + *** в доке — плейсхолдеры вида BALDA_MATTERMOST_TOKEN=*** в примерах конфига остаются на диске целыми; искажается только вывод чтения. Проверять awk 'NR==N', не глазами (см. hermes-secret-redaction-bypass).
  5. Артефакты деплоя — вон из PR. tools/mm-*.sh (9 скриптов) и tools/deltas-*.json (15 файлов) оставлены незакоммиченными: это ops-инструменты и метод правок, в апстрим-репозиторий им не место.

Что осталось

Ничего по коду. Дальше по желанию Alex:

  1. git push -u origin feat/mattermost-channel и открыть PR в baldaworks/balda.
  2. Фаза 3/4 (эксплуатация на Kraken) — personal/projects/balda/balda-kraken-mm-deploy.

⚠️ Незакоммиченные tools/mm-*.sh + tools/deltas-*.json — локальный инструментарий. Если они нужны в репо — отдельным коммитом с пометкой, но для PR в апстрим я бы их не отправлял.

Связанные заметки