[2026-09-28] eagle: personal/plans/balda-runtime-rebuild-mm-validation.md personal/plans/runtime-pr5-toolset-dedup-review-fixes.md personal/projects/balda/balda-kraken-mm-deploy.md personal/tech/adk-hostedagent-openai-mcp.md
This commit is contained in:
1 parent
3ae2f056d4
commit
1480fa8d95
4 files changed
+410
-106
No files matched your search
@@ -211,6 +211,80 @@ fail closed). Проверка кода брокера, а не симметри
|
||||
контролем** — вернуть баг и убедиться, что тест падает. Тест, который не падает на сломанном
|
||||
коде, — это не тест, а его имитация. См. навык `batch-data-edit-review-loop`.
|
||||
|
||||
---
|
||||
|
||||
## 5a. 🔴 ПОСТ-МЕРЖ: мейнтейнер нашёл 4 дефекта в моём фиксе PR #5
|
||||
|
||||
До мержа в ветку прилетели 3 коммита мейнтейнера (`f8011c1`, `e888d5e`, `facb0d0`).
|
||||
Два замечания — **настоящие дефекты моего кода**, не стилистика.
|
||||
|
||||
| Коммит | Что нашёл | Почему это дефект |
|
||||
|---|---|---|
|
||||
| `f8011c1` | **`hydrateMCPServerConfig` не переносил `DedupKey`/`DedupPreferred`** | 🔴 **Фикс был бы мёртвым в продовом пути `Build()`**: `hostedToolsets` читает гидратированные конфиги → ключ всегда пуст → дедуп не срабатывает **никогда**. Мой тест звал `hostedToolsets` напрямую, минуя гидратацию, поэтому дефект не поймал |
|
||||
| `e888d5e` | `DedupPreferred: true` без `DedupKey` не отвергался | бессмысленная конфигурация проходила молча |
|
||||
| `facb0d0` | убран мой `fmt.Printf` | библиотека не должна писать в stdout |
|
||||
| — | 🔴 **`strings.TrimSpace(key)` на сравнении — нормализация** | ключ обязан быть **opaque**: `"tenant-a"` ≠ `" tenant-a "`. Нормализация склеила бы независимо сконфигурированные namespace'ы и **воссоздала бы cross-tenant merge**, который этот API и должен предотвращать |
|
||||
|
||||
### 🔴 Тест, обходящий продовый путь, не ловит дефект
|
||||
|
||||
Это **четвёртая форма** бесполезного теста (дополняет таблицу выше):
|
||||
|
||||
| Форма | Как выглядит | Почему бесполезна |
|
||||
|---|---|---|
|
||||
| Терпимый ассерт | `x != "A" && x != "a"` | валидное значение никогда не отклоняется |
|
||||
| Копия логики в тесте | тест-хелпер переписывает цикл прода | проверяется копия, не результат |
|
||||
| Вакуумный пробник | `ProcessRequest(ctx any, req any)` | типы не совпадут никогда, `t.Fatal` недостижим |
|
||||
| **Юнит-тест внутренней функции** | тест зовёт `hostedToolsets(...)` напрямую, минуя `factory.Build()` | **проверяет половину конвейера**; дефект в гидратации/сборке конфига не виден |
|
||||
|
||||
📌 **Правило:** для фичи, живущей в конвейере «собрать конфиг → гидратировать → использовать»,
|
||||
нужен **хотя бы один тест через публичную точку входа**. Эталон, появившийся в upstream после
|
||||
ревью, — `TestFactoryBuildKeepsPreferredDedupEndpoint`: собирает фабрику через `New(...)`,
|
||||
регистрирует MCP-серверы, зовёт `f.Build(...)` и ассертит, что до транспорта дошёл scoped-endpoint.
|
||||
|
||||
### 📌 Ключ дедупа обязан быть opaque
|
||||
|
||||
```go
|
||||
// ❌ нормализация на сравнении — cross-tenant merge
|
||||
key := strings.TrimSpace(cfg.DedupKey)
|
||||
// ✅ ключ не трогаем; TrimSpace только для проверки «пустой ли»
|
||||
key := cfg.DedupKey
|
||||
if strings.TrimSpace(key) == "" { continue }
|
||||
```
|
||||
|
||||
⚠️ И: несколько `DedupPreferred` в одной группе должны давать **ошибку**, а не выбирать
|
||||
победителя по порядку id — активная авторизация не может зависеть от сортировки.
|
||||
|
||||
### 🔴 Осиротевший каталог чужого модуля ломает `go-arch-lint`
|
||||
|
||||
Пока в корне Balda лежал `runtime-local/` (копия runtime через `replace`), `go-arch-lint`
|
||||
давал **56 notices** `File /runtime-local/taskmaster/core.go not attached to any component in
|
||||
archfile` — хотя каталог не участвовал в сборке. После выноса → `OK - No warnings found`.
|
||||
|
||||
📌 Заметки arch-lint о «файлах вне компонентов» — сначала проверить, не осиротевший ли это
|
||||
каталог, а не править `.go-arch-lint.yml`.
|
||||
|
||||
---
|
||||
|
||||
## 5б. 📌 PR создаётся через `gh` API — git-ремоут на базовый репо не нужен
|
||||
|
||||
Частая путаница: «как открыт PR, если ремоута на базовый репозиторий нет?».
|
||||
PR идёт **из форка**: ветка пушится в `origin` (форк), затем
|
||||
`gh pr create --repo <base> --head <owner>:<branch>`. Git-ремоут на `<base>` для этого
|
||||
**не требуется** — достаточно доступа аккаунта к репозиторию.
|
||||
|
||||
```bash
|
||||
# где реально живёт ветка PR
|
||||
git ls-remote --heads <base-url> <branch> # пусто → ветка в форке, так и должно быть
|
||||
gh pr view <N> --repo <base> --json headRepositoryOwner,headRepository,headRefName,baseRefName
|
||||
```
|
||||
|
||||
⚠️ `normahq/balda` и `baldaworks/balda` отдавали **идентичный** `main` (`c1fde3c4`) — это один
|
||||
репозиторий (переименование/зеркало). **Не считать их разными апстримами.**
|
||||
|
||||
⚠️ База PR может отставать от `main`: у PR #8 база `de273d8f`, а `upstream/main` уже `c1fde3c4`
|
||||
→ PR требует синхронизации перед мержем.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 6. Метод: исполняемый пробник вместо чтения
|
||||
|
||||
Reference in new issue
Block a user