[2026-09-26] eagle: personal/plans/balda-mm-phase4-agents.md personal/plans/music-tags-review/music-tags-review.md personal/tech/agents-bridge.md personal/tech/music-tags-repair-truenas.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-26 18:04:35 +06:00
1 parent d2f6a411f9
commit dd9e081273
4 files changed
+492 -32

No files matched your search

+87 -27
View File
@@ -1,8 +1,10 @@
# Фаза 4 — исполнитель на Mac + `~/agents` + секция «Agents» в Eagle Dashboard
> План. **Шаг 1 выполнен** (2026-09-26): образ собран, контейнер `balda-executor` Up (healthy),
> План. **Шаги 1-2 выполнены** (2026-09-26): образ собран, контейнер `balda-executor` Up (healthy),
> `claude 2.1.283` + `codex 0.157.1` внутри, монтирования проверены в обе стороны.
> ⏳ Осталось в шаге 1: логин CLI (нужен апрув на копирование auth-файлов).
> Мост `agents-bridge` :8790 поднят и протестирован (auth, идемпотентность, сквозной вызов CLI).
> 🔴 Осталось: **логин CLI делает Alex сам** (копирование auth-файлов отклонено); мост не в launchd;
> шаги 3-6 не начаты.
> Часть [[personal/projects/balda/balda-mm-delegation-plan]] (Фазы 4-5).
> Предыдущее: [[personal/projects/balda/balda-kraken-mm-deploy]] (Фаза 3 ✅ — бот отвечает Alex).
@@ -71,13 +73,12 @@ diff + тесты + коммит → Балда → Mattermost
| Codex auth | `~/cli-auth/codex` | `/root/.codex` | 0700 |
| OAuth-токен Claude | `~/Docker/balda-executor/.env` | env | 0600 |
📌 **Основной путь авторизации — не `claude setup-token`, а копия auth-файлов** из
`~/.claude`/`~/.codex`. Токен в `.env` — запасной вариант для headless без монтирования.
Выбранный вариант: копируются `~/.claude/.credentials.json` + `~/.claude/.claude.json` и
`~/.codex/auth.json` + `~/.codex/config.toml`. Полные каталоги **не** копируются:
`~/.codex` содержит ~640 МБ sqlite-логов/состояний (`logs_2.sqlite`, `state_5.sqlite`,
`memories_1.sqlite`, `queue_1.sqlite`) — исполнителю не нужны, а вес и шум дают.
📌 **Авторизацию CLI делает Alex сам** (решение 2026-09-26). Копирование auth-файлов из
`~/.claude`/`~/.codex` в `~/cli-auth` **отклонено** — я эти файлы не читаю и не копирую.
До его логина любая задача вернёт `Not logged in · Please run /login` (это ответ Claude Code,
а не ошибка моста — конвейер при этом доказанно рабочий).
Токен `CLAUDE_CODE_OAUTH_TOKEN` в `.env` контейнера — запасной путь для headless без монтирования.
Пересборка образа и обновление CLI auth не сбрасывают. Токены вне `/agents` → агент их не видит.
---
@@ -180,25 +181,77 @@ docker-compose restart # проверка переживан
⚠️ `deploy.resources.limits.memory: 8G` из черновика **убран**: в не-swarm compose
эта секция молча игнорируется, лимит создавал ложное ощущение защиты.
#### ⏳ Осталось в шаге 1: логин CLI (ждёт апрува)
#### ✅ Логин CLI — зона Alex (не автоматизируется)
`~/cli-auth/claude` пуст, в `~/cli-auth/codex` только `tmp/`. Копировать **только auth-файлы**,
не целые каталоги (`~/.codex` ≈ 640 МБ служебных sqlite — агенту не нужны):
`~/cli-auth/claude` пуст, в `~/cli-auth/codex` только `tmp/`.
| CLI | Хост | Куда |
|---|---|---|
| claude | `~/.claude/.credentials.json`, `~/.claude/.claude.json` | `~/cli-auth/claude/` |
| codex | `~/.codex/auth.json`, `~/.codex/config.toml` | `~/cli-auth/codex/` |
🔴 Копирование auth-файлов **отклонено Alex** («авторизую я, копировать из кредсы не надо»).
Не предлагать повторно, не читать `~/.claude/.credentials.json`, `~/.codex/auth.json`.
Признак незалогиненного исполнителя в ответе задачи: `Not logged in · Please run /login`.
📌 В `~/cli-auth` кладётся **копия** (оригиналы на месте, `~/.claude` не переезжает):
у агента-исполнителя свои токены, изолированные от рабочих. Права `~/cli-auth` = 0700.
### ✅ Шаг 2 ВЫПОЛНЕН (2026-09-26) — мост `agents-bridge`
**2. Мост (~3-4 ч)**
`~/Developer/agents-bridge/`, FastAPI :8790, `POST /task` (idempotency), `GET /task/{id}`, `GET /healthz`;
запуск CLI headless в контейнере; лимит 1-2 задач; shared secret.
Проект: `~/Developer/agents-bridge/` (FastAPI, python из `~/Developer/eagle-dash/.venv`, py3.14).
**3. Сеть (~1 ч)**
Cloudflare Tunnel: добавить published route `agents-bridge.qentra.top` → HTTP `localhost:8790` +
| Файл | Роль |
|---|---|
| `app.py` | роуты, авторизация, лимит параллельности, ThreadPoolExecutor |
| `store.py` | SQLite WAL: `tasks` + UNIQUE-индекс по `idempotency_key` |
| `executor.py` | `docker exec` в контейнер, провайдеры claude/codex, таймаут, обрезка вывода |
| `config.py` | чтение `.env` (минимальный парсер, без python-dotenv на старте) |
| `.env` | 0600, `BRIDGE_SECRET` (64 симв.), **не коммитить** |
| `.env.example` | шаблон без секретов |
| `state.sqlite3` | статусы задач, WAL |
**API:**
```
GET /healthz → статус моста + контейнера (без секрета)
POST /task → 202 {task_id, status} | 200 (идемпотентный повтор) | 401 | 429 | 400
GET /task/{task_id} → статус + stdout/stderr/exit_code
GET /tasks?limit=N → последние задачи
```
**Авторизация:** заголовок `X-Bridge-Secret` на всех `/task*`. Идемпотентность — заголовок
`Idempotency-Key`; повтор возвращает **тот же** `task_id` со HTTP **200** (первый ответ — 202).
**Проверено живьём (2026-09-26):**
| Проверка | Результат |
|---|---|
| `POST /task` без секрета / с неверным | 401 / 401 ✅ |
| Два POST с одним `Idempotency-Key` | один `task_id` ✅ |
| Задача дошла до CLI в контейнере | ответ CLI вернулся ✅ |
| Статус в SQLite (WAL) | ✅ |
| `/healthz` видит контейнер | `container_running: true` ✅ |
Ответ `/healthz`:
```json
{"status":"ok","container":"balda-executor","container_running":true,
"provider":"claude","secret_configured":true,"active_tasks":0,"max_concurrent":1}
```
Результат сквозной пробы (до логина CLI): `status=failed, exit_code=1,
stdout='Not logged in · Please run /login'` — **это ожидаемо** и доказывает, что
путь Kraken → Mac → контейнер → CLI проходит целиком.
**Запуск (вручную, до launchd):**
```bash
cd ~/Developer/agents-bridge
~/Developer/eagle-dash/.venv/bin/python -m uvicorn app:app --host 127.0.0.1 --port 8790
```
#### 🔴 Питфолл: `BRIDGE_SECRET` и redaction Hermes
Команда, создающая `.env` через `python -c` с f-строкой `BRIDGE_SECRET={...}`, в логе выглядит
обрезанной (`E...cret written`) — **это редакция секретов Hermes, файл на диске цел**.
Проверять содержимое не чтением файла, а через awk с маскировкой:
```bash
/usr/bin/awk -F= '{ if ($1 ~ /SECRET|TOKEN|KEY|PASSWORD/) print $1"=<redacted len "length($2)">"; else print }' .env
```
`read_file` на `.env` отказывает по определению (secret-bearing file).
**3. Сеть (~1 ч)** — Cloudflare Tunnel
Добавить published route `agents-bridge.qentra.top` → HTTP `localhost:8790` +
Access Application. Токен и процесс cloudflared не трогаются. Проверка: `curl` извне на `/healthz`.
⚠️ hostname — **одноуровневый** (двухуровневые дают TLS handshake failure).
@@ -228,16 +281,23 @@ MCP-инструмент в Балде → `POST /task`; проба `echo ok > /
## 8. Открыто
1. ~~Провайдер исполнителя — claude или codex~~ → **claude** (оба в образе, переключение `EXECUTOR_PROVIDER`)
2. ~~Нужен ли `ask`-апрув в будущем~~ → при `allow_all` не нужен; при потребности начинать с варианта B (апрув в мосте, ~0.5 дня)
3. Hostname для моста (`agents-bridge.qentra.top`?) — ждёт шага 3
4. ⏳ **Апрув на копирование auth-файлов CLI** в `~/cli-auth` — блокирует завершение шага 1
5. Порт моста `8790` — проверено, свободен (`lsof -nP -i :8790`)
1. ~~Провайдер исполнителя~~ → **claude** (оба в образе, переключение `EXECUTOR_PROVIDER`)
2. ~~Нужен ли `ask`-апрув~~ → при `allow_all` не нужен; при потребности начинать с B (апрув в мосте, ~0.5 дня)
3. 🔴 **Логин CLI — делает Alex сам.** Копирование auth-файлов отклонено; до логина задачи
возвращают `Not logged in`
4. 🔴 **Мост не в launchd** — поднят вручную (`uvicorn` в фоне), при перезагрузке Mac умрёт.
Плейт `com.agents.bridge` **обязателен до шага 3**: туннель опубликует URL, который может
вести в закрытый порт. Предложено, ждёт команды Alex
5. Hostname моста — `agents-bridge.qentra.top` (шаг 3, ждёт public route в Cloud Zero Trust)
6. Порт `8790` — проверено, свободен (`lsof -nP -i :8790`), занят мостом после запуска
7. ⚠️ В дашборде в `services.yaml` **нет** записи `agents_bridge` — добавить в шаге 4
(`health.type: http`, `url: http://127.0.0.1:8790/healthz`, `port: 8790`)
## Связанные заметки
- [[personal/projects/balda/balda-mm-delegation-plan]] — общий план (Фазы 4-5)
- [[personal/projects/balda/balda-kraken-mm-deploy]] — Фаза 3 (✅)
- [[personal/plans/balda-mm-pr-plan]] — Фаза 2 (PR #8)
- [[personal/tech/agents-bridge]] — мост :8790, API, питфоллы (шаг 2 ✅)
- [[personal/tech/macos-docker-virtiofs-mount-limits]] — ограничения macOS Docker
- [[personal/tech/balda-go-fx-pitfalls]] — fx-питфоллы, дельта-апплаер
- [[family/how-to/kraken-portainer-access]] — cloudflared, routes
@@ -20,6 +20,74 @@ updated: '2026-09-26'
| [[2-medium-confidence\|Средняя уверенность]] | 5813 |
| [[3-high-confidence\|Высокая уверенность]] | 959 |
## 🔴 Пятнадцатая волна (2026-09-26): КЛАСС 3 ЗАКРЫТ, КЛАСС 4 НАЧАТ
### ✅ Класс 3 (номер трека в `new_title`) — ЗАКРЫТ ПОЛНОСТЬЮ, 156 строк
Блок `!Детские/Детский хит/` доведён до конца. Фильтр остатка → **пусто**:
`grep 'Детский хит/' tag-fix-plan.csv | grep 'artist<-cleared-junk'`.
Паттерн фикса (единый):
```
БЫЛО: title = `143 БЮРО НАХОДОК`, artist = (пусто), track = (пусто), source = artist<-cleared-junk
СТАЛО: title = `БЮРО НАХОДОК`, artist = (пусто), track = 143, source = manual (user decision)
```
**artist пустой намеренно** — сборник детских песен из мультфильмов без единого исполнителя.
`album = Детский Хит Сезона` — название сборника, **остаётся**.
Полный список исправленного — в `personal/tech/music-tags-repair-truenas.md`, раздел «ПЯТНАДЦАТАЯ ВОЛНА».
### ⚠️ Ложные срабатывания детектора «номер в title»
`grep -E ',[0-9]{1,3} [А-ЯЁA-Z]'` ловит **нормальные** названия:
`32 Leaves` (группа), `3 Doors Down` (группа), `2 кота` (часть названия),
`Зинчук` (номер в **пути**, папка диска), `Амадеус N 146 2002` (номер альбома).
> 🔴 **Правило: цифра в title — НЕ автоматически дефект.** Номер трека стоит **в начале** title
> через пробел и дублируется как `NNN_` в имени файла. Разбирать 3-5 примеров глазами до
> объявления классом.
### 🔄 Класс 4 (транслит) — ~20 из ~40
Метка `translit artist tag; folder is Cyrillic` = **116 строк**, но большинство **ложные**
(западные группы: Joe Hisaishi, Ian Oliver, Yello, Muse, Gorillaz, Europe, Pain, Scooter).
**Реальные — русские группы латиницей.**
Исправлено: `!A Not sorted/Sbornik_Novij_Rok` (13 строк: Мумий Тролль, Мара, Дельфин, Фактор Страха,
Гроза, Диверсанты, Курара, Лакмус, Смысловые Галлюцинации, Скрябин, Бумбокс, Декабрь, Бумбокс),
Глюкоза, Потап и Настя Каменских, Каста (`Бабка`, `Горячее время`), **Наутилус Помпилиус**
(альбомы Атлантида 11, Раскол 10, Подъём 12).
### 🔴 Три собственные ошибки, пойманные в diff
1. `Берегитесь, мальчики` — запятая без кавычек → строка распалась на лишние колонки.
2. В «Крепкий орешек» подставил title `Дождь`.
3. `Goryacheye Vremya` приписал artist `Баста` вместо `Каста`.
> **Правило: читать diff после каждой правки `patch`.** Все три были видны именно в diff.
### 📊 Состояние
| Показатель | Значение |
|---|---:|
| Битых строк | **0** |
| Ручных правок | **~500** |
| Класс 5/C «склейка в title» | ✅ ЗАКРЫТ |
| Класс A «техпапка в artist» | ✅ ЗАКРЫТ |
| Класс 3 «номер в title» | ✅ ЗАКРЫТ (156) |
| Класс 4 «транслит» | 🔄 ~20 / ~40 |
| `no_change` (~1100) | 🔴 НЕ ПРОВЕРЯЛИСЬ |
| Применение на NAS | НЕ начато |
### ⏭ Осталось
1. **Класс 4** — остаток Наутилуса (`1998 Яблокитай` и далее), `!Рэп/НТЛ` (`RacinG_Portal`,
`PaDoNkÈ[NTL]`, `Fristaile`), `Df1` (вероятно НЕ трогать — западные).
2. **Строки `no_change` (~1100) — последний непроверенный пласт.**
3. Затем бэкап в `Music/backup/` и применение (по «go» Alex) → приёмка в UI → Music-библиотека.
## 🔴 Четырнадцатая волна (2026-09-26): КЛАСС A ЗАКРЫТ, КЛАСС 3 НАЧАТ
### ✅ Класс A («имя техпапки в artist/album») закрыт полностью — 0 остатков