[2026-09-28] eagle: personal/plans/runtime-pr5-toolset-dedup-review-fixes.md personal/tech/adk-hostedagent-openai-mcp.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-28 15:34:42 +06:00
1 parent 122872a677
commit addd5ba445
2 files changed
+165 -164

No files matched your search

+38 -10
View File
@@ -5,7 +5,9 @@
> Проект: [[personal/plans/balda-mm-phase4-agents]] §19, [[personal/projects/balda/balda-kraken-mm-deploy]] §19.
>
> 🔴 **ОБНОВЛЕНО 2026-09-28:** первая версия фикса дедупа (§4) и два теста (§5, §6)
> **отклонены ревью PR #5**. Правки помечены в §4a / §5 / §6 — читать их вместе с §4.
> **отклонены ревью PR #5**. §4a объясняет причину и **описывает замену, реализованную в `d4ab923`**
> (явный `DedupKey`/`DedupPreferred` вместо вывода из URL). §5 и §6 помечены `✅ ИСПРАВЛЕНО`.
> Читать §4 только как историю — не копировать.
---
@@ -137,16 +139,29 @@ extraMCPServerIDs = append(extraMCPServerIDs, binding.ID)
| P2 | test gap | `selectScopedOnly` (§5) **дублирует алгоритм продакшена** и сам вычисляет «ожидаемого» победителя → не проверяет фактически удержанный конфиг. Вакуумный ассерт. |
| P2 | test gap | Пробник `ProcessRequest(ctx any, req any)` (§6) — Go требует **точных** типов, реальная подпись `(agent.Context, *model.LLMRequest)` его **не** удовлетворяет → проверка не может сработать. |
📌 **Направление замены (ожидает одобрения Alex):**
- generic-слой (`agentfactory`) **перестаёт выводить** идентичность из формы URL;
- схлопывание только по **явному** ключу — предлагается `DedupKey string` в
`agentconfig.MCPServerConfig` (альтернатива — `Aliases []string`);
- Balda объявляет свой дубль **сама** в composition layer — `internal/apps/balda/agent/runtime_manager.go:344`
(`registry.Set(binding.ID, binding.Config)`) — ровно этого просит ревьюer («resolve the Balda-specific
duplicate in the Balda composition layer»);
- победитель — **детерминированный** (lexicographic) или явное поле, но **не** эвристика по наличию query.
📌 **Направление замены — РЕАЛИЗОВАНО 2026-09-28 в `d4ab923`** (PR #5):
- generic-слой (`agentfactory`) **перестал выводить** идентичность из формы URL —
`mcpEndpointKey` и `mcpURLIsScoped` удалены;
- схлопывание только по **явному** ключу: `DedupKey string` в `agentconfig.MCPServerConfig`
(+ `DedupPreferred bool` — кто выживает, когда записи не взаимозаменяемы);
- Balda объявляет свой дубль **сама** в composition layer:
`internal/apps/balda/internalmcp/manager.go:213` (bundled) и
`internal/apps/balda/sessionapp/module.go:130` (scoped-binding) ставят общий
`sessionmemorymcp.BundledDedupKey = "balda-bundled-mcp"`;
- победитель — **детерминированный**: помеченный `DedupPreferred` > лексикографически меньший id.
⚠️ Разные `?tenant=`/`Authorization` в общем слое обязаны оставаться **разными серверами**.
📌 **Пустой `DedupKey` = дедуп выключен.** Это safety-свойство: конфиги, которые раньше
сливались по общему host/path, теперь **по умолчанию остаются разными**. Есть тест
`TestEmptyDedupKeyNeverCollapses`.
⚠️ Разные `?tenant=`/`Authorization` в общем слое остаются **разными серверами** — тесты
`TestDistinctQueryParamsNeverCollapse` и `TestDistinctHeadersNeverCollapse`.
⚠️ **Почему понадобился `DedupPreferred`, а не порядок id.** Лексикографически меньший id — это
`balda` (plain, **без** токена). Простая замена эвристики на сортировку была бы регрессией:
токен в URL функциональный (`contextQueryParameter = "balda_context"`, `Wrap` инжектит
`HeaderSessionLocator`/`HeaderSessionID`/`HeaderSessionBinding`, без токена session-memory
fail closed). Проверка кода брокера, а не симметрия с ревью, это поймала.
---
@@ -178,6 +193,19 @@ extraMCPServerIDs = append(extraMCPServerIDs, binding.ID)
либо подняв реальные httptest-MCP-серверы с разными tool-листами. Урок усиливается: **копия логики
в тесте — тот же класс ошибки, что терпимый ассерт.** Тест обязан наблюдать **результат продакшена**.
✅ **ИСПРАВЛЕНО в `d4ab923`.** `selectScopedOnly` удалён. Реализован **тестовый хук**:
`var mcpTransportFactory = mcpTransportForConfig` — тест подменяет её на записывающую и ассертит
`Transport.Endpoint` конфига, реально дошедшего до сборки транспорта. Плюс два **негативных
контроля** (проверено скриптом):
1. возврат инференса из URL (стрип query) → `TestDistinctQueryParamsNeverCollapse` **FAIL**:
`expected 2 toolsets for distinct tenants, got 1`;
2. возврат `ctx any, req any` → **build failed**
(`*stubRequestProcessor does not implement requestProcessor`).
📌 **Правило, выведенное на практике:** новый тест на баг обязательно проверять **негативным
контролем** — вернуть баг и убедиться, что тест падает. Тест, который не падает на сломанном
коде, — это не тест, а его имитация. См. навык `batch-data-edit-review-loop`.
---
## 6. Метод: исполняемый пробник вместо чтения