[2026-09-26] eagle: family/how-to/truenas-infrastructure.md personal/plans/balda-mm-pr-plan.md personal/projects/balda/balda-mattermost-connector.md personal/projects/balda/balda-mm-delegation-plan.md personal/tech/balda-go-fx-pitfalls.md
This commit is contained in:
1 parent
036e7a7091
commit
1bf8320446
5 files changed
+318
-57
No files matched your search
@@ -115,6 +115,19 @@
|
||||
> - **✅ НЕАКТУАЛЬНО с 2026-09-14:** USB-адаптеры (CH340 ZONT/вентиляция) **физически перенесены на t610** → на TrueNAS узлов `/dev/ttyZONT` / `/dev/ttyVent` **нет вообще**, а сами контейнеры `mbusd`, `modbus-bridge`, `ser2net` **погашены** (`stop` + `--restart=no`). Проверка: `ls /dev/ttyUSB*` → пусто; `/sys/bus/usb/devices` содержит только принтер Samsung `04e8:3425` (**`lsusb` на TrueNAS не установлен** — использовать `/sys/bus/usb/devices`).
|
||||
> - **Актуальная гонка udev живёт на t610** — см. [[family/how-to/zont-modbus-bridge-udev-race-protection]].
|
||||
> - ⚠️ **Историческая справка (если когда-нибудь откатывать):** `restart: unless-stopped` НЕ перезапускает контейнер, упавший на `start` из-за отсутствующего device-узла (отказ до старта процесса, ExitCode 128/255, RestartCount=0); лечилось ручным `docker start modbus-bridge mbusd` после готовности симлинков.
|
||||
> **⚠️ ПОСЛЕДСТВИЕ, ПОДТВЕРЖДЁННОЕ 2026-09-26 (File Browser):** потеря `.ix-apps` = потеря **всех docker NAMED VOLUMES**, а не только образов. Образы = кеш, перекачаются; **тома = данные, не восстанавливаются**. Первый пострадавший — `filebrowser`: его БД пользователей жила в томах `filebrowser_filebrowser_db` / `filebrowser_filebrowser_config` → при первом старте тома создались с нуля (`2026-08-24T02:04:12`), File Browser сгенерировал нового `admin`, прежние пользователи (`file_admin` в т.ч.) утрачены.
|
||||
>
|
||||
> 🔴 **Правило для будущих переносов:** перед `zpool destroy`/пересозданием всегда выгружать **`/mnt/.ix-apps/docker/volumes/`** отдельным шагом — `rsync -aHAX /mnt/.ix-apps/docker/volumes/ /mnt/<TARGET>/ix-apps-volumes/`. Одного `/mnt/RED_2TB/*` НЕДОСТАТОЧНО: `.ix-apps` — **отдельный ZFS-датасет**, смонтированный поверх одноимённой папки, в глоб пула не попадает.
|
||||
>
|
||||
> 🔑 **Как быстро найти сервисы с томами** (они теряются при переносе, в отличие от bind-mount'ов):
|
||||
> ```bash
|
||||
> docker volume ls
|
||||
> for c in $(docker ps -a --format '{{.Names}}'); do
|
||||
> echo "== $c =="; docker inspect $c --format '{{json .Mounts}}' | jq -c '.[] | select(.Type=="volume") | {Name, Destination, Source}'
|
||||
> done
|
||||
> ```
|
||||
> **Долгосрочное лечение:** переводить критичные сервисы с named volumes на **bind-mount в `/mnt/RED_2TB/docker/<app>/`** — тогда данные попадают в обычный бэкап `mailru-crypt:` и переживают пересоздание пула. Кандидат №1 — File Browser (см. раздел «File Browser — детали», вариант B).
|
||||
|
||||
> **⚠️ ДРУГОЕ (открытое):** пул `DEST` (IronWolf) на 2026-08-24 `DEGRADED` — разобраться, почему (отвалился mirror-член). TimeMachine (~277G) не возвращён (бэкапы macOS, вероятно не нужен — решение Alex не подтверждено). SSH с Mac по `192.168.2.197` — подключение давало `Connection reset` / `kex_exchange_identification` (вероятен конфликт сессий при активном входе на консоль) — рабочий путь: `mallexxx.duckdns.org`.
|
||||
|
||||
> ## 🔒 ИСТОРИЯ: статус до восстановления (2026-08-24)
|
||||
@@ -207,7 +220,7 @@ TrueNAS использует **NFSv4 ACL**, а не стандартный POSIX
|
||||
| transmission | linuxserver/transmission:latest | 9091, 51413 | transmission.mallexxx.duckdns.org |
|
||||
| hermes-taiga | hermes-taiga:latest | — | — |
|
||||
| vless-proxy | teddysun/xray:latest | — | — |
|
||||
| filebrowser | filebrowser/filebrowser:latest | — | — |
|
||||
| filebrowser | filebrowser/filebrowser:latest | 8000 | (через Caddy `192.168.2.197:8000`) — см. раздел «File Browser» |
|
||||
| webdav | hacdias/webdav:latest | — | webdav.mallexxx.duckdns.org |
|
||||
| ~~homeassistant~~ ⛔ | home-assistant:stable | ~~8123~~ | **ПОГАШЕН 2026-09-14** — переехал на t610 |
|
||||
| immich-server | immich-app/immich-server:release | 2283 | immich.mallexxx.duckdns.org |
|
||||
@@ -384,6 +397,82 @@ nas_users:x:3000:root,truenas_admin,mallexxx,nas,transmission
|
||||
- **Web:** https://transmission.mallexxx.duckdns.org
|
||||
- **Порты:** 9091 (RPC/web), 51413 (TCP/UDP peers)
|
||||
|
||||
### File Browser — детали (разобрано 2026-09-26)
|
||||
|
||||
**Папка:** `/mnt/RED_2TB/docker/filebrowser/` (только `docker-compose.yml`).
|
||||
**Порт:** `8000:80` (хост `0.0.0.0:8000`). Проверка: `nc -z 127.0.0.1 8000`.
|
||||
**Образ:** `filebrowser/filebrowser:latest` → **v2.63.23** (проект заархивирован 2026-09-01, обновлений не будет).
|
||||
|
||||
```yaml
|
||||
services:
|
||||
filebrowser:
|
||||
image: filebrowser/filebrowser:latest
|
||||
container_name: filebrowser
|
||||
restart: unless-stopped
|
||||
user: "0:0" # ← root: обходит NFSv4 ACL, как и webdav
|
||||
ports:
|
||||
- "8000:80"
|
||||
volumes:
|
||||
- /mnt/RED_2TB/storage:/srv
|
||||
- /mnt/RED_2TB/Edu:/srv/Edu
|
||||
- filebrowser_db:/database # ← NAMED VOLUME, не bind-mount!
|
||||
- filebrowser_config:/config # ← NAMED VOLUME, не bind-mount!
|
||||
volumes:
|
||||
filebrowser_db:
|
||||
filebrowser_config:
|
||||
```
|
||||
|
||||
> 🔴 **ДАННЫЕ ЖИВУТ В DOCKER NAMED VOLUMES, А НЕ В ПАПКЕ `/mnt/RED_2TB/docker/filebrowser/`.**
|
||||
> В папке контейнера лежат только `docker-compose.yml` + `settings.json` (130 б, дата `Jul 27 20:00`).
|
||||
> Реальные данные:
|
||||
> ```
|
||||
> filebrowser_filebrowser_db → /mnt/.ix-apps/docker/volumes/filebrowser_filebrowser_db/_data/filebrowser.db
|
||||
> filebrowser_filebrowser_config → /mnt/.ix-apps/docker/volumes/filebrowser_filebrowser_config/_data/settings.json
|
||||
> ```
|
||||
> Физически это **внутри `.ix-apps`** (`DockerRootDir=/mnt/.ix-apps/docker`). Оба тома созданы
|
||||
> `2026-08-24T02:04:12` — то есть **с нуля**, в день пересоздания пула.
|
||||
|
||||
#### 🔴 Пифолл 1: логин не работает, потому что пользователя нет / `hideLoginButton: true`
|
||||
|
||||
**Симптом (2026-09-26):** «не могу залогиниться как `file_admin`».
|
||||
**Факт:** в БД **ровно один** пользователь — `"username":"admin"` (id=1, `perm.admin=true`). `file_admin` **никогда не создавался**.
|
||||
**Почему 403:** в настройках `"hideLoginButton": true` → эндпоинт `GET /api/login` отдаёт **403 Forbidden** (а не 401). Лог контейнера:
|
||||
```
|
||||
2026/09/26 08:44:02 /api/renew: 401 92.62.77.233 ← Кра́кен
|
||||
2026/09/26 08:44:17 /api/login: 403 92.62.77.233 ← попытка логина, отбита
|
||||
```
|
||||
Прочие настройки из БД: `authMethod: "json"`, `signup: false`, `minimumPasswordLength: 12`, `tokenExpirationTime: "2h"`.
|
||||
|
||||
> ⚠️ **«403 на логине» ≠ «контейнер сломан».** Контейнер `Up (healthy)`, HTTP 200 на `/`, порт слушает.
|
||||
|
||||
#### 🔴 Пифолл 2: БД залочена — `filebrowser users ls` даёт `Error: timeout`
|
||||
|
||||
Bolt-БД держит живой процесс. Любая CLI-команда по живой БД падает:
|
||||
```bash
|
||||
docker exec filebrowser filebrowser users ls -d /database/filebrowser.db
|
||||
# → Error: timeout
|
||||
```
|
||||
**Правка пользователей/паролей только при ОСТАНОВЛЕННОМ контейнере.** Порядок:
|
||||
`docker stop filebrowser` → правка/бэкап → `docker start filebrowser`.
|
||||
Читать содержимое живой БД можно без остановки через `strings`:
|
||||
```bash
|
||||
docker exec filebrowser sh -c "strings /database/filebrowser.db | grep -oE '\"username\":\"[^\"]*\"'"
|
||||
docker exec filebrowser sh -c "strings /database/filebrowser.db | grep -A2 'authMethod'"
|
||||
```
|
||||
|
||||
#### 🔴 Пифолл 3: `docker exec ... wget --header=...` → `bad address 'application'`
|
||||
|
||||
Busybox-`wget` внутри контейнера не переваривает `--header='Content-Type: application/json'` через вложенный ssh-квотинг (аргумент рвётся). Для API-проб использовать `printf` в файл + `wget --post-file` или просто проверять код через `wget -qS`.
|
||||
Настройки также читаются прямо из тома (root-only для хоста `truenas_admin`):
|
||||
```bash
|
||||
docker exec filebrowser cat /config/settings.json
|
||||
docker exec filebrowser cat /database/filebrowser.db # бинарь, читать strings
|
||||
```
|
||||
|
||||
**Состояние на 2026-09-26:** решено НЕ менять (ждёт решения Alex по вариантам A/B/C из отчёта). Данные `admin`-пользователя утрачены при переносе пула; `file_admin` отсутствует.
|
||||
|
||||
> ⚠️ **`/mnt/RED_2TB/docker.bak/filebrowser/` — это НЕ бэкап данных.** Там те же два файла (`docker-compose.yml` + `settings.json`, дата `Apr 29`), которые пережили перенос, потому что лежали на пуле. Томов там нет.
|
||||
|
||||
### Caddy — домены
|
||||
| Домен | → |
|
||||
|-------|---|
|
||||
|
||||
@@ -1,13 +1,93 @@
|
||||
# Balda — Mattermost connector: PR-подготовка (закрыто)
|
||||
|
||||
> Создан 2026-09-26. Обновлён 2026-09-26 (PR-проход, финал).
|
||||
> Статус: **🟡 код/тесты/доки/коммиты готовы — но осталось ОДНО решение по `tools/` в ветке**
|
||||
> (см. §«Открытое решение» ниже). После него — `git push` и PR.
|
||||
> Создан 2026-09-26. Обновлён 2026-09-26 (PR открыт).
|
||||
> Статус: **✅ PR ОТКРЫТ — baldaworks/balda#8, 8/8 CI PASS, MERGEABLE.**
|
||||
> https://github.com/baldaworks/balda/pull/8
|
||||
> Команда Alex: «Коммит текущего стейта и продолжай пока не стыдно будет открывать PR mattermost connector.
|
||||
> Со всеми поддерживаемыми фичами и тестами. Вперёд! Без вопросов и требующих апрува команд.»
|
||||
> Часть [[personal/projects/balda/balda-mm-delegation-plan]] (Фаза 2 → PR в апстрим).
|
||||
|
||||
## ✅ Итог: ветка PR-clean (2026-09-26, финал)
|
||||
## ✅ PR ОТКРЫТ — https://github.com/baldaworks/balda/pull/8 (2026-09-26)
|
||||
|
||||
**Статус: OPEN · MERGEABLE · все 8 CI-джобов PASS.**
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| PR | **baldaworks/balda#8** |
|
||||
| База | `baldaworks/balda:main` |
|
||||
| Голова | `mallexxx:feat/mattermost-channel` |
|
||||
| Объём | **41 файл, +5622 / −18** |
|
||||
| Коммитов | 7 |
|
||||
| Mergeable | ✅ MERGEABLE |
|
||||
|
||||
### 🔴 Целевой репозиторий — `baldaworks/balda`, не `normahq/balda`
|
||||
|
||||
Проверено через API, а не по названию remote'а:
|
||||
```
|
||||
gh repo view mallexxx/balda --json parent
|
||||
→ parent: baldaworks/balda ← форк от него
|
||||
gh repo view normahq/balda --json owner
|
||||
→ owner.id: O_kgDOEgAHrw (= baldaworks) ← редирект, не отдельный репо
|
||||
```
|
||||
`origin` = `mallexxx/balda` (форк), `upstream` = `normahq/balda` (редирект на baldaworks).
|
||||
**PR создавать в `baldaworks/balda`**, head указывать как `mallexxx:<branch>`
|
||||
(не полный URL форка — иначе `gh` путается).
|
||||
|
||||
### База ветки — идеальная
|
||||
|
||||
`git rev-list --left-right --count upstream/main...HEAD` → `0 7` (0 позади, 7 впереди).
|
||||
`merge-base HEAD upstream/main` == `upstream/main` == `de273d8f`. Rebase не потребовался.
|
||||
|
||||
### CI — 8/8 PASS (прогон на чистом раннере)
|
||||
|
||||
```
|
||||
architecture-lint pass 2m2s
|
||||
ingress-e2e pass 30s
|
||||
jetstream-integration pass 1m0s
|
||||
lint pass 2m46s
|
||||
postgres-integration pass 57s
|
||||
projection-replay pass 26s
|
||||
sqlite-integration pass 1m15s
|
||||
test pass 6m0s ← главный: полный go test на чистом раннере
|
||||
```
|
||||
|
||||
📌 **Это и есть настоящая приёмка сборки.** Локально `cmd/balda` падал на
|
||||
`TestInitCommand_NonInteractiveAutoSelectsRootAndGeneratesDetectedAgents` — в CI он
|
||||
**прошёл**, то есть падение было особенностью моей локальной среды, а не дефектом.
|
||||
CI на чистом раннере закрывает ровно тот класс проблем, который локальные гейты не видят.
|
||||
|
||||
⚠️ **CI-пайплайн в репо ЕСТЬ** (`architecture-lint`, `lint`, `test`, `ingress-e2e`,
|
||||
`jetstream-integration`, `postgres-integration`, `sqlite-integration`, `projection-replay`).
|
||||
Значит локальные гейты — необходимое, но не достаточное условие; ждать CI обязательно.
|
||||
|
||||
### Команды (воспроизводимо)
|
||||
|
||||
```bash
|
||||
cd ~/Developer/balda
|
||||
git fetch upstream --quiet
|
||||
git rev-list --left-right --count upstream/main...HEAD # 0 7
|
||||
git push -u origin feat/mattermost-channel
|
||||
|
||||
gh pr create --repo baldaworks/balda --base main \
|
||||
--head mallexxx:feat/mattermost-channel \
|
||||
--title "feat(mattermost): add Mattermost channel transport" \
|
||||
--body-file /tmp/mm-pr-body.md
|
||||
|
||||
gh pr view 8 --repo baldaworks/balda --json state,mergeable,changedFiles,additions
|
||||
gh pr checks 8 --repo baldaworks/balda
|
||||
```
|
||||
|
||||
### Что осталось
|
||||
|
||||
1. **Ревью апстрима** — ждать. Правки по замечаниям делать в этой же ветке (push обновит PR).
|
||||
2. **Боевая проверка на Kraken** — PR-merge ≠ работает на стенде. Пересобрать образ из
|
||||
`9f1e6c9c`, задеплоить, `@balda` → ответ в ленте канала (см.
|
||||
[[personal/projects/balda/balda-kraken-mm-deploy]]).
|
||||
3. Фаза 4 (исполнитель) — [[personal/projects/balda/balda-mm-delegation-plan]].
|
||||
|
||||
---
|
||||
|
||||
## ✅ Итог: ветка PR-clean (2026-09-26, до пуша)
|
||||
|
||||
**7 коммитов**, рабочее дерево **чистое**, `tools/` **исключён** из ветки.
|
||||
|
||||
@@ -194,18 +274,24 @@ tools/deltas-mattermost.json
|
||||
tools/deltas-mattermost-2.json … -13.json (12 файлов)
|
||||
```
|
||||
|
||||
**Что нужно сделать — по выбору Alex:**
|
||||
**✅ РЕШЕНО (2026-09-26):** выбран вариант (a), выполнен по команде Alex «Добавь в ignored».
|
||||
Коммит `9f1e6c9c chore: ignore local project-editing tooling`.
|
||||
|
||||
| Вариант | Команда | Последствие |
|
||||
|---|---|---|
|
||||
| **(a) рекомендую** | `git rm -r --cached tools/` + коммит | файлы остаются на диске **untracked**, локальный инструментарий работает, ветка чистая |
|
||||
| (b) оставить | — | PR содержит 16 лишних файлов, ревьюер спросит |
|
||||
| (c) отдельная ветка | — | tooling живёт отдельно от PR |
|
||||
```bash
|
||||
echo '/tools/' >> .gitignore # + комментарий, что это локальный инструментарий
|
||||
git rm -r --cached tools/ # 16 файлов ушли из индекса, ОСТАЛИСЬ на диске
|
||||
git add .gitignore && git commit # → 9f1e6c9c
|
||||
```
|
||||
|
||||
⚠️ **Попытка (a) в этой сессии НЕ выполнена.** `git rm -r --cached tools/` ушла на
|
||||
апрув и **истекла по таймауту** — команда не применилась, состояние дерева целое
|
||||
(подтверждено `git status --short`: все файлы на месте). Повторять без команды Alex
|
||||
не стал: удаление из индекса — операция, требующая подтверждения.
|
||||
Результат: `git diff --stat upstream/main...HEAD -- tools/` → **пусто**;
|
||||
в PR-diff **41 файл**, все — файлы проекта. `tools/` на диске цел (**39 файлов**),
|
||||
`git status --short` чист.
|
||||
|
||||
⚠️ **`git rm -r --cached tools/` уходит на апрув** (рекурсивное удаление). Первая попытка
|
||||
истекла по таймауту и **не применилась** — состояние было целое. Проверять
|
||||
`git diff --cached --name-only` перед повтором.
|
||||
🔴 **`gitignore` НЕ отвязывает уже отслеживаемые файлы** — без `git rm --cached` они
|
||||
останутся в PR навсегда. Нужны оба шага, в этом порядке.
|
||||
|
||||
📌 **Правило на будущее:** проверять состав PR через
|
||||
`git diff --stat upstream/main...HEAD` **перед** объявлением готовности, а не только
|
||||
@@ -214,15 +300,29 @@ tools/deltas-mattermost-2.json … -13.json (12 файлов)
|
||||
|
||||
## Что осталось
|
||||
|
||||
**Ничего по коду.** Дальше по желанию Alex:
|
||||
**По PR — ничего, кроме ревью.** Всё выполнено:
|
||||
|
||||
0. 🔴 **Убрать `tools/` из ветки** — вариант (a) выше. Блокирует «стыдный» PR.
|
||||
1. `git push -u origin feat/mattermost-channel` и открыть PR в `baldaworks/balda`.
|
||||
2. Фаза 3/4 (эксплуатация на Kraken) — [[personal/projects/balda/balda-kraken-mm-deploy]].
|
||||
| Шаг | Статус |
|
||||
|---|---|
|
||||
| `tools/` убран из ветки, `/tools/` в `.gitignore` | ✅ коммит `9f1e6c9c` |
|
||||
| `git push -u origin feat/mattermost-channel` | ✅ запушено |
|
||||
| PR в `baldaworks/balda` открыт | ✅ **#8**, 41 файл, +5622/−18 |
|
||||
| CI | ✅ **8/8 PASS** |
|
||||
| Локальные гейты (build/vet/lint/arch-lint/no-race) | ✅ все зелёные |
|
||||
|
||||
⚠️ Скрипты `tools/mm-*.sh` (9 шт.) и дельты `tools/deltas-mattermost-14…26` +
|
||||
`deltas-goal-command-fix.json` + `deltas-mm-prefixfix.json` — **untracked, локальный
|
||||
инструментарий**. Для PR в апстрим не отправлять. Существенное продублировано в
|
||||
**Осталось (по желанию Alex):**
|
||||
|
||||
1. **Ревью апстрима** — ждать. Правки по замечаниям делать **в эту же ветку**:
|
||||
push обновит PR автоматически.
|
||||
2. 🔴 **Боевая проверка на Kraken — НЕ сделана.** PR-merge ≠ «бот работает на стенде».
|
||||
Нужно: пересобрать образ из `9f1e6c9c`, задеплоить, `@balda` → ответ в ленте канала.
|
||||
См. [[personal/projects/balda/balda-kraken-mm-deploy]].
|
||||
3. **Замержить PR** (после ревью) — тогда Фаза 2 закрывается официально.
|
||||
|
||||
⚠️ Скрипты `tools/mm-*.sh` (9 шт.), дельты `tools/deltas-mattermost-14…26` +
|
||||
`deltas-goal-command-fix.json` + `deltas-mm-prefixfix.json`, `apply-project-deltas.py`,
|
||||
`run-project-deltas.sh`, `.deltas-state.json` — **untracked, локальный инструментарий**,
|
||||
git-ignored. Существенное продублировано в
|
||||
[[personal/projects/balda/balda-kraken-mm-deploy]] и [[personal/tech/balda-go-fx-pitfalls]].
|
||||
|
||||
## Связанные заметки
|
||||
|
||||
@@ -1,30 +1,25 @@
|
||||
# Balda — Mattermost коннектор (архитектура)
|
||||
|
||||
> Создано 2026-09-26. Обновлено 2026-09-26 (сессия PR-подготовки, завершена).
|
||||
> Статус: **🟡 КОД ГОТОВ К PR — 6 коммитов, все гейты зелёные. Осталось одно решение: `tools/` в ветке.**
|
||||
> 🟢 **Сессия PR-подготовки завершена:** починены 2 дефекта **в коде** (идемпотентный
|
||||
> `MattermostSubject`; `ProgressPolicy.Typing`), написаны 6 файлов тестов (~90 тестов)
|
||||
> на транспорт + хендлер, обновлены README / `docs/balda.md` и создан `docs/mattermost.md`.
|
||||
> `golangci-lint` = 0 issues, `go-arch-lint` = OK.
|
||||
> 🔴 **Блокер PR:** в ветке 16 файлов `tools/` из базового коммита `004fda2f` — в апстриме
|
||||
> такого каталога нет. Нужно `git rm -r --cached tools/` по команде Alex (заблокировано
|
||||
> истёкшим апрувом). Детали, коммиты и варианты — [[personal/plans/balda-mm-pr-plan]].
|
||||
> Создано 2026-09-26. Обновлено 2026-09-26 (PR открыт).
|
||||
> Статус: **✅ PR ОТКРЫТ — baldaworks/balda#8, 8/8 CI PASS, MERGEABLE.**
|
||||
> 🟢 **PR:** https://github.com/baldaworks/balda/pull/8 — 41 файл, +5622/−18, 7 коммитов.
|
||||
> Фаза 2 закрыта полностью: код, 103 новых теста, доки, зелёный CI.
|
||||
> Блокер `tools/` снят: `/tools/` в `.gitignore` + `git rm -r --cached tools/`.
|
||||
> Детали — [[personal/plans/balda-mm-pr-plan]].
|
||||
> Часть проекта [[personal/projects/balda/balda-mm-delegation-plan]] (Фаза 2).
|
||||
> Требование Alex: поддержка **всех** функций Балды, по новым API, production-качество.
|
||||
>
|
||||
> **Проверено (2026-09-26, финал):**
|
||||
> - `go build ./...` → exit 0, `go vet ./...` → exit 0
|
||||
> **Проверено (2026-09-26, PR):**
|
||||
> - `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**
|
||||
> - **DI-граф собирается целиком** с `balda.mattermost.enabled=true` — проверено реальным
|
||||
> - **DI-граф собирается целиком** с `balda.mattermost.enabled=true` — проверено
|
||||
> `validateBaldaApplication(prepared)` через fx, а не только компиляцией
|
||||
> - 3 новых теста зелёные (см. §«Тесты»)
|
||||
> - Закоммичено: `004fda2f feat(mattermost): add Mattermost transport adapter` (40 файлов, +3072)
|
||||
> - **103 новых теста** зелёные, включая `-race`; в CI — 126 PASS, 0 FAIL, 0 SKIP
|
||||
> - **CI: 8/8 джобов PASS** на чистом раннере (`.github/workflows`)
|
||||
>
|
||||
> **Осталось:** ничего по коду. Дальше — Фаза 3 (Балда с MM на Kraken) и Фаза 4 (исполнитель).
|
||||
>
|
||||
> 🔴 **ОБНОВЛЕНО 2026-09-26 (ночь, позже): «все quality gates пройдены» оказалось неполным.**
|
||||
> При первом **живом запуске** на Kraken (Фаза 3) Балда ушла в crash-loop:
|
||||
> 🔴 **Исторический урок (Фаза 3):** «все quality gates пройдены» оказалось неполным —
|
||||
> при первом **живом запуске** на Kraken Балда ушла в crash-loop:
|
||||
> `advertised commands have no actor handler: goal`. В `Advertisement.Names` была объявлена
|
||||
> несуществующая команда `goal` (это payload kind, а не имя хендлера; цикл называется
|
||||
> `goalkeeper`). **Ни `go build`, ни `go vet`, ни `golangci-lint`, ни `go-arch-lint`, ни
|
||||
@@ -32,13 +27,23 @@
|
||||
> `inbound.go` дельтой `tools/deltas-goal-command-fix.json`. Разбор —
|
||||
> [[personal/tech/balda-go-fx-pitfalls]] §«Дефект 4».
|
||||
> 📌 Вывод: «Фаза 2 закрыта» означала «код компилируется и граф собирается», но **не**
|
||||
> «транспорт работает». Живой запуск обязателен. Текущий статус Фазы 3 —
|
||||
> «транспорт работает». Живой запуск обязателен. Статус Фазы 3 —
|
||||
> [[personal/projects/balda/balda-kraken-mm-deploy]].
|
||||
>
|
||||
## ✅ PR-ПРОХОД 2026-09-26 — транспорт приведён к PR-качеству
|
||||
|
||||
Ветка `feat/mattermost-channel`, **6 коммитов**, готово к `git push` и PR.
|
||||
Подробности — [[personal/plans/balda-mm-pr-plan]].
|
||||
Ветка `feat/mattermost-channel`, **7 коммитов**, PR **открыт** — baldaworks/balda#8.
|
||||
Подробности и полный список — [[personal/plans/balda-mm-pr-plan]].
|
||||
|
||||
```
|
||||
9f1e6c9c chore: ignore local project-editing tooling ← уборка tools/ из 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 ← база прошлой сессии
|
||||
```
|
||||
|
||||
**Исправлено в коде (не в данных):**
|
||||
|
||||
@@ -47,12 +52,13 @@
|
||||
| 🔴 Двойной префикс `principal` — прошлый фикс был в БД и вернулся | `auth.MattermostSubject()` теперь **идемпотентен** (срезает `mattermost:` перед повторной квалификацией); из `handler.go` убран `TrimPrefix`-костыль |
|
||||
| `ProgressPolicy.Typing: true` в command-пути | Приведено к `false` — у ботов MM нет typing API, `SendTyping` осознанный no-op |
|
||||
|
||||
**Тесты — 6 новых файлов, ~90 тестов:** `locator_codec_test.go`, `inbound_test.go`,
|
||||
`adapter_test.go`, `client_test.go`, `ingress_test.go` (в пакете транспорта) +
|
||||
`handlersfx/mattermost_ingress_test.go`. Ключевые регрессионные guard'ы:
|
||||
**Тесты — 6 новых файлов, 103 теста:** `locator_codec_test.go` (15), `inbound_test.go` (18),
|
||||
`adapter_test.go` (17), `client_test.go` (13), `ingress_test.go` (23) +
|
||||
`handlersfx/mattermost_ingress_test.go` (17). Ключевые регрессионные guard'ы:
|
||||
`writeEvent` всегда с `seq` и уникальный `seq` под 16 горутинами (`bad_seq`),
|
||||
plain-fallback только на content-rejection (не на 5xx), идемпотентность subject'а,
|
||||
тред = одна сессия ≠ канальной, `/start` доступен до авторизации.
|
||||
Пакеты `mattermost` + `handlersfx` в verbose-прогоне: **126 PASS, 0 FAIL, 0 SKIP**.
|
||||
|
||||
**Доки:** README + `docs/balda.md` + новый **`docs/mattermost.md`** (создание бота,
|
||||
минтинг токена, membership, 5 ключей, поведение, troubleshooting).
|
||||
@@ -65,11 +71,13 @@ go tool golangci-lint run → 0 issues
|
||||
go tool go-arch-lint check --project-path . → OK - No warnings found
|
||||
go test -race (затронутые пакеты) → все ok
|
||||
```
|
||||
⚠️ 5 пакетов падают (`cmd/balda`, `apps/balda`, `mcpruntime`, `session`, `state`) —
|
||||
⚠️ 5 пакетов падают локально (`cmd/balda`, `apps/balda`, `mcpruntime`, `session`, `state`) —
|
||||
**это апстримная база**, проверено `git stash` (те же 4 теста падают без правок).
|
||||
🔴 **В CI эти же тесты ПРОШЛИ** — локальное падение было особенностью машины, не дефектом.
|
||||
|
||||
⚠️ `tools/mm-*.sh` + `tools/deltas-*.json` оставлены **незакоммиченными** — локальный
|
||||
инструментарий, в PR не идёт.
|
||||
**`tools/` вычищен из ветки:** `/tools/` в `.gitignore` + `git rm -r --cached tools/`
|
||||
(коммит `9f1e6c9c`). Файлы на диске целы (39 шт.), в PR-diff их нет.
|
||||
⚠️ `gitignore` **не отвязывает** уже отслеживаемые файлы — нужны оба шага.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# Balda 2.0 — Mattermost + распределённое делегирование (план)
|
||||
|
||||
> Создан 2026-09-25. Статус: **Фазы 1-3 закрыты 2026-09-26** (MM на Kraken · MM-адаптер
|
||||
> в коде · оркестратор развёрнут, **бот отвечает в MM**). Следующая — Фаза 4 (исполнитель).
|
||||
> в коде · оркестратор развёрнут, **бот отвечает в MM**). Фаза 2 выведена на **PR
|
||||
> `baldaworks/balda#8`** — 8/8 CI PASS, ждёт ревью. Следующая — Фаза 4 (исполнитель).
|
||||
> Alex дал команду исполнять без вопросов.
|
||||
> Задача: поднять свежую Балду из `baldaworks/balda` (без наших коммитов), завязать на Mattermost,
|
||||
> построить распределённое делегирование (дешёвый оркестратор + подписочные CLI в VM).
|
||||
@@ -203,8 +204,9 @@ Mattermost (Alex) — итог + артефакты
|
||||
туннель `{"status":"OK"}`. ⏳ Осталась приёмка входом в браузере (делает Alex).
|
||||
→ [[personal/projects/balda/mattermost-kraken-deploy]]
|
||||
|
||||
### Фаза 2 — адаптер Mattermost в Балде — ✅ ЗАКРЫТА (все quality gates пройдены)
|
||||
### Фаза 2 — адаптер Mattermost в Балде — ✅ PR ОТКРЫТ: baldaworks/balda#8
|
||||
Детальный док: [[personal/projects/balda/balda-mattermost-connector]].
|
||||
PR-план и команды: [[personal/plans/balda-mm-pr-plan]].
|
||||
|
||||
1. ✅ Ветка **`feat/mattermost-channel`** от чистого `upstream/main` (`de273d8f`).
|
||||
2. ✅ Изучен `channel/zulip/*` целиком как образец.
|
||||
@@ -221,12 +223,26 @@ Mattermost (Alex) — итог + артефакты
|
||||
8. ✅ **DI-граф проверен реальным `validateBaldaApplication`** с `mattermost.enabled=true` —
|
||||
найдены и починены 3 дефекта (`fx.In` + `fx.ParamTags`, отсутствующие провайдеры строк,
|
||||
отсутствующий импорт).
|
||||
9. ✅ 3 новых теста зелёные (env-override + fx-граф + маршрут `TestBuiltinRoutes`).
|
||||
10. ✅ **`golangci-lint` = 0 issues, `go-arch-lint` = OK**, `go build`/`go vet` = exit 0.
|
||||
11. ✅ **Закоммичено:** `004fda2f feat(mattermost): add Mattermost transport adapter` (40 файлов, +3072).
|
||||
9. ✅ **`golangci-lint` = 0 issues, `go-arch-lint` = OK**, `go build`/`go vet` = exit 0.
|
||||
10. ✅ **Закоммичено:** `004fda2f feat(mattermost): add Mattermost transport adapter` (40 файлов, +3072).
|
||||
11. ✅ **PR-проход (2026-09-26):** починены 2 дефекта в коде (идемпотентный
|
||||
`MattermostSubject` — из-за него бот не отвечал владельцу; `ProgressPolicy.Typing`),
|
||||
написаны **103 новых теста** в 6 файлах, доки README/`docs/balda.md`/`docs/mattermost.md`.
|
||||
12. ✅ **`tools/` вычищен из ветки** — `/tools/` в `.gitignore` + `git rm -r --cached tools/`
|
||||
(коммит `9f1e6c9c`); файлы на диске целы, в PR-diff их нет.
|
||||
13. ✅ **PR ОТКРЫТ: `baldaworks/balda#8`**, 41 файл, +5622/−18, 7 коммитов.
|
||||
14. ✅ **CI: 8/8 PASS** на чистом раннере (architecture-lint, lint, test, ingress-e2e,
|
||||
jetstream-integration, postgres-integration, sqlite-integration, projection-replay).
|
||||
|
||||
**Фаза 2 закрыта на уровне кода.** Все quality gates из `AGENTS.md` пройдены.
|
||||
Дальше — Фаза 3 (развернуть Балду с MM-адаптером на Kraken) и Фаза 4 (исполнитель в Docker на Mac).
|
||||
**Фаза 2 закрыта на уровне кода и PR.** Осталось: **ревью апстрима + merge**.
|
||||
|
||||
📌 **Целевой репозиторий — `baldaworks/balda`.** `origin` = `mallexxx/balda` (форк, родитель
|
||||
baldaworks), `upstream` = `normahq/balda` = **редирект** на baldaworks (тот же org id).
|
||||
PR: `gh pr create --repo baldaworks/balda --base main --head mallexxx:feat/mattermost-channel`.
|
||||
|
||||
🔴 **Урок PR-прохода:** локальные гейты — необходимое, но **не достаточное** условие. Локально
|
||||
`cmd/balda` падал на `TestInitCommand_...GeneratesDetectedAgents`, **в CI тот же тест прошёл** —
|
||||
падение было особенностью машины. В репо есть CI (8 джобов) — **дожидаться его** перед «готово».
|
||||
|
||||
#### Дефекты, найденные на этапе закрытия (важно для будущих транспортов)
|
||||
|
||||
@@ -238,11 +254,14 @@ Mattermost (Alex) — итог + артефакты
|
||||
| 4 | `TestBuiltinRoutes` ждал 4 маршрута | `len(BuiltinRoutes()) = 5, want 4` | добавить маршрут Mattermost в `want` |
|
||||
| 5 | Мёртвый typing-throttle (`shouldSendTyping`, поля, mutex, `SetTypingThrottleInterval`) | `unused` ×2, затем каскад `undefined` | удалён целиком — `SendTyping` всегда no-op |
|
||||
| 6 | Обёртка `func(client, logger) *Adapter` без тела | `unlambda` (gocritic) | заменена на `mattermost.NewAdapter` |
|
||||
| 7 | 🔴 **Двойной префикс `principal`** (`mattermost:mattermost:<id>`) | каждый пост владельца → `settlement_stage=unauthorized`, бот молчит | `MattermostSubject()` сделана **идемпотентной** (срезает префикс) — дефект был «починен» в БД и вернулся |
|
||||
| 8 | `ProgressPolicy.Typing: true` в command-пути, `false` в inbound | мёртвая ветка + warn-шум | приведено к `false` — у ботов MM нет typing API |
|
||||
|
||||
⚠️ **Метод проверки, который окупился:** `go build` ловит только компиляцию. **Реальный DI-граф
|
||||
валидируется только `validateBaldaApplication` через fx** — именно этот тест нашёл дефекты 1-2,
|
||||
которых `build`/`vet` не видят. Для любого нового транспорта писать такой тест сразу.
|
||||
|
||||
🔴 **Дефект из данных — чинить в коде, а не в БД:** дефект 7 «починили» UPDATE'ом и он вернулся
|
||||
при следующей записи.
|
||||
|
||||
🔴 **Урок Фазы 2:** `go build` = exit 0 **не значит** «транспорт рабочий». fx-несовместимости
|
||||
и отсутствующие провайдеры видны только при `fx.ValidateApp`/`validateBaldaApplication`.
|
||||
|
||||
@@ -1223,6 +1223,51 @@ git rm -r --cached tools/ # 🔴 файлы ОСТАЮТСЯ на диске
|
||||
⚠️ Артефакты деплоя (`mm-*.sh` ops-скрипты) в PR не шлём — только код транспорта,
|
||||
wiring, тесты, доки.
|
||||
|
||||
## 🔴 Целевой репозиторий определять через API, не по имени remote'а
|
||||
|
||||
Два remote'а выглядели так: `origin` = `mallexxx/balda` (форк), `upstream` = `normahq/balda`.
|
||||
Но **реальный родитель форка — `baldaworks/balda`**, а `normahq/balda` — просто редирект:
|
||||
|
||||
```bash
|
||||
gh repo view mallexxx/balda --json parent
|
||||
# → parent: baldaworks/balda
|
||||
|
||||
gh repo view normahq/balda --json owner
|
||||
# → owner.id: O_kgDOEgAHrw ← тот же org, что у baldaworks/balda = редирект, не отдельный репо
|
||||
```
|
||||
|
||||
📌 Создавать PR в **`baldaworks/balda`**, а `--head` указывать как `mallexxx:<branch>`
|
||||
(«владелец:ветка»). Полный URL форка в `--head` ломает `gh`.
|
||||
|
||||
```bash
|
||||
gh pr create --repo baldaworks/balda --base main \
|
||||
--head mallexxx:feat/mattermost-channel \
|
||||
--title "…" --body-file /tmp/pr-body.md
|
||||
```
|
||||
|
||||
⚠️ **Проверять базу перед пушем:** `git rev-list --left-right --count upstream/main...HEAD`
|
||||
→ `0 7` значит «0 позади, 7 впереди» — идеальная база, rebase не нужен.
|
||||
|
||||
## 🔴 CI на чистом раннере — это НАСТОЯЩАЯ приёмка сборки (шире локальных гейтов)
|
||||
|
||||
Локально `cmd/balda` падал на
|
||||
`TestInitCommand_NonInteractiveAutoSelectsRootAndGeneratesDetectedAgents`.
|
||||
В CI (чистый раннер, свой образ) **тот же тест прошёл**.
|
||||
|
||||
Локальные гейты (`build`/`vet`/`golangci-lint`/`go-arch-lint`/`go test`) — **необходимое,
|
||||
но не достаточное** условие. Они видят состояние **моей** машины: остатки кэшей, локальные
|
||||
конфиги, переменные окружения, версии инструментов. CI видит чистое дерево.
|
||||
|
||||
**Пайплайн в `baldaworks/balda` (8 джобов):**
|
||||
`architecture-lint`, `lint`, `test`, `ingress-e2e`, `jetstream-integration`,
|
||||
`postgres-integration`, `sqlite-integration`, `projection-replay`.
|
||||
|
||||
📌 **Порядок:** локальные гейты → push → **дождаться CI** → только потом говорить
|
||||
«готово». Не объявлять готовность по локальным гейтам, если в репо есть CI.
|
||||
|
||||
⚠️ Локальный фейл, которого нет в CI, — **не повод чинить код**: сначала проверить, не
|
||||
особенность ли это локальной среды (`git stash` + повтор, или прогон в контейнере).
|
||||
|
||||
## Связанные заметки
|
||||
|
||||
- [[personal/projects/balda/balda-mattermost-connector]] — Фаза 2, где всё это найдено
|
||||
|
||||
Reference in new issue
Block a user