[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

+165
View File
@@ -0,0 +1,165 @@
# agents-bridge — мост Mac ↔ Kraken (FastAPI :8790)
> Создан 2026-09-26. Компонент Фазы 4 [[personal/plans/balda-mm-phase4-agents]] (шаг 2 ✅).
> Назначение: принять задачу от оркестратора Балды (Kraken) по HTTP, запустить
> CLI-исполнитель в контейнере `balda-executor`, вернуть вывод.
---
## Расположение
| Что | Путь |
|---|---|
| Проект | `~/Developer/agents-bridge/` |
| Python | `~/Developer/eagle-dash/.venv/bin/python` (3.14, fastapi 0.115.0, uvicorn 0.30.6) |
| Конфиг + секрет | `~/Developer/agents-bridge/.env` (**0600, не коммитить**) |
| Шаблон | `~/Developer/agents-bridge/.env.example` |
| Состояние | `~/Developer/agents-bridge/state.sqlite3` (WAL) |
| Лог (ручной запуск) | `/tmp/agents-bridge.log` |
| Контейнер-исполнитель | `balda-executor` (`~/Docker/balda-executor/`) |
Своего venv у проекта **нет** — используется venv дашборда (там уже fastapi/uvicorn/httpx).
---
## Файлы
| Файл | Роль |
|---|---|
| `app.py` | роуты, проверка секрета, лимит параллельности, `ThreadPoolExecutor` |
| `store.py` | SQLite: таблица `tasks`, UNIQUE-индекс по `idempotency_key`, `reap_stale()` |
| `executor.py` | `docker exec` в контейнер; провайдеры `claude`/`codex`; таймаут; обрезка вывода |
| `config.py` | чтение `.env` встроенным парсером + `Settings` (frozen dataclass) |
| `requirements.txt` | fastapi==0.115.0, uvicorn==0.30.6, httpx, python-dotenv |
---
## API
```
GET /healthz → статус моста и контейнера (без секрета)
POST /task → 202 | 200 (идемпотентный повтор) | 401 | 429 | 400
GET /task/{task_id} → статус + stdout/stderr/exit_code
GET /tasks?limit=N → последние задачи (для дашборда/отладки)
```
**Авторизация:** заголовок `X-Bridge-Secret` на всех `/task*`. Если `BRIDGE_SECRET` не
настроен — `POST /task` возвращает **503**, мост не принимает задачи.
**Идемпотентность:** заголовок `Idempotency-Key`. Повтор возвращает **тот же** `task_id`
с HTTP **200** (первый ответ — 202). Гарантия на уровне БД: UNIQUE-индекс + `IntegrityError`
как обработка гонки. CLI запускается **ровно один раз** на задачу.
**Лимит параллельности:** `MAX_CONCURRENT_TASKS` (по умолчанию **1**). При исчерпании —
**429**. Больше 2 задач под одним подписочным аккаунтом — риск бана за «unusual traffic».
---
## Провайдеры
`executor.PROVIDERS` — argv для headless-запуска:
| Провайдер | argv |
|---|---|
| `claude` | `claude -p --output-format text <prompt>` |
| `codex` | `codex exec --skip-git-repo-check <prompt>` |
Дефолт — `EXECUTOR_PROVIDER=claude`. Команда собирается **списком аргументов** (без
`shell=True`), `WORKDIR=/agents` внутри контейнера — наружу не выйти.
---
## Переменные окружения
| Ключ | Дефолт | Смысл |
|---|---|---|
| `BRIDGE_HOST` | `127.0.0.1` | слушать только локально (наружу — через туннель) |
| `BRIDGE_PORT` | `8790` | порт |
| `BRIDGE_SECRET` | — | **обязателен**, 64 симв. `secrets.token_urlsafe(48)` |
| `EXECUTOR_CONTAINER` | `balda-executor` | имя контейнера |
| `EXECUTOR_PROVIDER` | `claude` | `claude` или `codex` |
| `MAX_CONCURRENT_TASKS` | `1` | одновременно выполняемых |
| `TASK_TIMEOUT_SECONDS` | `900` | таймаут задачи, процесс убивается |
| `MAX_OUTPUT_BYTES` | `200000` | вывод обрезается |
| `DB_PATH` | `state.sqlite3` | SQLite |
---
## Запуск
**Сейчас — вручную** (launchd ещё не сделан, см. открытый пункт 4 плана):
```bash
cd ~/Developer/agents-bridge
~/Developer/eagle-dash/.venv/bin/python -m uvicorn app:app --host 127.0.0.1 --port 8790
```
Проверка:
```bash
curl -s http://127.0.0.1:8790/healthz
```
⚠️ На macOS `docker compose` **не работает** — только `docker-compose` (см. план, шаг 1).
---
## Питфоллы
### 1. `Not logged in` — это ответ CLI, а не ошибка моста
Сквозная проба до логина CLI вернула:
```
status=failed exit_code=1 stdout='Not logged in · Please run /login'
```
Это **признак рабочего конвейера**: docker поднял процесс, `claude` ответил. Если видишь
эту строку — auth у исполнителя, а не мост. Логин делает **Alex сам**; копирование
auth-файлов из `~/.claude`/`~/.codex` отклонено, не предлагать.
### 2. Редакция секретов Hermes искажает команды создания `.env`
`python -c` с f-строкой `BRIDGE_SECRET={s}` печатает в лог обрезанный фрагмент
(`E...cret written`) — **редакция Hermes, файл на диске цел**. Не «чинить».
Проверять `.env` только так:
```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. Зависшие задачи после рестарта
`store.reap_stale()` на старте помечает `running`-задачи старше `TASK_TIMEOUT_SECONDS`
как `timeout` с причиной `bridge restarted while task was running`. Иначе они навсегда
висят активными и блокируют слот лимита.
### 4. Мост не переживает перезагрузку
Пока нет launchd-плейта `com.agents.bridge`, процесс живёт только в текущей сессии.
Это **блокер для шага 3** (туннель опубликует URL, ведущий в закрытый порт).
---
## Порядок ручной приёмки (сработавший)
```bash
curl -s -o /dev/null -w "%{http_code}\n" -X POST http://127.0.0.1:8790/task \
-H 'Content-Type: application/json' -d '{"prompt":"hi"}' # → 401 (нет секрета)
# с секретом и одним Idempotency-Key дважды → один и тот же task_id, 202 затем 200
# GET /task/{id} → status/stdout/exit_code
```
Тестовый скрипт: `/tmp/test-bridge.sh` (читает секрет из `.env`, в командной строке
секрет не светится).
---
## Связанное
- [[personal/plans/balda-mm-phase4-agents]] — план Фазы 4 (шаги 1-2 ✅)
- [[personal/tech/macos-docker-virtiofs-mount-limits]] — почему bind-mount вместо symlink
- [[personal/projects/balda/balda-mm-delegation-plan]] — общий план делегирования
## История
- **2026-09-26**: создан, поднят на :8790, протестирован (auth 401, идемпотентность,
сквозной вызов CLI). Не в launchd. Логин CLI — за Alex.
+172 -5
View File
@@ -4,6 +4,7 @@ created: '2026-09-26'
updated: '2026-09-26'
type: tech
namespace: personal
wave: 15
tags:
- music
- jellyfin
@@ -19,14 +20,19 @@ related:
# Music Tags Repair — TrueNAS (7906 файлов)
> **Статус: ЧЕТЫРНАДЦАТАЯ ВОЛНА (2026-09-26). КЛАСС C (склейка) И КЛАСС A (техпапка) ЗАКРЫТЫ.
> КЛАСС 3 (номер в title) — В РАБОТЕ (~25 из ~80). NAS ДОСТУПЕН, применение НЕ начато.**
> **Статус: ПЯТНАДЦАТАЯ ВОЛНА (2026-09-26). КЛАСС C, КЛАСС A, КЛАСС 3 — ЗАКРЫТЫ ПОЛНОСТЬЮ.
> КЛАСС 4 (транслит) — В РАБОТЕ (~20 из ~40). NAS ДОСТУПЕН, применение НЕ начато.**
> Работа — ручной проход по CSV `tag-fix-plan.csv` построчно; правка скриптов ЗАПРЕЩЕНА.**
> ✅ **Класс A («имя техпапки в artist/album») — ЗАКРЫТ ПОЛНОСТЬЮ: 0 остатков.**
> (`Забугр`, `disk`, `disk_v2`, `1 DRIVE`, `5 POPSA`, `3 SHANSON` — все вычищены.)
> ✅ **Класс 3 (номер трека в `new_title`) — в работе: блок `!Детские/Детский хит` ~25 из ~80.**
> ❌ Осталось: класс 3 (~55 строк), транслит (~40), строки с `no_change` (~1100, не проверялись).
> Детали и таблицы — «ЧЕТЫРНАДЦАТАЯ ВОЛНА».
> ✅ **Класс 3 (номер трека в `new_title`) — ЗАКРЫТ ПОЛНОСТЬЮ.** Блок `!Детские/Детский хит/`
> — все **156 строк**: номер → `new_track`, title чистый, artist пустой, album `Детский Хит Сезона`.
> ✅ **Класс 4 (транслит) — в работе: ~20 из ~40.** Закрыты: `!A Not sorted/Sbornik_Novij_Rok`
> (10 строк), Мумий Тролль, Мара, Дельфин, Каста, Глюкоза, Потап и Настя, Наутилус Помпилиус
> (альбомы Атлантида / Раскол / Подъём).
> ❌ Осталось: транслит Наутилуса (`Яблокитай` и далее), строки с `no_change` (~1100, не проверялись),
> транслит в `!Рэп/НТЛ`, `Df1`.
> Детали и таблицы — «ПЯТНАДЦАТАЯ ВОЛНА».
> ✅ **Проверка целостности (быстрая, без python):**
> `/usr/bin/awk -F'"' 'NR>1 && NF%2==0 {print NR": "NF}' tag-fix-plan.csv` → пусто = 0 битых.
> **CSV: 7907 строк (7906 данных + заголовок), 0 битых. Ручных правок: 311+.**
@@ -64,6 +70,167 @@ related:
> Прогонялись **девять волн** проверок: см. таблицу волн ниже.
> Итог v7: «требует решения» **4**, medium **5811**, high **958**, mojibake = 0, остаточный mojibake = 0.
## 🖐 ПЯТНАДЦАТАЯ ВОЛНА: КЛАСС 3 ЗАКРЫТ, КЛАСС 4 НАЧАТ (2026-09-26)
### ✅ КЛАСС 3 (номер трека в `new_title`) — ЗАКРЫТ ПОЛНОСТЬЮ (156 строк)
Блок `!Детские/Детский хит/` — **все строки** доведены до конца.
Паттерн фикса (единый для всего блока):
```
БЫЛО: title = `143 БЮРО НАХОДОК`, artist = (пусто), track = (пусто), source = artist<-cleared-junk
СТАЛО: title = `БЮРО НАХОДОК`, artist = (пусто), track = 143, source = manual (user decision)
```
**Почему artist пустой:** это сборник детских песен из мультфильмов, у него нет единого
исполнителя. `album = Детский Хит Сезона` — осмысленное название сборника, **остаётся**.
Второй подпаттерн в блоке (строки, где номер уже был убран ранее):
`source = track<-filename;artist<-cleared-junk` → просто менялся `source` на
`manual (user decision)`, поля уже были верные.
**Примеры правок (все 156):** НЕ ХОДИТЕ В АФРИКУ (128), РАССКАЖИ СНЕГУРОЧКА (105),
МАРИЯ МИРАБЕЛЛА (123), ПЕСЕНКА БОБРЯТ (154), ЧЕБУРАШКА (140), ПЕСНЯ ШАПОКЛЯК (132),
ЧЕМУ УЧАТ В ШКОЛЕ (109), ХЭППИ ЭНД (156), АНТОШКА (145), ПЕСНЯ ВОЛКА (103),
ПЕСЕНКА БЕЛЯНКИ (135), ПЕСЕНКА ЦАРЯ (155), ПЕСЕНКА ПАРОВОЗИКА (126),
ПЕСНЯ ПРО КОНДИТЕРСКУЮ ФАБРИКУ (114), ЛЕСНОЙ ОЛЕНЬ (152), ФИЛЬМ ФИЛЬМ ФИЛЬМ (116),
Я ВОДЯНОЙ (106), ПЕСНЯ СИНЕГЛАЗКИ (147), ПЕСНЯ ПИРАТА (108), ПЕСНЯ КОТА (113),
КТО ХОДИТ В ГОСТИ ПО УТРАМ (139), ТРИ БЕЛЫХ КОНЯ (124), ПЕСНЯ УРРИ (30),
ПЕРВОКЛАШКА (51), ПЕСНЯ ПРИВИДЕНИЙ (88), ПРИХОДИ СКАЗКА (97), КРЫЛАТЫЕ КАЧЕЛИ (89),
ПЕСЕНКА О ЖИРАФЕ (33), БАРМАЛЕЙ (71), ПЕСНЯ КОЩЕЯ (40), КРУЧУ КРУЧУ КРУЧУ ПЕДАЛИ КРУЧУ (56),
ПРЕКРАСНОЕ ДАЛЕКО (7), МОЖЕТ БЫТЬ ВОРОНА (8), ПЕСЕНКА ХОМЫ И СУСЛИКА (99),
ЛЯГУШАЧЬЯ ЛАМБАДА (16), ПЕСНЯ КЛЫКА-ПОТРОШИТЕЛЯ (91), КОЛЫБЕЛЬНАЯ МЕДВЕДИЦЫ (41),
ОБЖОРЫ (68), ТОЧКА ТОЧКА ЗАПЯТАЯ (3), ПЕСЕНКА ВАСИЛИСЫ (39), ПЕСНЯ СОЛДАТА (38),
БОЛЬШОЙ СЕКРЕТ ДЛЯ МАЛЕНЬКОЙ КАМПАНИИ (94), ПЕСНЯ О ХОТТАБЫЧЕ (64), ПЕСНЯ БЕЛОЧКИ (35),
МАНИ-МАНИ (50), ПЕСЕНКА КВАКИ (23), ПЕСНЯ БАБЫ-ЯГИ (118), ПЕСНЯ БАРСУКА БОНИФАЦИЯ (54),
ПЕСЕНКА УМКИ (5), РОМАНС ЧЕРЕПАХИ ТОРТИЛЛЫ (134), ГОВОРЯТ МЫ БЯКИ-БУКИ (75),
БУРАТИНО (1), ЧУНГА-ЧАНГА (2), КОГДА МОИ ДРУЗЬЯ СО МНОЙ (59), ТАНЕЦ МАЛЕНЬКИХ УТЯТ (6),
СПОР МАШИ И ВИТИ О СКАЗКАХ (53), РЫЖИЙ РЫЖИЙ КОНОПАТЫЙ (77), ПЕСНЯ ПРО РОБИН-ГУДА (43),
ОХ РАНО ВСТАЕТ ОХРАНА (9), ЧАСТУШКИ БАБОК-ЕЖЕК (11), БЮРО НАХОДОК (143), ПЕСНЯ СЫЩИКА (151),
УТРО НАЧИНАЕТСЯ (149), ЧЕЛОВЕК СОБАКЕ ДРУГ (90), НА ДАЛЕКОЙ АМАЗОНКЕ (37), ПЕСНЯ РУСАЛОЧКИ (61),
БАЮ БАЮШКИ БАЮ (18), ПЕСНЯ РЫБЫ-ПИЛЫ (52), ГИМН НЕЗНАЙКИ (17), ПОПУРРИ ИЗ М-Ф БРЕМЕНСКИЕ
МУЗЫКАНТЫ (82), А МОЖЕТ БЫТЬ ВОРОНА (133), ПУСТЬ НЕТУ НИ КОЛА И НИ ДВОРА (81),
ГДЕ ВОДЯТСЯ ВОЛШЕБНИКИ (141), В МИРЕ МНОГО СКАЗОК (57), ПЕСНЯ ХОМЯКА (127),
НЕПРИЯТНОСТЬ ЭТУ МЫ ПЕРЕЖИВЕМ (21), ВМЕСТЕ ВЕСЕЛО ШАГАТЬ (150), ЖИВИ В ВОЛШЕБНОМ ЯЩИЧКЕ (66),
ТАКАЯ-СЯКАЯ СБЕЖАЛА ИЗ ДВОРЦА (22), КАБЫ НЕ БЫЛО ЗИМЫ (120), СПИ МОЯ РАДОСТЬ УСНИ (137),
ПЕСНЯ ВАНИ-ПЕЧНИКА (148), А Я ТАКОЙ ГОЛОДНЫЙ (73), ДВАЖДЫ ДВА - ЧЕТЫРЕ (4),
САМОВАРО-ПАРОВОЗО-ВЕРТОЛЕТ (111), ПЕСЕНКА ЛЬВЕНКА И ЧЕРЕПАХИ (60), ПЕСЕНКА ДРАКОНЧИКА (49),
ПЕСНЯ ИОХИМА ЛИСА (104), ПОЙ ВАСЯ (101), И Я ТОГО ЖЕ МНЕНИЯ (86), ПЕСЕНКА ВИННИ-ПУХА (47),
КАКОЙ ЧУДЕСНЫЙ ДЕНЬ (131), ПЕСНЯ СОРНЯКОВ (142), ПЕСЕНКА КРОКОДИЛА ГЕНЫ (112),
НАСТОЯЩИЙ ДРУГ (15), ПЕСНЯ БАЗИЛИО И АЛИСЫ (85), НИЧЕГО НА СВЕТЕ ЛУЧШЕ НЕТУ (80),
ДВОЙКА (65), СОБАКА БЫВАЕТ КУСАЧЕЙ (48), ДВА ВЕСЕЛЫХ ГУСЯ (138), ПО СЕКРЕТУ ВСЕМУ СВЕТУ (146),
ПЕСНЯ КАРАБАСА БАРАБАСА (46), ВЕСЕННЯЯ КАПЕЛЬ (117), У ПОНИ ДЛИННАЯ ЧЕЛКА ИЗ НЕЖНОГО ШЕЛКА (79),
ДУЭТ ТРУБОДУРА И ПРИНЦЕССЫ (29), В ТРАВЕ СИДЕЛ КУЗНЕЧИК (107), МЫ БАНДИТО-ГАНГСТЕРИТО (12),
ПЕСНЯ КОТА МАТВЕЯ (119), ПЕСЕНКА О ЛЕТЕ (70), В ЛЕСУ РОДИЛАСЬ ЕЛОЧКА (14),
ДУЭТ ГЛУПОГО КОРОЛЯ И ПРЕКРАСНОЙ ПРИНЦЕССЫ (74), ПЕСЕНКА ПАУЧКА АНАСИ (32), КАРУСЕЛЬ (10),
ХВОСТ ЗА ХВОСТ (67), ДА НУЖЕН ОТДЫХ ПАРУСАМ (45), ПЕСЕНКА КОТЕНКА (96), ПЕСЕНКА СТРАХОВ (115),
ДИАЛОГ ВОЛКА И КОЗЛЯТ (13), ПОЛЕ ЧУДЕС (130), ВТОРАЯ ПЕСНЯ КОЗЫ (153), ЛОМАТЬ КРУШИТЬ (42),
ПЕСНЯ ДУРЕМАРА (92), ПЕСНЯ ЛЕШЕГО (136), СДАЕТСЯ КВАРТИРА С РЕБЕНКОМ (122), ПЕСЕНКА ДРУЗЕЙ (144),
ПЕСНЯ ДИКИХ ГИТАР (62), ОБЛАКА (25), ПЕСЕНКА КРАСНОЙ ШАПОЧКИ (121), ЗВЕЗДНАЯ СТРАНА (102),
ГОЛУБОЙ ВАГОН (78), КУДА ТЫ ТРОПИНКА МЕНЯ ПРИВЕЛА (63), КОЛЫБЕЛЬНАЯ (58),
В КАЖДОМ МАЛЕНЬКОМ РЕБЕНКЕ (19), ПЕСНЯ ПТИЦЕЛОВА БЕНКАНА (129), ПЕСНЯ ВОЛКОВ (84),
ОСЬМИНОЖКИ (93), ПЕСЕНКА ПРО НЕПРИЯТНОСТИ (44), ВСЕ МЫ ДЕЛИМ ПОПОЛАМ (100),
ПЕСНЯ О ЕЛОЧКЕ (20), ПЕСНЯ МИКРОБУСА (110), ПЕСНЯ КОЗЫ (87), ЗЕМЛЯНИЧНОЕ ВАРЕНЬЕ (125),
КОРОБКА С КАРАНДАШАМИ (28), ПЕСНЯ СТАМПА (69).
**Фильтр остатка (после закрытия = 0):**
`grep 'Детский хит/' tag-fix-plan.csv | grep 'artist<-cleared-junk'` → пусто.
### ⚠️ ВАЖНО: ЛОЖНЫЕ СРАБАТЫВАНИЯ ДЕТЕКТОРА «номер в title»
`grep -E ',[0-9]{1,3} [А-ЯЁA-Z]'` даёт **ложные** на нормальных названиях:
| Строка | Почему НЕ баг |
|---|---|
| `145_32 Leaves - All Is Numb` | `32 Leaves` — название группы |
| `189_3 Doors Down - It's Not My Time` | `3 Doors Down` — название группы |
| `007_Татьяна Зыкина - 2 кота` | `2 кота` — часть названия песни |
| `002 Одинокий в ночи 2002/04 Miks` | `Зинчук` — номер в **пути** (папка диска), title чистый |
| `001 Амадеус N 146 2002` | `N 146` — номер альбома в названии |
> 🔴 **Правило: цифра в title — НЕ автоматически дефект.** Номер трека отличается тем, что
> стоит **в начале** title и **отделён пробелом**, а сами данные в файле начинаются с `NNN_`
> в имени файла. Перед объявлением классом — разобрать 3-5 примеров глазами (тот же урок,
> что с детекторами в одиннадцатой и девятой волнах).
### 🛠 КЛАСС 4 (транслит) — НАЧАТ, ~20 из ~40
Метка `translit artist tag; folder is Cyrillic` стоит на **116 строках**, но большинство —
**ложные**: для западных групп латиница корректна (Joe Hisaishi, Ian Oliver, Yello, Ace of Base,
Muse, Gorillaz, Europe, Pain, Scooter, Nautilus в некоторых альбомах и т.д.).
**Реальные кандидаты — русские группы, записанные латиницей.**
**Исправлено в этой волне:**
| Файл / было | Стало |
|---|---|
| `Kontrabandy` / `Mumiy Troll'` | `Контрабанды` / `Мумий Тролль` |
| `Ya Popala` / `Mara` | `Я попала` / `Мара` |
| `Na Zare` / `Evgeniy Grishkovec & Bigudi & Renars Kaupers` | `На заре` / `Евгений Гришковец & Бигуди & Ренарс Кауперс` |
| `Bez Nas` / `Del'fin` | `Без нас` / `Дельфин` |
| `Vyshe Sil` / `Faktor Straha` | `Выше сил` / `Фактор Страха` |
| `Nad Eniseem` / `Groza` | `Над Енисеем` / `Гроза` |
| `Beregites' Mal'chiki` / `Diversanty` | `Берегитесь мальчики` / `Диверсанты` |
| `Nas Dvoe` / `Kurara` | `Нас двое` / `Курара` |
| `My Vstretimsya Tam` / `Lakmus` | `Мы встретимся там` / `Лакмус` |
| `Parni Ne Plachut` / `Smyslovye Gallyucinacii` | `Парни не плачут` / `Смысловые Галлюцинации` |
| `Fantastika` / `Mumiy Troll'` | `Фантастика` / `Мумий Тролль` |
| `Mumitrol'` / `Skryabin` | `Мумитроль` / `Скрябин` |
| `Ta Chto` / `Bumboks` | `Та что` / `Бумбокс` |
| `PIPEC` / `GLJUKOZA` | `Пипец` / `Глюкоза` |
| `Mama, My Vse Soshli S Uma` / `Dekabr'` | `Мама, мы все сошли с ума` / `Декабрь` |
| `Krepkiy Oreshek+++` / `Potap & Nastya Kamenskih` (×2) | `Крепкий орешек` / `Потап и Настя Каменских` |
| `babka` / `kasta` | `Бабка` / `Каста` |
| `Goryacheye Vremya` / `kasta` | `Горячее время` / `Каста` |
| `Nautilus Pompilius` → **`Наутилус Помпилиус`** | альбомы **Атлантида** (11), **Раскол** (10), **Подъём** (12) |
**Папка `!A Not sorted/Sbornik_Novij_Rok`** дала основной улов транслита (13 строк) —
там собраны русские рок-группы, у которых теги были латиницей.
> ⚠️ **Питфолл метода:** `replace_all` по паре `,Nautilus Pompilius,<album>,,no_change,translit artist tag; folder is Cyrillic`
> безопасен только при точном указании альбома — иначе `Found 3 matches`. Наутилус правился
> по альбомам отдельно (Атлантида, Раскол, Подъём).
> **Остаток:** `1998 Яблокитай` и далее — там метка ещё стоит.
### 🔴 ТРИ СОБСТВЕННЫЕ ОШИБКИ, ПОЙМАННЫЕ И ИСПРАВЛЕННЫЕ В ЭТОЙ ВОЛНЕ
| # | Ошибка | Как поймано | Фикс |
|---|---|---|---|
| 1 | `,Берегитесь, мальчики,Диверсанты` — запятая в title без кавычек → строка распалась на лишние колонки | diff показал сдвиг полей | переписал без запятой: `Берегитесь мальчики` |
| 2 | В строку «Крепкий орешек» подставил title `Дождь` (не то название) | визуальная проверка diff | вернул `Крепкий орешек` |
| 3 | `Goryacheye Vremya` приписал artist `Баста` вместо `Каста` | визуальная проверка diff | `Горячее время` / `Каста` |
> 🔴 **Правило (закрепить):** после КАЖДОЙ правки читать diff в ответе `patch` — три ошибки
> этой волны были видны именно в diff. Значение с запятой внутри **обязательно** в кавычках.
### 📊 СОСТОЯНИЕ НА КОНЕЦ ПЯТНАДЦАТОЙ ВОЛНЫ
| Показатель | Значение |
|---|---:|
| Строк в CSV | 7906 (+1 заголовок = 7907 в файле) |
| Битых строк | **0** |
| Ручных правок (`source = manual (user decision)`) | **~500** |
| Класс C «склейка artist-title в `new_title`» | ✅ **ЗАКРЫТ** |
| Класс A «имя техпапки в artist/album» | ✅ **ЗАКРЫТ (0 остатков)** |
| Класс 3 «номер трека в title» | ✅ **ЗАКРЫТ (156 строк блока `Детский хит`)** |
| Класс 4 «транслит вместо русского» | 🔄 **~20 / ~40** |
| Строки `no_change` (~1100) | 🔴 **НЕ ПРОВЕРЯЛИСЬ** |
| Применение на NAS | **НЕ начато** |
### ⏭ ЧТО ДЕЛАТЬ ПЕРВЫМ ДЕЛОМ В СЛЕДУЮЩЕЙ СЕССИИ
1. **Класс 4, остаток** — транслит Наутилуса (`/!Rock&Folk/Наутилус Помпилиус/1998 Яблокитай/`
и следующие альбомы). Детектор: `grep 'translit artist tag'` → отсеять западные группы
глазами → править русские.
2. **Транслит в `!Рэп/НТЛ`** — `RacinG_Portal` / artist `PaDoNkÈ[NTL]` (стр. 2823), `Fristaile`,
`DrakRacing`, `Kasta - Kto budet pit' s nami` → русский.
3. **Транслит в `Df1`** — проверить глазами, там в основном западные (Paffendorf, Ian Oliver) —
вероятно НЕ трогать.
4. **Проверить строки `no_change`** (~1100) — часть заведомо грязная (David Guetta был вытащен
вручную). Это последний непроверенный пласт.
5. Только после этого — **бэкап в `Music/backup/` и применение** (по «go» Alex), затем приёмка
в UI, затем Music-библиотека Jellyfin.
## 🖐 ЧЕТЫРНАДЦАТАЯ ВОЛНА: КЛАСС A ЗАКРЫТ + КЛАСС 3 НАЧАТ (2026-09-26)
### 🔴 ГЛАВНЫЙ УРОК ВОЛНЫ: `awk -F','` НЕ ГОДИТСЯ И ДЛЯ ДЕТЕКТА ПОЛЕЙ — ТОЛЬКО ДЛЯ КАВЫЧЕК