15 KiB
Создан 2026-09-28. Статус: 📋 ПЛАН, ЖДЁТ ОДОБРЕНИЯ ALEX. Цель: собрать локально runtime (PR4+PR5 влиты) + balda (ревью PR #8), задеплоить на Kraken, прогнать проверку тулинга и Mattermost. Связано: personal/projects/balda/balda-kraken-mm-deploy, personal/plans/balda-mm-pr8-review-fixes, personal/plans/runtime-pr5-toolset-dedup-review-fixes.
0. ФАКТЫ, проверенные сейчас (не предположения)
| Факт | Значение |
|---|---|
normahq/runtime PR #4 |
MERGED 2026-09-28T13:21:59Z, head 22f7f17 |
normahq/runtime PR #5 |
MERGED 2026-09-28T13:22:13Z, head facb0d0 |
upstream/main (runtime) |
c41939f; содержит DedupKey (6 вхождений) и openAIToolsFromConfig (2) |
baldaworks/balda PR #8 |
OPEN, head e0162009, review CHANGES_REQUESTED (2026-09-28T13:54Z) |
Локальный ~/Developer/balda |
06b2b8d0 — на 4 коммита позади origin/feat/mattermost-channel |
~/Developer/balda/runtime-local |
HEAD 06b2b8d0 — это клон репо balda, не runtime (!) |
🔴 Проблема №1 (блокирующая): runtime-local — фикция
~/Developer/balda/runtime-local — не отдельный чекаут runtime, а вложенный git-клон
mallexxx/balda (HEAD = balda-коммит 06b2b8d0). В нём:
openai.goот PR #4 вписан руками (openAIToolsFromConfig— 3 вхождения);DedupKey— 0 вхождений, т.е. PR #5 отсутствует.
Каталог git-ignored в balda (git ls-files runtime-local → 0 файлов) и подключён через
replace github.com/normahq/runtime/v2 => ./runtime-local. В доке
personal/plans/runtime-pr5-toolset-dedup-review-fixes §5 это отмечено как отдельная задача.
⚠️ Мои правки Balda-слоя из PR #5 (DedupKey в internalmcp/manager.go и sessionapp/module.go)
в локальном дереве есть (M-статус), но не компилируются против этой копии.
🔴 Проблема №2 (из ревью PR #8): остались 3 блокера
Последнее ревью (13:54) подтверждает: canonical chat ingress, command registry, scope
classifiers, обязательный InboundProcessor — исправлены. Осталось надёжность WS-ingress:
| # | Файл:строка | Суть |
|---|---|---|
| P1 | channel/mattermost/ingress.go:389 |
При заполнении локального semaphore событие теряется безвозвратно: MM не получает ack/nack от клиента и не повторит posted. Нужен backpressure на read loop или durable bounded queue с повтором по post.ID |
| P1 | ingress.go:483 |
InboundRetry и err только логируются → post считается потерянным. Нужен bounded retry/durable handoff с dedupe по post.ID; terminal settlement завершать без повтора. Ошибки HandleCommand выше тоже игнорируются |
| P2 | ingress.go:164 |
Сначала остановить producer, потом processWG.Wait(). Сейчас read loop может дойти до processWG.Add(1) после начала waitForProcessing → Stop завершается, не дождавшись воркера. Также нарушение контракта sync.WaitGroup |
1. План — Часть A: runtime-local → чистый upstream
Идея: replace на локальный форк больше не нужен — PR #4 и #5 влиты в апстрим.
Значит копию можно заменить на настоящий upstream без потери функционала.
| Шаг | Действие | Обоснование |
|---|---|---|
| A1 | Зафиксировать текущее состояние: git -C ~/Developer/balda/runtime-local rev-parse HEAD, бэкап каталога в ~/Developer/balda/runtime-local.bak-20260928 |
Правило: бэкап ДО изменения |
| A2 | Заменить runtime-local на чекаут normahq/runtime @ c41939f (или тега, если есть релиз после merge) |
Убирает форк-коппию, снимает вечное расхождение |
| A3 | Убрать replace github.com/normahq/runtime/v2 => ./runtime-local из go.mod, поднять require до версии с PR4+PR5 |
Штатный путь; форк больше не нужен |
| A4 | Если тега после merge нет — оставить replace на чистый upstream, а не на клон balda |
Минимальное изменение, если апстрим ещё не тегирован |
| A5 | Обновить комментарий в go.mod (сейчас ссылается на PR #4 как на открытый) |
Док не должен врать |
⚠️ Развилка A3/A4 требует решения Alex — см. §3.
Альтернатива (если править runtime у себя не хочется): оставить replace, но заменить
содержимое runtime-local на актуальный upstream-чекаут. Тогда Balda-код из PR #5 наконец
скомпилируется.
2. План — Часть B: подтянуть Balda + закрыть 3 блокера PR #8
B0. Синхронизация ветки
git fetch + git merge --no-rebase origin/feat/mattermost-channel (правило AGENTS.md:
синхронизировать merge'ем, не rebase). Проверить, что мои незакоммиченные правки
(internalmcp/manager.go, sessionapp/module.go, sessionmemorymcp/broker.go — это PR #5-слой)
не конфликтуют. 🔴 Решить: коммитить их сейчас или они уже не нужны (если DedupKey
приезжает из апстрима — правки Balda-слоя всё равно нужны, чтобы включить дедуп).
B1. P1 — не терять событие при заполнении semaphore (ingress.go:389)
Сейчас: acquireSlot() не смог → лог → post потерян.
Направление: backpressure на read loop — блокирующее взятие слота до чтения следующего
кадра (MM не шлёт ack, повтора не будет). Плюс/или bounded queue с повтором по post.ID.
🔴 Выбор между «блокировать read loop» и «durable queue» — решение Alex (§3): блокировка
проще, но читающий цикл встаёт; очередь честнее, но требует dedupe и хранилища.
B2. P1 — settlement + retry для retryable failure (ingress.go:483)
Направление: различать terminal и retryable settlement; retryable — bounded retry с dedupe по
post.ID; terminal завершать без повтора. Ошибки HandleCommand перестать игнорировать.
B3. P2 — порядок shutdown (ingress.go:164)
Направление: отменить/закрыть producer → дождаться done (новые Add невозможны) →
и только затем processWG.Wait() для drain уже принятых.
B4. Гейты Balda
go build ./...
go vet ./...
go test -race ./...
go tool golangci-lint run ./...
go tool go-arch-lint check --project-path .
B5. 📌 Проверить гипотезу ревьюера фактом, а не на слово
Ревьюер сам пишет: «The first issue needs a real Mattermost integration check because the
current command test injects a synthetic posted frame». Проверка воспроизводимости —
на Kraken живым постом (§C).
3. ⛔ Требует решения Alex (до начала работ)
- A3 vs A4: убрать
replaceсовсем (поднять версию runtime) или заменитьruntime-localна чистый upstream-чекаут и оставитьreplace? - B1: backpressure (блокировать read loop) или durable bounded queue с dedupe?
- Порядок: сначала закрыть 3 блокера PR #8, потом собирать/деплоить? Или собрать сейчас (валидация тулинга + MM уже возможна) и блокеры закрыть следом?
4. План — Часть C: сборка и деплой на Kraken
Проверенный порядок (из personal/projects/balda/balda-kraken-mm-deploy):
cd ~/Developer/balda
docker buildx build --builder arm64builder --platform linux/arm64 \
-f Dockerfile.release \
--build-arg VERSION=<ver> --build-arg COMMIT=<sha> \
--build-arg BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
--provenance=false --load -t balda-mm:<NEXT> .
zstd -3 -T0 -o /tmp/balda-mm-<NEXT>.tar.zst --force <(docker save balda-mm:<NEXT>)
zstd -dc /tmp/balda-mm-<NEXT>.tar.zst | ssh kraken 'docker load'
ssh kraken '/home/kraken/balda/tools/mm-switch-image.sh <NEXT>' # бэкап compose + recreate
🔴 Обязательные питфоллы (проверенные, не забывать):
--provenance=false— иначеdocker loadна Kraken ругается на формат.- zstd распаковывать на Mac (zstd 1.5.4 на Kraken не читает фрейм macOS 1.5.7).
- Все правки → финальный
go build/go test→ и только потом docker build. Сборка, начатая до последней правки, даёт устаревший бинарник. command: ["start"]в compose — без подкоманды бинарь печатает help и висит.- Образ —
balda-mm, неclaudio-agent.-tопределяет, чей контейнер обновится.
Текущий образ на Kraken: balda-mm:0.1.13 → следующий 0.1.14.
⚠️ Проверить состояние хоста ПЕРЕД деплоем — в доке зафиксировано исчерпание RAM и
watchtower-убийца mm-postgres, плюс depends_on не работает между compose-проектами.
personal/tech/kraken-host-resource-limits.md, personal/tech/kraken-docker-startup-order.md.
5. План — Часть D: валидация (тулинг + MM)
D1. Тулинг (MCP-инструменты исполняются)
Признак успеха — вызов инструмента реально исполнен, не «контейнер Up»:
function_response_part_count = 1
duplicate tool: → 0
deadletter → 0
turn_complete / final_response → true
⚠️ Питфолл своей же проверки: grep -c "duplicate tool" даёт ложную 1, потому что
собственная строка лога — «skipping duplicate toolset». Искать строго
grep -c "duplicate tool:" (с двоеточием).
D2. Mattermost — приёмка ОТ АККАУНТА ALEX (не от testuser)
🔴 testuser → settlement_stage=unauthorized. Это не приёмка.
# токен владельца БЕЗ пароля
ssh kraken 'docker exec mattermost mmctl --local token generate admin "agent-e2e-$(date +%Y%m%d-%H%M)"'
# пост от владельца
ssh kraken '/tmp/mm-post-admin.sh <token> 7bjw4g7o1jdsbmjbqd649xxgaw "@balda <текст>"'
# чтение ленты
ssh kraken '/tmp/mm-feed.sh <token>'
⚠️ Скрипты mm-post-admin.sh / mm-feed.sh живут только в /tmp на Kraken — не переживут
reboot. Воспроизводить из дока. Собирать заголовок из кусков
(HN="Auth""orization"), иначе редакция секретов Hermes калечит файл.
Сценарии проверки (покрывают и блокеры §2):
| # | Сценарий | Что доказывает |
|---|---|---|
| D2-a | @balda вызови executor_health от Alex |
тулинг исполняется, scoped-URL выжил (PR #5) |
| D2-b | Burst из ~17 сообщений подряд | не теряется ни одно (блокер B1) |
| D2-c | docker compose restart balda во время обработки |
drain, нет потерянных постов (B3) |
| D2-d | /topic / управляющая команда в канале |
command ingress работает |
| D2-e | Пост из группового DM от двух участников | одна сессия на канал |
Метрики: settlement_stage=accepted, bad_seq=0, RestartCount=0.
6. Риски
- 🔴 Смена
runtime-local— самая опасная правка. Если в локальной копии есть незакоммиченные ручные правки, кроме PR4 (#4 вписан руками), их потеря = регрессия. ⇒ До замены:diff -r runtime-local ~/Developer/runtime-localи просмотр отличий от апстрима. - 🔴 RAM на Kraken (4 ГБ, swap 0). Прошлый раз load 57, MM недоступен. Проверить перед деплоем.
- ⚠️
depends_onмежду compose-проектами не работает —balda-mmможет стартовать раньше MM. - ⚠️ Правки — только дельта-апплаером (
tools/run-project-deltas.sh <check|apply|list> <deltas.json> <state.json>, JSON — плоский массив, не объект). Не sed/in-place. - ⚠️ Мои незакоммиченные правки Balda-слоя (PR #5) — решить судьбу в B0.
- ⚠️ Двойной префикс
display_nameв БД — прошлый раз починили в БД, а не в коде; проверять.
Связанные заметки
- personal/projects/balda/balda-kraken-mm-deploy — деплой, питфоллы, скрипты приёмки
- personal/plans/balda-mm-pr8-review-fixes — предыдущий раунд правок PR #8
- personal/plans/runtime-pr5-toolset-dedup-review-fixes — PR #5, вопрос копии рантайма
- personal/plans/runtime-pr4-openai-toolcalls-fixes — PR #4, tool_calls
- personal/tech/kraken-host-resource-limits · personal/tech/kraken-docker-startup-order
- personal/tech/balda-go-fx-pitfalls · personal/tech/hermes-secret-redaction-bypass