[2026-09-28] eagle: personal/plans/balda-runtime-rebuild-mm-validation.md personal/plans/runtime-pr4-openai-toolcalls-fixes.md personal/plans/runtime-pr5-toolset-dedup-review-fixes.md personal/tech/adk-hostedagent-openai-mcp.md
This commit is contained in:
1 parent
73518c5e43
commit
7501feea25
4 files changed
+299
-23
No files matched your search
@@ -0,0 +1,206 @@
|
||||
> Создан 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
|
||||
```bash
|
||||
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 (до начала работ)
|
||||
|
||||
1. **A3 vs A4:** убрать `replace` совсем (поднять версию runtime) или заменить `runtime-local`
|
||||
на чистый upstream-чекаут и оставить `replace`?
|
||||
2. **B1:** backpressure (блокировать read loop) или durable bounded queue с dedupe?
|
||||
3. **Порядок:** сначала закрыть 3 блокера PR #8, потом собирать/деплоить? Или собрать сейчас
|
||||
(валидация тулинга + MM уже возможна) и блокеры закрыть следом?
|
||||
|
||||
---
|
||||
|
||||
## 4. План — Часть C: сборка и деплой на Kraken
|
||||
|
||||
Проверенный порядок (из [[personal/projects/balda/balda-kraken-mm-deploy]]):
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
🔴 **Обязательные питфоллы (проверенные, не забывать):**
|
||||
1. `--provenance=false` — иначе `docker load` на Kraken ругается на формат.
|
||||
2. zstd распаковывать **на Mac** (zstd 1.5.4 на Kraken не читает фрейм macOS 1.5.7).
|
||||
3. **Все правки → финальный `go build`/`go test` → и только потом docker build.**
|
||||
Сборка, начатая до последней правки, даёт устаревший бинарник.
|
||||
4. `command: ["start"]` в compose — без подкоманды бинарь печатает help и висит.
|
||||
5. Образ — **`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 tool**set». Искать строго
|
||||
`grep -c "duplicate tool:"` (с двоеточием).
|
||||
|
||||
### D2. Mattermost — приёмка ОТ АККАУНТА ALEX (не от `testuser`)
|
||||
🔴 `testuser` → `settlement_stage=unauthorized`. Это **не** приёмка.
|
||||
```bash
|
||||
# токен владельца БЕЗ пароля
|
||||
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. Риски
|
||||
|
||||
1. 🔴 **Смена `runtime-local` — самая опасная правка.** Если в локальной копии есть
|
||||
**незакоммиченные ручные правки**, кроме PR4 (#4 вписан руками), их потеря = регрессия.
|
||||
⇒ До замены: `diff -r runtime-local ~/Developer/runtime-local` и просмотр отличий от апстрима.
|
||||
2. 🔴 **RAM на Kraken (4 ГБ, swap 0).** Прошлый раз load 57, MM недоступен. Проверить перед деплоем.
|
||||
3. ⚠️ `depends_on` между compose-проектами не работает — `balda-mm` может стартовать раньше MM.
|
||||
4. ⚠️ Правки — **только дельта-апплаером** (`tools/run-project-deltas.sh <check|apply|list> <deltas.json> <state.json>`,
|
||||
JSON — **плоский массив**, не объект). Не sed/in-place.
|
||||
5. ⚠️ Мои незакоммиченные правки Balda-слоя (PR #5) — решить судьбу в B0.
|
||||
6. ⚠️ Двойной префикс `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]]
|
||||
@@ -1,11 +1,18 @@
|
||||
# runtime PR #4 — OpenAI tool_calls: исправление 4 дефектов ревью
|
||||
|
||||
> Создан 2026-09-28. Статус: **✅ РЕАЛИЗОВАНО, ЗАПУШЕНО. CI блокирован одобрением мейнтейнера (внешний).**
|
||||
> Голова PR: **`0937011`** (3 файла, +1045/−27), ветка `feat/openai-tool-calls-v2`.
|
||||
> **PR normahq/runtime#4** — OPEN, MERGEABLE.
|
||||
> Создан 2026-09-28. Статус: **✅ ВЛИТО В АПСТРИМ (2026-09-28T13:21:59Z).**
|
||||
> Голова PR: **`22f7f17`** (мой коммит `0937011` + правки мейнтейнера), ветка `feat/openai-tool-calls-v2`.
|
||||
> **PR normahq/runtime#4** — **MERGED** (merge-коммит `c6dfc6d`).
|
||||
> Все 4 дефекта ревью закрыты + 4 контрактных теста. Гейты репо зелёные локально.
|
||||
> Репо: `~/Developer/runtime-local`.
|
||||
> Связано: [[personal/tech/adk-hostedagent-openai-mcp]], [[personal/projects/balda/balda-valera]].
|
||||
> Связано: [[personal/tech/adk-hostedagent-openai-mcp]], [[personal/projects/balda/balda-valera]],
|
||||
> [[personal/plans/runtime-pr5-toolset-dedup-review-fixes]].
|
||||
>
|
||||
> 📌 **После мержа:** `upstream/main` (`c41939f`) содержит и PR #4, и PR #5, и мейнтейнерские
|
||||
> фиксы к обоим. Форк `mallexxx/runtime` и `replace` в Balda **больше не нужны** —
|
||||
> см. [[personal/plans/balda-runtime-rebuild-mm-validation]].
|
||||
> ⚠️ Мейнтейнер добавил в ветку PR #4 коммит `d83b8e0` `fix(hostedagent): preserve aliased tool names`
|
||||
> — алиасы имён инструментов (`toolAliases`), которых в моём варианте не было.
|
||||
|
||||
---
|
||||
|
||||
@@ -199,20 +206,38 @@ go tool golangci-lint run ./...
|
||||
7. ⛔ `gh pr checks 4` — `action_required` (fork-PR, нужно одобрение мейнтейнера), §0в
|
||||
8. ✅ Obsidian обновлён: этот файл + [[personal/tech/adk-hostedagent-openai-mcp]]
|
||||
|
||||
## 4a. Открытый вопрос: синхронизация копии рантайма в balda
|
||||
## 4a. ✅ ЗАКРЫТО: синхронизация копии рантайма в balda
|
||||
|
||||
`~/Developer/balda/runtime-local` — **отдельная копия** (не симлинк), которую `balda/go.mod`
|
||||
подключает через `replace github.com/normahq/runtime/v2 => ./runtime-local`.
|
||||
Её HEAD = `05342c5a` (коммит **balda**, другой репо), 516 строк, без правок PR #4.
|
||||
> **Обновлено 2026-09-28 (после мержа).** Вопрос решён концептуально, реализация — открыта.
|
||||
|
||||
Значит наш боевой стенд Балды **пока не получил** фиксы tool_calls. Синхронизировать =
|
||||
перенести `hostedagent/openai.go` из `~/Developer/runtime-local` в `~/Developer/balda/runtime-local`
|
||||
(плюс решить, как версионировать: submodule / копия / отдельная ветка).
|
||||
Уточнено фактами (**прежнее описание в этом разделе было неточным**):
|
||||
|
||||
🔴 **Решать после мержа PR #4** — иначе копия разъедется повторно при следующей правке апстрима.
|
||||
- `~/Developer/balda/runtime-local` — **НЕ git-клон runtime и не «HEAD `05342c5a` runtime»**.
|
||||
Это **простой копированный снапшот** каталога runtime (есть `AGENTS.md`, `agentconfig/`,
|
||||
`hostedagent/`, `go.mod` и т.д., **но нет `.git`**). Каталог **git-ignored** в balda
|
||||
(`git ls-files runtime-local` → 0).
|
||||
- От `upstream/main` отличаются **ровно 3 файла**, и все три — **устаревшие** версии того,
|
||||
что уже влито:
|
||||
`agentfactory/agentfactory.go`, `hostedagent/openai.go`, `hostedagent/openai_test.go`.
|
||||
- `agentconfig/config.go` содержит `DedupKey` — **0 вхождений** (PR #5 отсутствует).
|
||||
|
||||
⇒ **Потери при замене нет.** Подключён через
|
||||
`replace github.com/normahq/runtime/v2 => ./runtime-local` (`go.mod:368`).
|
||||
|
||||
🔴 **Почему это больше не нужно:** PR #4 и PR #5 **влиты в `normahq/runtime`**, а мейнтейнер
|
||||
довёл оба до финального вида (`d83b8e0`, `f8011c1`, `e888d5e`, `facb0d0`).
|
||||
Форк `mallexxx/runtime` и `replace` утратили смысл.
|
||||
|
||||
**Развилка (решение за Alex)** — [[personal/plans/balda-runtime-rebuild-mm-validation]] §1/§3:
|
||||
1. убрать `replace`, поднять `require github.com/normahq/runtime/v2` до версии с PR4+PR5 (штатный путь);
|
||||
2. либо заменить содержимое `runtime-local` на чекаут `upstream/main` @ `c41939f`, оставив `replace`.
|
||||
|
||||
⚠️ Обновить комментарий в `go.mod:365-367` — он ссылается на PR #4 как на **открытый**.
|
||||
|
||||
## Связанные заметки
|
||||
|
||||
- [[personal/plans/runtime-pr5-toolset-dedup-review-fixes]] — PR #5, дедуп MCP-тулсетов по явному ключу
|
||||
- [[personal/plans/balda-runtime-rebuild-mm-validation]] — сборка + деплой на Kraken + валидация
|
||||
- [[personal/tech/adk-hostedagent-openai-mcp]] — MCP/tool_calls архитектура, этот патч
|
||||
- [[personal/projects/balda/balda-valera]] — где патч применяется в бою
|
||||
- [[personal/tech/balda-go-fx-pitfalls]] — метод дельт, питфоллы
|
||||
@@ -1,11 +1,42 @@
|
||||
> Создан 2026-09-28. Статус: **✅ РЕАЛИЗОВАНО, ЗАПУШЕНО. Ре-ревью ожидается.**
|
||||
> Голова PR: **`d4ab923`** (4 файла, +411/−1), ветка `fix/hosted-toolsets-duplicate-endpoint`.
|
||||
> **PR normahq/runtime#5** — OPEN. Ответ ревьюеру опубликован:
|
||||
> https://github.com/normahq/runtime/pull/5#issuecomment-5867224210
|
||||
> Создан 2026-09-28. Статус: **✅ ВЛИТО В АПСТРИМ (2026-09-28T13:22:13Z).**
|
||||
> Мой коммит: **`d4ab923`** (4 файла, +411/−1), ветка `fix/hosted-toolsets-duplicate-endpoint`.
|
||||
> **PR normahq/runtime#5** — **MERGED** (merge-коммит `6775d71`).
|
||||
> Ответ ревьюеру: https://github.com/normahq/runtime/pull/5#issuecomment-5867224210
|
||||
> Репо: `~/Developer/runtime-local`. Связано: [[personal/plans/runtime-pr4-openai-toolcalls-fixes]].
|
||||
|
||||
---
|
||||
|
||||
## 0а. 🔴 ПОСТ-МЕРЖ: мейнтейнер нашёл 2 дефекта в МОЁМ фиксе
|
||||
|
||||
После моего `d4ab923` и **до** мержа в ветку прилетели 3 коммита мейнтейнера
|
||||
(`f8011c1`, `e888d5e`, `facb0d0` — head PR стал `facb0d0`). Это **code review моего кода**,
|
||||
и два замечания — настоящие дефекты:
|
||||
|
||||
| Коммит | Что нашёл | Почему это мой дефект |
|
||||
|---|---|---|
|
||||
| `f8011c1` `fix(agentfactory): preserve MCP dedup metadata` | **`hydrateMCPServerConfig` не переносил `DedupKey`/`DedupPreferred`** в гидратированную копию | 🔴 **Фикс был бы мёртвым в продовом пути `Build()`.** `hostedToolsets` читает гидратированные конфиги → ключ всегда пуст → дедуп никогда не срабатывает. Мой юнит-тест звал `hostedToolsets` **напрямую**, минуя гидратацию, поэтому дефект не поймал |
|
||||
| `e888d5e` `fix(agentconfig): validate preferred MCP dedup` | `DedupPreferred: true` без `DedupKey` не отвергался | Бессмысленная конфигурация проходила молча |
|
||||
| `facb0d0` `fix(agentfactory): keep MCP dedup silent` | Убрал мой `fmt.Printf` из библиотеки; добавил ошибку при **нескольких** `DedupPreferred` в одной группе | Библиотека не должна писать в stdout; молчаливый выбор победителя делал активную авторизацию зависимой от порядка id |
|
||||
| — | **`strings.TrimSpace(key)` — нормализация ключа** | 🔴 Ключ обязан быть **opaque**: `"tenant-a"` и `" tenant-a "` — разные namespace'ы. Нормализация склеила бы независимо сконфигурированные namespace'ы и воссоздала бы cross-tenant merge, который этот API и должен предотвращать |
|
||||
|
||||
**Заменённые строки в моём коде:**
|
||||
```go
|
||||
// было (мой вариант) // стало (upstream/main)
|
||||
key := strings.TrimSpace(cfg.DedupKey) key := cfg.DedupKey
|
||||
if strings.TrimSpace(key) == "" { continue }
|
||||
skip[id] = true skip[id] = true // без fmt.Printf
|
||||
```
|
||||
+ `hydrateMCPServerConfig` теперь копирует `DedupKey`/`DedupPreferred`.
|
||||
|
||||
📌 **ГЛАВНЫЙ УРОК (durable):** юнит-тест, вызывающий внутреннюю функцию **напрямую**,
|
||||
не покрывает продовый путь, где конфиг проходит через **гидратацию/нормализацию**.
|
||||
Мейнтейнер добавил `TestFactoryBuildKeepsPreferredDedupEndpoint` — он идёт через
|
||||
`f.Build()` (registry lookup → hydration → hostedToolsets). **Правило: тестировать сквозь
|
||||
композиционный путь, а не только целевую функцию.** Этот дефект дал бы «зелёные гейты
|
||||
и неработающий фикс» — ровно тот класс ошибки, против которого был весь PR.
|
||||
|
||||
---
|
||||
|
||||
## 0. ИТОГ — что сделано
|
||||
|
||||
Коммит **`d4ab923`** `fix(agentfactory): dedup MCP toolsets by explicit key`.
|
||||
@@ -116,15 +147,24 @@ go tool golangci-lint run ./... → 0 issues
|
||||
|
||||
## 5. Осталось сделать
|
||||
|
||||
1. ⏳ **Ре-ревью metalagman** — ждать.
|
||||
2. ⛔ **Синхронизация копии рантайма в Balda** (`~/Developer/balda/runtime-local`, HEAD `05342c5a`,
|
||||
`grep -c DedupKey agentconfig/config.go` → **0**). Правки Balda-слоя (§0) **сейчас не компилируются**
|
||||
против этой копии — ошибки `unknown field DedupKey in struct literal of type agentconfig.MCPServerConfig`.
|
||||
Это **отдельная задача**, как и в PR #4 (решать после мержа, чтобы копия не разъехалась снова).
|
||||
🔴 Пока не синхронизировано — боевой стенд Балды фикс **не получил**.
|
||||
1. ✅ **Ре-ревью пройдено, PR влит** (`6775d71`).
|
||||
2. 🔴 **Синхронизация копии рантайма в Balda — ОТКРЫТО, блокирует боевой стенд.**
|
||||
`~/Developer/balda/runtime-local` — **не клон runtime**, а **снапшот кода эпохи PR #4**
|
||||
(3 файла отличаются от `upstream/main`, все три — в пользу апстрима; `DedupKey` — **0 вхождений**).
|
||||
Каталог **git-ignored** в balda и подключён через
|
||||
`replace github.com/normahq/runtime/v2 => ./runtime-local`.
|
||||
Правки Balda-слоя из §0 **не компилируются** против него
|
||||
(`unknown field DedupKey in struct literal of type agentconfig.MCPServerConfig`).
|
||||
✅ **Потери при замене НЕТ** — проверено `diff -rq`:
|
||||
отличаются только `agentfactory/agentfactory.go`, `hostedagent/openai.go`,
|
||||
`hostedagent/openai_test.go` (все — устаревшие версии того, что уже в апстриме).
|
||||
⚠️ В апстриме мой код **уже исправлен мейнтейнером** (§0а) — синхронизировать надо с
|
||||
`upstream/main` (`c41939f`), а не с моим `d4ab923`.
|
||||
План и развилка (убрать `replace` совсем vs заменить копию) —
|
||||
[[personal/plans/balda-runtime-rebuild-mm-validation]] §1/§3.
|
||||
3. ⚠️ `/tmp/negctl.sh`, `/tmp/control1.py`, `/tmp/control2.py`, `/tmp/af.bak`, `/tmp/dt.bak`,
|
||||
`/tmp/commitmsg.txt`, `/tmp/reply.md`, `/tmp/pr5_af.go`, `/tmp/pr5_test.go` — временные.
|
||||
4. ⚠️ Проверить, не утекла ли ветка PR #4 (`feat/openai-tool-calls-v2`) — она тоже открыта.
|
||||
4. ✅ Ветки PR #4/#5 больше не «утекли» — обе влиты.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in new issue
Block a user