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

This commit is contained in:
Alexey Martemyanov committed 2026-09-26 20:06:18 +06:00
1 parent 8199307531
commit b00eb549bf
5 files changed
+469 -25

No files matched your search

+107 -18
View File
@@ -12,9 +12,9 @@
|---|---|---|
| 1 | `~/agents` + `~/cli-auth` + контейнер | ✅ собрано, запущено |
| 2 | Мост FastAPI :8790 | ✅ работает под launchd |
| 3 | Сеть (Cloudflare Tunnel) | ⏳ **на Alex** — CF-панель |
| 4 | Секция «Agents» в Dashboard | ✅ API + вкладка |
| 5 | Связка Балда → мост | ⏳ не начато |
| 3 | Сеть Kraken → Mac | ✅ **LAN напрямую**, туннель не нужен |
| 4 | Секция «Agents» в Dashboard | ✅ активирована и проверена |
| 5 | Связка Балда → мост | 🟡 **связка работает**, конфиг Балды ждёт переключения на `type: http` |
| 6 | Приёмка от аккаунта Alex | 🔴 блокер: авторизация CLI |
---
@@ -27,7 +27,7 @@
| 2 | Подтверждения | Full access → `permissions.mode: allow_all` |
| 3 | Управление линками в `~/agents` | Секция «Agents» в Eagle Dashboard |
| 4 | Auth CLI (claude/codex) | на хосте, `~/cli-auth`, **вне** `~/agents`; логинит **Alex вручную** |
| 5 | Сеть Kraken → Mac | Cloudflare Tunnel (существующий cloudflared на Mac) |
| 5 | Сеть Kraken → Mac | ✅ **LAN напрямую** (`http://192.168.1.57:8790`); Cloudflare Tunnel — резерв |
| 6 | Провайдер исполнителя | `claude` (дефолт в `.env`); `codex` собирается в том же образе, переключается переменной |
---
@@ -58,8 +58,11 @@ Mattermost (Alex)
Балда-оркестратор (Kraken, DeepSeek, allow_all)
│ читает Obsidian, формирует ТЗ, /goalkeeper → work → validate
▼
Cloudflare Tunnel: agents-bridge.qentra.top → localhost:8790 ⏳
│ (существующий cloudflared на Mac, PID + LaunchAgent)
MCP-сервер balda-executor-mcp (Kraken, контейнер в mattermost_mm-net) :8890
│ инструменты executor_run / executor_status / executor_health
│ HTTP + X-Bridge-Secret
▼
LAN: http://192.168.1.57:8790 ← Kraken и Mac в одной сети, туннель не нужен
▼
Мост (Mac, FastAPI :8790) — под launchd com.agents.bridge
│ idempotency key, таймаут 900 с, лимит 1 задача, shared secret
@@ -74,6 +77,8 @@ Cloudflare Tunnel: agents-bridge.qentra.top → localhost:8790 ⏳
diff + тесты + коммит → Балда → Mattermost
```
Детали MCP-сервера: [[personal/tech/balda-executor-mcp]].
### Auth CLI на хосте
| Данные | Хост | В контейнере | Права |
@@ -97,14 +102,22 @@ diff + тесты + коммит → Балда → Mattermost
| `~/Docker/balda-executor/agents-mounts.yaml` | манифест внешних проектов |
| `~/Docker/balda-executor/tools/render-mounts.py` | манифест → `compose.override.yaml` |
| `~/Developer/agents-bridge/` | мост: `app.py`, `store.py`, `executor.py`, `config.py` |
| `~/Library/LaunchAgents/com.agents.bridge.plist` | автозапуск + KeepAlive |
| `~/Library/LaunchAgents/com.agents.bridge.plist` | автозапуск + KeepAlive, `--host 0.0.0.0` |
| `~/Developer/eagle-dash/agents.py` | роутер секции «Agents» |
| `~/Developer/balda-executor-mcp/` | MCP-сервер: `server.py`, `Dockerfile`, `docker-compose.yml` |
| `/home/kraken/mcp/docker-compose.yml` (Kraken) | запуск контейнера MCP |
**Известные питфоллы (пройдены):**
- `docker compose` в этом окружении **отсутствует** — только `docker-compose` (v5.1.3);
- `docker compose` на Mac **отсутствует** — только `docker-compose` (v5.1.3);
**на Kraken наоборот**: `docker compose`, а `docker-compose` → `command not found`;
- `compose.override.yaml` обязателен при старте, иначе `up` падает на монтировании;
- компайл: `node:24-bookworm` вместо `scratch` (CA-сертификаты — иначе TLS-фейл);
- `psutil` не установлен в venv дашборда → supervisor не может трекать мост по PID; health для моста — `type: http`.
- образ исполнителя: `node:24-bookworm` вместо `scratch` (CA-сертификаты — иначе TLS-фейл);
- `psutil` не установлен в venv дашборда → supervisor не может трекать мост по PID; health для моста — `type: http`;
- `--host` берётся из `ProgramArguments` plist, **`.env` его не перебивает**;
смена аргументов требует `bootout`+`bootstrap`, не `kickstart`;
- образ Балды из `scratch`: **нет shell**, `docker exec … sh` не работает;
`docker.sock` в контейнер Балды **не смонтирован** → `docker run` изнутри невозможен;
- на Kraken в sshd `AllowTcpForwarding no` → обратный SSH-туннель поставить нельзя.
---
@@ -177,13 +190,62 @@ diff + тесты + коммит → Балда → Mattermost
---
## 7. Сеть (шаг 3) — на Alex
## 7. Сеть Kraken → Mac — ✅ РЕШЕНО, туннель НЕ нужен
Cloudflare Tunnel: добавить published route `agents-bridge.qentra.top` → HTTP `localhost:8790` +
Access Application. Токен и процесс cloudflared не трогаются.
⚠️ hostname — **одноуровневый** (двухуровневые дают TLS handshake failure).
### Итог: обычный HTTP по локальной сети
Проверка после настройки: `curl https://agents-bridge.qentra.top/healthz`.
Kraken и Mac **стоят в одной LAN и видят друг друга напрямую** — проверено
`ping` с Kraken на `192.168.1.57` (RTT ~2.4 мс, 0% потерь). Никакой туннель,
никакой проброс и никакая Access Application не нужны.
```
BRIDGE_URL=http://192.168.1.57:8790
```
Проверки, подтвердившие связь:
| Проверка | Результат |
|---|---|
| `ping` Kraken → `192.168.1.57` | 2/2, RTT 2.4 мс ✅ |
| `curl` с Kraken на `:8790/healthz` | `status: ok` ✅ |
| `curl` из контейнера в `mattermost_mm-net` на `:8790/healthz` | `status: ok` ✅ |
### Что НЕ сработало и почему (чтобы не повторять)
| Путь | Почему отпал |
|---|---|
| Cloudflare Tunnel (`agents-bridge.qentra.top`) | Требует правки маршрута в CF-панели — ручная работа Alex, а LAN работала сразу. Остаётся резервным вариантом, если Mac уедет из этой сети |
| Обратный SSH-туннель (`ssh -R`) | 🔴 **На Kraken в sshd стоит `AllowTcpForwarding no`.** Симптом: `Error: remote port forwarding failed for listen port 18790`, в verbose — `debug1: Remote: Server has disabled port forwarding.` Не диагностировать как «порт занят»: порт свободен, форвард выключен администратором |
📌 Если понадобится туннель в будущем — сначала проверить `AllowTcpForwarding` на Kraken,
потом уже ставить форвард. Cloudflare Tunnel этот запрет обходит (исходящее соединение,
не SSH-форвард).
### Мост теперь слушает всю сеть — это осознанное изменение
| Было | Стало | Почему |
|---|---|---|
| `BRIDGE_HOST=127.0.0.1` | `BRIDGE_HOST=0.0.0.0` | иначе Kraken не достучится |
⚠️ **Порт 8790 теперь открыт в локальной сети.** Защита — `X-Bridge-Secret` (обязателен,
иначе `POST /task` отдаёт 503). При уходе Mac в недоверенную сеть — вернуть `127.0.0.1`
и поднимать туннель.
🔴 **Питфолл: `.env` не перебивает plist.** Я поменял `BRIDGE_HOST` в `.env`, но мост
продолжал слушать `127.0.0.1` — потому что `--host` **жёстко задан в `ProgramArguments`**
plist. Симптом: `lsof` показывает `127.0.0.1:8790` после «перезапуска с новым конфигом».
Исправлять надо **в plist**, а не в `.env`.
```bash
# применить: правка plist → перезагрузка сервиса (не kickstart!)
launchctl bootout gui/$(id -u)/com.agents.bridge
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.agents.bridge.plist
# проверка: должно быть *:8790, а не 127.0.0.1:8790
lsof -nP -iTCP:8790 -sTCP:LISTEN
```
`kickstart` перечитывает только программу, но **не** изменённый `ProgramArguments` —
для смены аргументов нужен `bootout` + `bootstrap`.
---
@@ -201,14 +263,41 @@ Access Application. Токен и процесс cloudflared не трогают
## 9. Открыто
1. Cloudflare Tunnel (шаг 3) — нужен доступ к CF-панели
2. Связка Балда → мост (шаг 5) — MCP-инструмент
3. Логин CLI (Alex вручную) — без него сквозная приёмка невозможна
1. **Переключить конфиг Балды на HTTP-MCP** — сейчас там stdio-вариант с `docker run`,
который не может работать (нет `docker.sock` и нет shell в образе Балды).
Нужен `type: http` → `http://balda-executor-mcp:8890/mcp`. См. [[personal/tech/balda-executor-mcp]] §7.
2. Проверить, что инструменты видны в сессии Балды (после перезапуска).
3. Логин CLI (Alex вручную) — без него сквозная приёмка невозможна.
4. Cloudflare Tunnel — **не нужен** на текущей схеме; держать как резерв, если Mac
уедет из LAN.
## 10. Шаг 5 — связка Балда → мост (что сделано 2026-09-26)
| Компонент | Где | Статус |
|---|---|---|
| MCP-сервер `balda-executor-mcp` | `~/Developer/balda-executor-mcp/` | ✅ код + образ |
| Образ | `balda-executor-mcp:0.1.0`, загружен на Kraken | ✅ |
| Контейнер MCP | Kraken, `/home/kraken/mcp/docker-compose.yml` | ✅ Up |
| Конфиг Балды | `runtime.mcp_servers.executor-mcp` + `balda.mcp_servers` | 🟡 ждёт `type: http` |
| `.env` Балды | `+ BRIDGE_URL`, `+ BRIDGE_SECRET` | ✅ |
Бэкапы на Kraken: `config.yaml.bak-mcp-20260926-194313`, `.env.bak-mcp-*`, `.env.bak-url-*`.
Проверено живьём: MCP-handshake (stdio и HTTP), `tools/list` с 3 инструментами,
`executor_health` из docker-сети Kraken вернул живые данные моста на Mac,
Балда после правки конфига стартовала без ошибок.
📌 **Ключевой вывод по архитектуре:** MCP-сервер обязан быть **отдельным контейнером
с HTTP-транспортом**. Вариант «stdio + `docker run` изнутри Балды» нерабочий:
в образе Балды нет shell и не смонтирован `docker.sock`.
## Связанные заметки
- [[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/balda-executor-mcp]] — MCP-сервер делегирования (шаг 5)
- [[personal/tech/agents-bridge]] — мост :8790 (шаг 2)
- [[personal/tech/eagle-dashboard-agents-tab]] — секция «Agents» в дашборде (шаг 4)
- [[personal/tech/macos-docker-virtiofs-mount-limits]] — ограничения macOS Docker
- [[personal/tech/balda-go-fx-pitfalls]] — fx-питфоллы, дельта-апплаер
- [[family/how-to/kraken-portainer-access]] — cloudflared, routes
+33 -5
View File
@@ -73,7 +73,7 @@ GET /tasks?limit=N → последние задачи (для дашбор
| Ключ | Дефолт | Смысл |
|---|---|---|
| `BRIDGE_HOST` | `127.0.0.1` | слушать только локально (наружу — через туннель) |
| `BRIDGE_HOST` | `0.0.0.0` | слушать всю LAN (Kraken ходит по LAN). Было `127.0.0.1` |
| `BRIDGE_PORT` | `8790` | порт |
| `BRIDGE_SECRET` | — | **обязателен**, 64 симв. `secrets.token_urlsafe(48)` |
| `EXECUTOR_CONTAINER` | `balda-executor` | имя контейнера |
@@ -93,7 +93,7 @@ GET /tasks?limit=N → последние задачи (для дашбор
|---|---|
| Label | `com.agents.bridge` |
| Plist | `~/Library/LaunchAgents/com.agents.bridge.plist` |
| Program | `~/Developer/eagle-dash/.venv/bin/python -m uvicorn app:app --host 127.0.0.1 --port 8790` |
| Program | `~/Developer/eagle-dash/.venv/bin/python -m uvicorn app:app --host 0.0.0.0 --port 8790` |
| WorkingDirectory | `/Users/admin/Developer/agents-bridge` |
| `RunAtLoad` / `KeepAlive` | `true` / `true` |
| Логи | `~/Library/Logs/agents-bridge.log` (+ `.err.log`) |
@@ -166,10 +166,30 @@ auth-файлов из `~/.claude`/`~/.codex` отклонено, не пред
`EnvironmentVariables.PATH` с `/opt/homebrew/bin` первым. Симптом без него:
`docker не найден в PATH процесса моста` в `stderr` задачи.
### 6. Мост слушает только `127.0.0.1`
### 6. Мост слушает `0.0.0.0` — изменение 2026-09-26
`BRIDGE_HOST=127.0.0.1` — намеренно. Наружу выставляется туннелем (шаг 3), не пробросом
порта. Не менять на `0.0.0.0` без Access Application на стороне Cloudflare.
**Было:** `BRIDGE_HOST=127.0.0.1` («наружу — через туннель»).
**Стало:** `0.0.0.0` — иначе Kraken не достучится по LAN.
Причина: Kraken и Mac в одной сети, `ping` 2.4 мс. Туннель не нужен (см.
[[personal/plans/balda-mm-phase4-agents]] §7). Kraken обращается к
`http://192.168.1.57:8790`.
⚠️ Порт 8790 теперь открыт в LAN. Защита — `X-Bridge-Secret` (без него `POST /task` → 503).
Уходя в недоверенную сеть — вернуть `127.0.0.1` и поднимать туннель.
🔴 **`--host` задаётся в plist, `.env` его НЕ перебивает.** Симптом: поменял `.env`,
перезапустил — `lsof` всё равно показывает `127.0.0.1:8790`. Правка — в
`ProgramArguments` plist. И применять через `bootout` + `bootstrap` (не `kickstart`).
### 7. Обратный SSH-туннель на Kraken невозможен
`ssh -R` падает: `Error: remote port forwarding failed for listen port 18790`,
в verbose — `debug1: Remote: Server has disabled port forwarding.`
Причина: на Kraken в sshd `AllowTcpForwarding no`. Не путать с «порт занят» —
порт свободен, форвард выключен администратором. Обход — Cloudflare Tunnel
(исходящее соединение, не SSH-форвард).
---
@@ -191,6 +211,7 @@ curl -s -o /dev/null -w "%{http_code}\n" -X POST http://127.0.0.1:8790/task \
## Связанное
- [[personal/plans/balda-mm-phase4-agents]] — план Фазы 4 (шаги 1-2 ✅)
- [[personal/tech/balda-executor-mcp]] — MCP-сервер, который ходит в этот мост
- [[personal/tech/macos-docker-virtiofs-mount-limits]] — почему bind-mount вместо symlink
- [[personal/projects/balda/balda-mm-delegation-plan]] — общий план делегирования
- `~/Developer/agents-bridge` — код моста
@@ -201,3 +222,10 @@ curl -s -o /dev/null -w "%{http_code}\n" -X POST http://127.0.0.1:8790/task \
- **2026-09-26** (продолжение): переведён под launchd (`com.agents.bridge`,
`RunAtLoad` + `KeepAlive`, pid 3063), добавлен `EnvironmentVariables.PATH`.
Шаг 3 разблокирован; проверка `KeepAlive` при падении не выполнена (отклонён `kill -9`).
- **2026-09-26** (шаг 5): `BRIDGE_HOST` → `0.0.0.0` (в plist, не в `.env`),
сервис переставлен через `bootout`+`bootstrap`. Проверено с Kraken: `curl` с хоста и
из контейнера в `mattermost_mm-net` дают `status: ok`. Туннель не потребовался —
Kraken и Mac в одной LAN. Обратный SSH-туннель на Kraken невозможен
(`AllowTcpForwarding no`).
- **2026-09-26** (MCP): `executor_health` из контейнера `balda-executor-mcp`
(docker-сеть Kraken) вернул живые данные моста — связка Kraken→Mac работает.
+190
View File
@@ -0,0 +1,190 @@
# balda-executor-mcp — MCP-сервер делегирования задач (шаг 5 Фазы 4)
> Создан 2026-09-26. Шаг 5 плана [[personal/plans/balda-mm-phase4-agents]].
> Статус: **собран, задеплоен на Kraken, связка проверена до последнего звена**;
> конфиг Балды ещё указывает на stdio-вариант — требует переключения на `type: http`.
> Связка: Балда (Kraken) → MCP → мост (Mac :8790) → контейнер-исполнитель.
---
## 1. Зачем отдельный MCP-сервер
Балда **не может** сама запустить CLI на Mac: Mac за NAT, а `runtime.mcp_servers` —
это либо stdio-процесс внутри контейнера Балды, либо HTTP по сети.
Схема выбрана такая:
```
Балда (Kraken, контейнер balda-mm)
│ runtime.mcp_servers.executor-mcp
▼
MCP-сервер balda-executor-mcp (Kraken, контейнер в mattermost_mm-net) ← HTTP
│ X-Bridge-Secret
▼
мост agents-bridge (Mac, 192.168.1.57:8790) ← обычный HTTP по LAN
│ docker exec
▼
контейнер balda-executor (Mac) → CLI claude/codex
```
---
## 2. Расположение и файлы
| Что | Путь |
|---|---|
| Проект | `~/Developer/balda-executor-mcp/` |
| Сервер | `server.py` (stdio + HTTP в одном файле) |
| Образ | `balda-executor-mcp:0.1.0` (python:3.12-slim-bookworm) |
| Dockerfile | `~/Developer/balda-executor-mcp/Dockerfile` |
| Compose (Kraken) | `/home/kraken/mcp/docker-compose.yml` |
| Контейнер на Kraken | `balda-executor-mcp` (сеть `mattermost_mm-net`) |
| Порядковый порт | `:8890` внутри docker-сети, **наружу не публикуется** |
---
## 3. Инструменты MCP
| Инструмент | Аргументы | Что делает |
|---|---|---|
| `executor_run` | `prompt` (обяз.), `provider?` (`claude`/`codex`), `idempotency_key?` | ставит задачу, возвращает `task_id` немедленно |
| `executor_status` | `task_id` | статус + stdout/stderr/exit_code |
| `executor_health` | — | живость моста и контейнера-исполнителя |
Ошибки возвращаются как `isError: true` с человеческим текстом:
- 429 → «Исполнитель занят (лимит одновременных задач)»
- 404 → «задача … не найдена»
- прочие → «мост вернул N: …»
---
## 4. Переменные окружения
| Ключ | Смысл |
|---|---|
| `BRIDGE_URL` | базовый URL моста (например `http://192.168.1.57:8790`) |
| `BRIDGE_SECRET` | общий секрет, уходит в `X-Bridge-Secret` |
| `BRIDGE_TIMEOUT` | таймаут обычных вызовов (по умолчанию 60 с) |
| `MCP_HOST` / `MCP_PORT` | адрес HTTP-режима (по умолчанию `127.0.0.1:8890`) |
---
## 5. Два режима запуска
```bash
# stdio (Балда сама запускает процесс)
python3 server.py
# HTTP (отдельный контейнер, Балда ходит по URL)
python3 server.py --http --host 0.0.0.0 --port 8890
```
⚠️ **Использовать надо HTTP-режим.** Причины — §7.
---
## 6. Приёмка (2026-09-26) — что именно проверено
| Проверка | Результат |
|---|---|
| stdio: `initialize` → `tools/list` | 3 инструмента возвращены ✅ |
| stdio: `tools/call` health | живые данные моста ✅ |
| stdio: 429 / 500 / 404 | корректные `isError` с текстом ✅ |
| образ: тот же handshake внутри контейнера | ✅ |
| образ на Kraken: загрузка | `Loaded image: balda-executor-mcp:0.1.0` ✅ |
| Kraken → мост по LAN (curl из docker-сети) | `status: ok` ✅ |
| MCP в docker-сети → `executor_health` через мост | живые данные Mac ✅ |
| контейнер `balda-executor-mcp` | Up ✅ |
Тестовые скрипты: `/tmp/test-mcp-server.sh` (мок моста + stdio-проба),
`/tmp/kraken-test-mcp.sh` (ручной handshake из docker-сети Kraken).
---
## 7. 🔴 Питфолл: stdio-вариант нерабочий в этом окружении
Изначальный план был `type: stdio` + `cmd: ["docker", "run", ...]` — то есть Балда
сама запускает MCP-контейнер. **Это не работает по двум причинам:**
1. **`docker.sock` в контейнер Балды не смонтирован.** Проверено:
`docker inspect balda-mm` даёт только три тома (config/state/workspace) — сокета нет.
Значит `docker run` изнутри Балды невозможен.
2. **В образе Балды нет shell.** `docker exec balda-mm sh -c ...` →
`OCI runtime exec failed: exec: "sh": executable file not found in $PATH`
(образ из `scratch`). Отладка и запуск подпроцессов через shell недоступны.
**Решение:** MCP-сервер вынести в **отдельный контейнер** с HTTP-транспортом.
Конфиг Балды тогда:
```yaml
runtime:
mcp_servers:
executor-mcp:
type: http
url: "http://balda-executor-mcp:8890/mcp"
balda:
mcp_servers:
- executor-mcp
```
---
## 8. 🔴 Питфолл: `--chmod=644` для файла, запускаемого не-root
Dockerfile изначально делал `COPY server.py /app/server.py` + `USER mcpsvc` → при
запуске: `python3: can't open file '/app/server.py': [Errno 13] Permission denied`.
Фикс: `COPY --chmod=644 server.py /app/server.py`. Не-root пользователь должен уметь
**читать** код, иначе контейнер падает ещё до handshake.
Симптом обманчив — выглядит как поломка образа, а не как права файла.
---
## 9. Питфолл: `docker-compose` на Mac, `docker compose` на Kraken
| Хост | Как вызывать |
|---|---|
| Mac (Colima) | **`docker-compose`** (v5.1.3, отдельный бинарь) |
| Kraken | **`docker compose`** (плагин v5.1.3); `docker-compose` → `command not found` |
Одна и та же версия, но на разных хостах **разный способ вызова**. Скрипты деплоя
для двух хостов нельзя копировать без правки этой строки.
---
## 10. HTTP-transport: ручная проба (streamable)
```bash
docker run --rm --network mattermost_mm-net curlimages/curl:latest \
-s --max-time 10 -X POST http://balda-executor-mcp:8890/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"0"}}}' -i
```
⚠️ Заголовок `Accept: text/event-stream` **обязателен** — сервер отвечает SSE.
Без него — отказ. Ответ отдаётся как `event: message\ndata: {...}`.
`GET /healthz` у MCP-сервера отдаёт `{"status":"ok","bridge_url":...,"secret_set":true}`.
---
## 11. Что осталось
1. **Переключить `runtime.mcp_servers.executor-mcp` на `type: http`** (сейчас там stdio-вариант с `docker run`).
2. Перезапустить Балду, убедиться, что инструменты видны в сессии.
3. Сквозная приёмка: `executor_run` из чата → задача на Mac → результат.
4. Логин CLI внутри `balda-executor` — делает **Alex вручную**.
---
## Связанное
- [[personal/plans/balda-mm-phase4-agents]] — план Фазы 4 (шаг 5)
- [[personal/tech/agents-bridge]] — мост :8790, к которому ходит этот MCP
- [[personal/projects/balda/balda-kraken-mm-deploy]] — деплой Балды на Kraken (конфиг, `.env`, сети)
- [[personal/tech/macos-docker-virtiofs-mount-limits]] — ограничения macOS Docker
- `~/Developer/balda-executor-mcp` — код
- скилл `native-mcp` — handshake streamable-http, питфоллы
+75
View File
@@ -0,0 +1,75 @@
---
title: Music Tags — сводки для финального аппрува
created: '2026-09-26'
updated: '2026-09-26'
type: tech
namespace: personal
tags:
- music
- jellyfin
- metadata
- approval
related:
- '[[personal/tech/music-tags-repair-truenas]]'
- '[[family/how-to/jellyfin-config]]'
---
# Чистка тегов Music: сводки для финального аппрува
_Обновлено: 2026-09-26. Источник: `~/Downloads/music-tags/tag-fix-plan.csv`._
> ⚠️ **Статус: НЕ ФИНАЛЬНЫЙ аппрув.** Блок строк 6402–7906 (1505 строк, ~19%) прочитан
> скриптами, но НЕ глазами. См. «Что НЕ покрыто». Полный контекст волн —
> `personal/tech/music-tags-repair-truenas.md`.
## Состав файлов
| Файл | Строк | Что это |
|---|---|---|
| `tag-fix-plan.csv` | 7906 | Главный план правок, 11 колонок |
| `artists-single-track.csv` | 3223 | Разбивка: треки БЕЗ номера (artist/title/album/path) |
| `artists-multi-track.csv` | 4667 | Разбивка: треки С номером (artist/album/track/title/path) |
| | **7890** | = сумма сводок (16 строк отфильтрованы: AppleDouble + skip) |
## Действия
| action | строк | смысл |
|---|---|---|
| `fix` | 6934 | теги будут перезаписаны |
| `no_change` | 957 | теги корректны, файл не трогаем |
| `skip` | 15 | AppleDouble-мусор `._*`, не трогаем |
## Источник правки (`source`)
| строк | источник |
|---|---|
| 3173 | номер трека из имени файла |
| 1384 | title из имени файла |
| 1311 | **ручное решение (user decision)** |
| 756 | только кодировка/очистка |
| 882 | (пусто — правка не требуется) |
## Проверки перед аппрувом
- 0 битых строк (все 11 колонок на месте), 0 разъехавшихся запятыми
- 0 пустых `new_title` среди `fix`
- 0 сайтов-водяных знаков в `new_title`/`new_artist`/`new_album`
- 0 нечисловых номеров треков
- 0 дублей-артистов (регистр/ё/латиница-кириллица), кроме сведённых
- 577 строк без artist — из них **562 это `!Детские/Сказки`** (artist пуст намеренно)
## Приёмка (глазами)
1. Открой `artists-single-track.csv` — треки без номера, отсортированы по артисту
2. Открой `artists-multi-track.csv` — альбомы с нумерацией
3. Найди свой артист, проверь названия
4. Скажи «go» → бэкап в `Music/backup/` → применение → приёмка в UI Jellyfin
## Что НЕ покрыто
Блок **строк 6402-7906** главного файла разобран скриптами (кодировка, номера, album из папки),
но **не прочитан построчно глазами**. Крупные артисты блока: Агата Кристи (244), ДДТ (205),
Rammstein (134), Би-2 (128), Ночные Снайперы (96), Muse (91), Пикник (69), Захар Май (67),
Ундервуд (66), Чиж & Со (63).
Отдельные «не определить без прослушивания»: `ty_49` (`!Radio/y OOF/пакет.mp3`).
+64 -2
View File
@@ -4,7 +4,7 @@ created: '2026-09-26'
updated: '2026-09-26'
type: tech
namespace: personal
wave: 25
wave: 26
tags:
- music
- jellyfin
@@ -20,7 +20,69 @@ related:
# Music Tags Repair — TrueNAS (7906 файлов)
> **Статус: ДВАДЦАТЬ ПЯТАЯ ВОЛНА (2026-09-26). ИДЁТ РУЧНОЕ ЧТЕНИЕ ПО ВСЕМУ СПИСКУ.**
> **Статус: ДВАДЦАТЬ ШЕСТАЯ ВОЛНА (2026-09-26). ПРОЧИТАНО ПОСТРОЧНО 2402–6401 ИЗ 7906 (~81%).**
> Продолжение требования Alex: «Проходить весь список руками и валидировать» + «Хули встал»
> (без пауз). В этой волне закрыты блоки **2402–6401** (11 блоков по 200 строк).
>
> ✅ **НОВОЕ (26-я волна) — построчное чтение 2402–6401.** ~230 правок, найденное детекторами
> НЕ ловится:
> | Класс | Строк | Скрипт | Результат |
> |---|---|---|---|
> | Трофим: транслит-титулы из имён файлов (`#1 10 Aristokratiya pomoyki`) | **58** | `fix_trofim.py` | → кириллица; album `Война и мр`→`Война и мир` |
> | Трофим: album-плейсхолдеры `#1`…`#9` | ~30 | `fix_block3000.py` | раскрыты в реальные альбомы (`Аристократия помойки 1`…`Бард-Авангард`) |
> | АК-47: артист в title (`Витя АК & Tip - Грубо говоря`) | 19 | `fix_block2600.py` | артист-префикс срезан |
> | Eminem: split `title='Shop'`+`artist='Candy'`; `Mile`→`8 Mile` | 3 | `fix_block2600.py` | восстановлено |
> | NTL / `!Radio`: префикс `NTL - ` в title | ~15 | `fix_block2800.py` | срезан |
> | `!Radio`: битые префиксы `ÿþ` (DOS-кириллица), мусор `NN Track NN` в artist, сайт `WAP.BITMOB.RU` | ~15 | `fix_block3200.py` | вычищено |
> | Savant: опечатки в `new_album` (`Unrelesed`) → `Unreleased`; `Bit Lightsaber`→`8-Bit Lightsaber`; `Prorophecy`→`Prophecy`; `Clssical`→`Classical` | ~8 | `fix_block3800/4200.py` | исправлено |
> | Банд'Эрос / Потап / Серёга: артист в title (`Серега - Кружим`); `Загубиги`→`Загубили` | 7 | `fix_block4400.py` | исправлено |
> | Пилот: `Илья Черт`→`Илья Чёрт`; `Осеннее пора`→`Осенняя`; 4-точечные многоточия; `Тецкатлипокa` (латинская `a`); Prodigy-плейсхолдеры `2002 - Babyes Got a temper N`→`Baby's Got a Temper` | **93** | `fix_block4600/4800.py` | исправлено |
> | Звери / Земфира: `для тебя`→`Для тебя`; Меамуры транслит (`stekla`,`V reis`,`na udachu`,`Glubzhe`); album `Земфира ()`→`Земфира (2000)`; `Земфира Рамазанова`→`Земфира` | 16 | `fix_block5000/5200.py` | исправлено |
> | Кукрыниксы: полный транслит (`Kukriniksi - 01 Stolknovenie - Serebrianii sentiabr`) | 12 | `fix_block5400.py` | → кириллица |
> | Ногу Свело!: **регрессия** — album `Второй Магаданский` разъехался на 4 варианта; `Исскуство`→`Искусство`; `Французкая`→`Французская` | 24 | `fix_block5800.py` | сведено к одному |
> | The Used: track все `9` (из `3-9 - Title`); `Geschchte`→`Geschichte`; `ПаникА Киев` split | 11 | `fix_block6200.py` | исправлено |
> | AppleDouble `._МИМИКРИЯ.MP3` → `action=skip` | 1 | `fix_block5600.py` | помечено |
>
> 🔴 **ГЛАВНЫЙ ДЕФЕКТ, НАЙДЕННЫЙ ФИНАЛЬНЫМ АУДИТОМ (26-я волна):** строка **3498** разъехалась
> на **12+ полей** — незакавыченная запятая в пути `/!Pop, Club, Любэ/` склеила путь с title,
> `new_artist` и `new_track` поменялись местами (`new_track='DJ Иван Silver & Сява'`).
> Починено `fix_final.py`. **Это 4-й случай повреждения строки запятой в пути** — паттерн
> `!Pop, Club, Любэ/` опасен, проверять его в первую очередь.
>
> 🛠 **Финальные аудиты (read-only, гонять перед «готово»):**
> - `final_audit.py` — воронка: кол-во строк/колонок/битых, `action`, заполненность полей,
> сайты-водяные знаки, нечисловые `new_track`, разбор пустых artist по папкам,
> near-duplicates артистов (регистр/ё/латиница-кириллица).
> - Нашёл и починил: `Fever // By Maddalinio //`→`Fever`; album `Best-Mp3.Ru`→пусто;
> `Муммий Троль / Медведица (Dj Ivan Scratchin T` → `Медведица (DJ Ivan Scratchin Trance Mix)`;
> `YOJI Biomehanika`→`Yoji Biomehanika`.
>
> 📊 **ФИНАЛЬНОЕ СОСТОЯНИЕ (26-я волна):**
> | Показатель | Значение |
> |---|---:|
> | Строк в `tag-fix-plan.csv` | 7906 (+голова = 7907), **0 битых** |
> | `fix` / `no_change` / `skip` | **6934 / 957 / 15** |
> | Пустых `new_title` среди `fix` | **0** |
> | Сайтов-воды в `new_*/` | **0** |
> | Нечисловых `new_track` | **0** |
> | Групп дублей артистов | **0** |
> | Строк без artist | **577** (562 = `!Детские`, намеренно) |
> | Сводные CSV | `artists-single-track.csv` **3223** + `artists-multi-track.csv` **4667** = **7890** |
>
> ⚠️ **НЕ ГОТОВ:** блок **6402–7906 (1505 строк, ~19%)** разобран скриптами, но **построчно
> глазами НЕ читался**. Крупные артисты блока: Агата Кристи (244), ДДТ (205), Rammstein (134),
> Би-2 (128), Ночные Снайперы (96), Muse (91), Пикник (69), Захар Май (67), Ундервуд (66),
> Чиж & Со (63), Несчастный случай (53), Краденое Солнце (48), Knorkator (12).
> ⏭ **ГДЕ ПРОДОЛЖАТЬ: со строки 6402.** Порядок: `read_file` блоками по 200 → править →
> `python3 final_audit.py` → `cp bak-$(date +%H%M%S)-<tag>` перед каждым скриптом.
>
> 📄 Сводка для аппрува Alex: `personal/tech/music-tags-final-review.md`.
> **Бэкапы 26-й волны:** `bak-*-trofim`, `bak-*-blk2600/2800/3000/3200/3400/3600/3800/4000/4200/`
> `4600/4800/5000/5200/5400/5600/5800/6000/6200`, `bak-*-presummary`, `bak-*-final`, `bak-*-yoji`.
>
> ---
>
> **Статус предыдущей волны: ДВАДЦАТЬ ПЯТАЯ (2026-09-26). Прочитаны и вычищены строки 1–1401.**
> Alex потребовал: «Проходить весь список руками и валидировать» (после 3 отказов принять
> «всё готово»). Работа в процессе: **прочитаны и вычищены строки 1–1401 из 7906 (~18%)**.
> CSV: 7906 строк, 0 битых, 0 дублей артистов, 0 год-префиксов/плейсхолдеров/сайтов.