From e177d11aacf9a08554a9bb57f4157bd099b28fc3 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Sun, 27 Sep 2026 21:14:41 +0600 Subject: [PATCH] [2026-09-27] eagle: personal/plans/music-artist-albumartist-repair.md personal/plans/music-artist-albumartist-repair.md.bak-verify-v3-20260927 personal/tech/music-tags-repair-truenas.md --- .../plans/music-artist-albumartist-repair.md | 83 ++++- ...bumartist-repair.md.bak-verify-v3-20260927 | 326 ++++++++++++++++++ personal/tech/music-tags-repair-truenas.md | 16 +- 3 files changed, 420 insertions(+), 5 deletions(-) create mode 100644 personal/plans/music-artist-albumartist-repair.md.bak-verify-v3-20260927 diff --git a/personal/plans/music-artist-albumartist-repair.md b/personal/plans/music-artist-albumartist-repair.md index 9a96f24c..5f370dad 100755 --- a/personal/plans/music-artist-albumartist-repair.md +++ b/personal/plans/music-artist-albumartist-repair.md @@ -4,7 +4,7 @@ created: '2026-09-27' updated: '2026-09-27' type: plan namespace: personal -status: canon-diff-v3-built / genre-gap-open +status: v3-verified-3-discrepancies / dry-run-blocked-on-alex-decision tags: - music - metadata @@ -40,11 +40,16 @@ related: ``` Дифф: ~/Downloads/music-tags/DIFF-base-vs-applyplan-v3.csv md5 bdb20c6ae00e7dfab4da2f76653fe084 - 945 строк · genre 427 · album 28 · albumartist 6 + 945 строк (ПАПКА 711 · ТРЕК 234) · genre 911 · album 28 · albumartist 6 План: /tmp/apply-plan-v3.csv (7861 строка, md5 6b9e49b2baa3f1d1708e4566972266a9) +Лог: ~/Downloads/music-tags/APPLY-PLAN-v3-changes.csv (31 строка — УСТАРЕЛ, см. § ВЕРИФИКАЦИЯ) Канон: ~/Downloads/music-tags/APPLY-PLAN.csv (7861 строка — НЕ ПЕРЕЗАПИСЫВАТЬ) ``` +**Состояние:** артефакты v3 проверифицированы 27 сен. **Dry-run НЕ запущен** — +блокирует решение Alex: дифф считает группы (genre 911), dry-run считает файлы +(genre 4359). См. § ВЕРИФИКАЦИЯ v3. + **Открытый дефект:** жанры (`TCON`) не записаны в теги — прогон шёл старым скриптом. Скрипт уже исправлен, **прогон не сделан**. @@ -65,6 +70,7 @@ related: | 6 | 27 сен | 38-я волна: `tag-fix-plan.csv` + ручные правки (транслит, треки, опечатки) | `tag-fix-plan.csv` | | 7 | 27 сен | `.ndignore` — 6 бэкапов исключены, Navidrome их не видит | `.ndignore` | | 8 | 27 сен | **Канонный дифф v3 собран** — сортировка по `field`, схлопывание, шум убран | `DIFF-base-vs-applyplan-v3.csv` | +| 9 | 27 сен | **Верификация артефактов v3 перед dry-run** — 3 расхождения вскрыты, см. § ВЕРИФИКАЦИЯ | `/tmp/verify_v3*.py` | --- @@ -162,6 +168,7 @@ backup_raw ``` ~/Downloads/music-tags/APPLY-PLAN.csv канон, 7861 стр, md5 bc20f2a49e364ecd5ed57d9fc97bfbcb ~/Downloads/music-tags/DIFF-base-vs-applyplan-v3.csv дифф v3, 945 стр, md5 bdb20c6ae00e7dfab4da2f76653fe084 +~/Downloads/music-tags/APPLY-PLAN-v3-changes.csv лог 31 правки v3, md5 2c6d2f0bb1d732d7e3e70ef1b210e7d8 ~/Downloads/music-tags/tag-fix-plan.csv 38-я волна, 7905 стр ~/Downloads/music-tags/ALBUM-FIX-306.csv скобочный прогон, 306 стр ~/Downloads/navidrome-db/navidrome-merged.db БД Navidrome (локальная копия) @@ -173,6 +180,9 @@ backup_raw /tmp/make_applyplan_v3.py сборка плана v3 (правило корня) /tmp/make_diff_rule.py детектор правила корня по БД /tmp/rule_check_v2.py проверка правила (вхождение, не равенство) +/tmp/verify_v3.py верификация: лог vs план +/tmp/verify_v3b.py верификация: ПАПКА/ТРЕК-строки диффа из плана +/tmp/verify_v3c.py верификация: аномалии (genre-дубли, Sbornik, пропуск пути) ~/Developer/personal-os/tools/music-tags/build_fix_plan2.py генератор плана (пофикшен) ``` @@ -186,12 +196,67 @@ DIFF-rule-vs-BASE.csv сверка правила с базой --- +## 🔎 ВЕРИФИКАЦИЯ v3 ПЕРЕД DRY-RUN (2026-09-27) + +Проверено на Mac, три скрипта, все числа — из самих файлов. + +### ✅ Что подтвердилось +``` +План 7861 стр · дифф 945 стр · лог 31 стр — все три md5 совпали с докой +Дифф: ПАПКА 711 / ТРЕК 234 = 945; album 28 · albumartist 6 · genre 911 +album + albumartist: все 234 ТРЕК-строки восстанавливаются из плана точно, 0 ошибок +``` + +### 🔴 РАСХОЖДЕНИЕ 1 — лог `APPLY-PLAN-v3-changes.csv` УСТАРЕЛ (план прав) +Лог писался ДО фиксов `fix_ruki.py` / `fix_rockopop_track.py`. Три строки врут: + +| файл | лог говорит | в плане (верно) | +|---|---|---| +| `!Retro/Руки/Руки Вверх - Алешка.mp3` | `Руки` | **`Руки вверх`** | +| `!Rock&Folk/!rock_o_pop/АлисА - Стать севера.mp3` | `!rock_o_pop` | **`rock_o_pop`** | +| `!Rock&Folk/!rock_o_pop/Рок-Группа - Попса.mp3` | `!rock_o_pop` | **`rock_o_pop`** | +| `!Retro/Юрий Никулин/Постой паровоз.mp3` | есть | в плане путь `Постой паровоз.mp3`, файлов 3, все `Песни → Юрий Никулин` | + +Плюс 3 строки с `old_album` в CP1251-кракозябрах (`Øàëàâû`) — план хранит битый `cur_*` +как есть, лог записал уже декодированное. **Лог не трогаем, план — эталон.** + +### 🔴 РАСХОЖДЕНИЕ 2 — `genre` в диффе НЕ выдержан по правилу `scope` +Пример `!Pop, Club, Любэ/!Radio/w 2008-07` (38 файлов): +- ПАПКА-строки в диффе: `Blues · Dance · Electronic · House · Pop` (5) +- фактически `new_genre` в плане: **11 значений** — `Pop 16 · Dance 5 · House 5 · + Electronic 4 · Blues 2 · Trance 1 · Club 1 · Progressive House 1 · Electro House 1 · + Drum & Bass 1 · Hip-Hop 1` +- **7 значений не попали в дифф**: файл с таким значением в папке единственный → + правило «ПАПКА, если ≥2 файла» его отбросило. + +Итог: из 234 ТРЕК-строк **211 — по `genre`** и они дублируют значения, которые уже лежат +в плане как `new_genre`. ПАПКА-строки по genre: 700 (из 711); 585 уникальных ключей +`(folder,field)` при 711 строках ⇒ **126 лишних строк** (65 ключей с >1 `new`). +`old` заполнен только у 11 из 711 (8×``, 3 конкретных), у 700 — пусто. + +### 🔴 РАСХОЖДЕНИЕ 3 — цифры dry-run НЕ МОГУТ совпасть с диффом +``` +Дифф считает ГРУППЫ: album 28 · albumartist 6 · genre 911 = 945 строк +Dry-run считает ФАЙЛЫ: album 28 · albumartist 6 · genre 4359 (все файлы с пустым cur_genre) +``` +Ожидаемый вывод dry-run — по счётчикам полей прогона 27 сен: `TCON 4359`. +**Поштучное совпадение с 945 недостижимо by design.** + +### ⏳ Открытый вопрос к Alex (блокирует формулировку «dry-run совпал») +1. Эталон = план (файлы, `genre 4359`) или дифф (группы, `genre 911`)? Дифф пересобираем? +2. 126 лишних строк диффа схлопывать до одной на `(folder,field)` или множественные + `new` внутри папки — намеренный показ «сколько разных значений осталось»? + +--- + ## 🔴 ОТКРЫТЫЕ ДЕФЕКТЫ | Дефект | Факт | Статус | |--------|------|--------| | **Жанры не в тегах** | В БД `genre` пусто у всех 7861; прогон 27 сен не писал `TCON` | Скрипт исправлен, **прогон нужен** | | Жанры в диффе | 427 строк / 911 групп, покрытие 7861 — не «правка», а повторная запись | Учтено | +| Лог v3 устарел | 3 строки + 1 путь расходятся с планом после `fix_ruki`/`fix_rockopop` | Решено: план — эталон, лог не пересобираем | +| Дифф: genre-группы | 211 ТРЕК-строк дублируют `new_genre`; 7 одиночек не добраны | **Ждём решения Alex** | --- @@ -202,9 +267,12 @@ DIFF-rule-vs-BASE.csv сверка правила с базой Бэкапы: 535 файлов (6 папок, в .ndignore) Боевой прогон: 27 сен, 7649/7649 ok, err=0, VERIFY 7649 Поля прогона: TPE2 7213 · TCON 4359 · TALB 1659 · TPE1 381 · TRCK 344 · TIT2 8 +Поля плана (cur!=new): album 2031 · albumartist 7213 · genre 4359 · artist 381 · + title 8 · track 441 ; plan.changed=yes 7653 Дифф v3: 945 строк (ПАПКА 711 · ТРЕК 234) - genre 427 · album 28 · albumartist 6 + genre 911 · album 28 · albumartist 6 Дифф на 100%: 7861 файл сопоставлен, не найдено 0 +Лог v3: 31 строка ``` --- @@ -225,6 +293,15 @@ DIFF-rule-vs-BASE.csv сверка правила с базой срабатываний, если не отсеять осмысленные альбомы. 8. **`album` для сборника** — правило корня применять НЕЛЬЗЯ, только если план не дал целевого значения. +9. **Не сравнивать дифф и dry-run по сырым числам.** Дифф = ГРУППЫ, dry-run = ФАЙЛЫ. + Единицу счёта называть явно, иначе «не совпало» на пустом месте. +10. **Дифф со `scope=ПАПКА` проверять агрегацией по плану, а не поиском пути в плане** — + у ПАПКА-строки в колонке `path` лежит ПАПКА, не файл. Наивный чек даёт 711 ложных + «DIFF-PATH-NOT-IN-PLAN». +11. **ТРЕК-строка диффа ≠ `cur!=new`.** У genre ТРЕК-строка может нести значение, + совпадающее с `cur_genre` (дубль групповой строки). Не считать их списком правок. +12. **Лог правок пересобирать ПОСЛЕ последнего фикса плана.** Иначе лог расходится с + планом (так и вышло: `fix_ruki`/`fix_rockopop` прошли после генерации лога). --- diff --git a/personal/plans/music-artist-albumartist-repair.md.bak-verify-v3-20260927 b/personal/plans/music-artist-albumartist-repair.md.bak-verify-v3-20260927 new file mode 100644 index 00000000..fe0a6bc7 --- /dev/null +++ b/personal/plans/music-artist-albumartist-repair.md.bak-verify-v3-20260927 @@ -0,0 +1,326 @@ +--- +title: Music Tags Repair — TrueNAS / Navidrome +created: '2026-09-27' +updated: '2026-09-27' +type: plan +namespace: personal +status: canon-diff-v3-built / genre-gap-open +tags: + - music + - metadata + - id3 + - album + - albumartist + - repair + - truenas + - navidrome +related: + - '[[family/how-to/truenas-access]]' + - '[[personal/tech/music-tags-repair-truenas]]' + - '[[personal/plans/tagwriter-container]]' + - '[[family/how-to/navidrome-truenas-android]]' + - '[[family/plans/music-jellyfin-lidarr-taiga]]' +--- + +# Music Tags Repair — TrueNAS / Navidrome + +> **Эта дока — выжимка.** Полная хронология 50 сессий — в бэкапе +> `music-artist-albumartist-repair.md.bak-20260927-210643` (7529 строк). +> Здесь: майлстоуны, текущий стейт, инструкции. + +--- + +## 🔑 СТАРТ ЗДЕСЬ + +**Что делаем:** привести ID3-теги библиотеки `/mnt/RED_2TB/storage/Music` (7861 файл) +в порядок, чтобы Navidrome показывал правильные альбомы/исполнителей/жанры. + +**Главный артефакт на сейчас:** + +``` +Дифф: ~/Downloads/music-tags/DIFF-base-vs-applyplan-v3.csv + md5 bdb20c6ae00e7dfab4da2f76653fe084 + 945 строк · genre 427 · album 28 · albumartist 6 +План: /tmp/apply-plan-v3.csv (7861 строка, md5 6b9e49b2baa3f1d1708e4566972266a9) +Канон: ~/Downloads/music-tags/APPLY-PLAN.csv (7861 строка — НЕ ПЕРЕЗАПИСЫВАТЬ) +``` + +**Открытый дефект:** жанры (`TCON`) не записаны в теги — прогон шёл старым скриптом. +Скрипт уже исправлен, **прогон не сделан**. + +**Доступ к NAS:** `ssh -i ~/.ssh/id_rsa truenas_admin@mallexxx.duckdns.org` +⚠️ `192.168.1.100` — ЧУЖАЯ подсеть, не использовать. Подробнее → [[family/how-to/truenas-access]] + +--- + +## 📍 МАЙЛСТОУНЫ + +| # | Дата | Что сделано | Артефакт | +|---|------|-------------|----------| +| 1 | 27 сен | Navidrome развёрнут на TrueNAS, класс дефекта вскрыт | — | +| 2 | 27 сен | Собраны правила Alex из Zulip DB (правило корня, сборники) | — | +| 3 | 27 сен | `APPLY-PLAN.csv` = 7861 строка, канон | `APPLY-PLAN.csv` | +| 4 | 27 сен | Боевой прогон тегов: 7649/7649 ok, err=0 | `tagwriter:latest` | +| 5 | 27 сен | Генератор `build_fix_plan2.py` пофикшен (обрезка категории) | — | +| 6 | 27 сен | 38-я волна: `tag-fix-plan.csv` + ручные правки (транслит, треки, опечатки) | `tag-fix-plan.csv` | +| 7 | 27 сен | `.ndignore` — 6 бэкапов исключены, Navidrome их не видит | `.ndignore` | +| 8 | 27 сен | **Канонный дифф v3 собран** — сортировка по `field`, схлопывание, шум убран | `DIFF-base-vs-applyplan-v3.csv` | +| 9 | 27 сен | **Верификация артефактов v3 перед dry-run** — 3 расхождения вскрыты, см. § ВЕРИФИКАЦИЯ | `/tmp/verify_v3*.py` | + +--- + +## 🧩 ПРАВИЛА (от Alex, обязательны) + +### 1. Правило корня +Файл лежит **в корне папки артиста** (без подпапки-альбома) → это один альбом: +- `album` = имя папки артиста +- `albumartist` = титульный исполнитель + +Сравнение по **вхождению** (`nleaf in nartist`), НЕ на равенство — иначе теряются +папки-огрызки (`Руки` vs `Руки Вверх`). + +### 2. Сборники не трогаем +Если тег `artist` ≠ имя папки → это сборник, правило корня к нему не применяется. +Пример: `Sbornik_Novij_Rok` (`artist` = разные исполнители). + +### 3. Папка-мусорка = альбом +`Разное`, `Избранное`, `Песни`, `misc` как имя папки → идут в `album` **как есть**. +Не разгребаем. Решение Alex от 27 сен. + +### 4. `track` — только целое +База хранит `track_number` целым (`1`, `2` … `24`). Формат `N/M` и ведущие нули +(`6/14`, `08`) — **шум, не правка**: значение не меняется, парсеры ломаются. + +### 5. Категории-контейнеры срезаются +`!Retro`, `!Rock&Folk`, `!Pop, Club, Любэ`, `!A Not sorted` — срезаются при разборе пути. + +--- + +## 🛠 КАК ЧТО ДЕЛАЕТСЯ + +### Доступ к NAS +```bash +ssh -i ~/.ssh/id_rsa truenas_admin@mallexxx.duckdns.org +``` +- Библиотека: `/mnt/RED_2TB/storage/Music` (`/mnt/RED_2TB/Music` — ПУСТАЯ) +- Navidrome БД: `/mnt/RED_2TB/storage/docker/navidrome/data/navidrome.db`, порт 4533 +- `sqlite3` на NAS есть; в контейнерах — НЕТ (читать БД через `strings`) + +### Собрать дифф (`field → folder → path`, схлопывание, шум-фильтр) +```bash +python3 /tmp/build_canon_diff_v3.py +# → ~/Downloads/music-tags/DIFF-base-vs-applyplan-v3.csv +``` + +### Собрать план v3 (правило корня поверх канона) +```bash +python3 /tmp/make_applyplan_v3.py +# → /tmp/apply-plan-v3.csv +``` + +### Применить теги (образ tagwriter) +```bash +# сухой прогон +docker create --name twdry --entrypoint python3 \ + -v /tmp/tw306:/app/data:ro -v /mnt/RED_2TB/storage/Music:/music:rw \ + tagwriter:latest /app/data/apply_tags_v2.py --dry-run && docker start -a twdry +``` +- Образ `tagwriter:latest` (НЕ `v2`), uid 950:950, amd64 +- План читается ТОЛЬКО как `/app/data/apply-plan.csv` +- Скрипт: `/app/apply_tags_v2.py` — пишет `TIT2 TPE1 TPE2 TALB TCON TRCK` + +### Пересканить Navidrome после правки тегов +```bash +cd /mnt/RED_2TB/storage/docker/navidrome && docker compose stop +rm -f data/navidrome.db* # БД = КЭШ, теги не перечитываются иначе +docker compose up -d +``` +⚠️ Рескан сам по себе теги НЕ перечитывает → старый альбом останется ДУБЛЕМ. + +### Обязательный фильтр во ВСЕХ запросах к БД +```sql +WHERE path NOT LIKE 'backup%' +``` +Иначе бэкап всплывает как живое дерево. + +### Правило `.ndignore` +Любой новый `backup*` в `/mnt/RED_2TB/storage/Music/` → дописать в `.ndignore` +в том же прогоне. Текущее содержимое (6 записей): +``` +backup +backup_album_root_20260927-album-root-229 +backup_before_306 +backup_conv40 +backup_fix +backup_raw +``` + +--- + +## 📦 АРТЕФАКТЫ + +### Рабочие (Mac) +``` +~/Downloads/music-tags/APPLY-PLAN.csv канон, 7861 стр, md5 bc20f2a49e364ecd5ed57d9fc97bfbcb +~/Downloads/music-tags/DIFF-base-vs-applyplan-v3.csv дифф v3, 945 стр, md5 bdb20c6ae00e7dfab4da2f76653fe084 +~/Downloads/music-tags/APPLY-PLAN-v3-changes.csv лог 31 правки v3, md5 2c6d2f0bb1d732d7e3e70ef1b210e7d8 +~/Downloads/music-tags/tag-fix-plan.csv 38-я волна, 7905 стр +~/Downloads/music-tags/ALBUM-FIX-306.csv скобочный прогон, 306 стр +~/Downloads/navidrome-db/navidrome-merged.db БД Navidrome (локальная копия) +``` + +### Скрипты +``` +/tmp/build_canon_diff_v3.py сборка канонного диффа (шум-фильтр внутри) +/tmp/make_applyplan_v3.py сборка плана v3 (правило корня) +/tmp/make_diff_rule.py детектор правила корня по БД +/tmp/rule_check_v2.py проверка правила (вхождение, не равенство) +/tmp/verify_v3.py верификация: лог vs план +/tmp/verify_v3b.py верификация: ПАПКА/ТРЕК-строки диффа из плана +/tmp/verify_v3c.py верификация: аномалии (genre-дубли, Sbornik, пропуск пути) +~/Developer/personal-os/tools/music-tags/build_fix_plan2.py генератор плана (пофикшен) +``` + +### Устаревшие диффы (не использовать) +``` +DIFF-new-vs-38-v2/v3/v4/v5/v6.csv промежуточные, дефектные +DIFF-base-vs-applyplan-v2.csv дефектный (albumartist 7861, Sbornik) +DIFF-rule-album-v1.csv подмножество +DIFF-rule-vs-BASE.csv сверка правила с базой +``` + +--- + +## 🔎 ВЕРИФИКАЦИЯ v3 ПЕРЕД DRY-RUN (2026-09-27) + +Проверено на Mac, три скрипта, все числа — из самих файлов. + +### ✅ Что подтвердилось +``` +План 7861 стр · дифф 945 стр · лог 31 стр — все три md5 совпали с докой +Дифф: ПАПКА 711 / ТРЕК 234 = 945; album 28 · albumartist 6 · genre 911 +album + albumartist: все 234 ТРЕК-строки восстанавливаются из плана точно, 0 ошибок +``` + +### 🔴 РАСХОЖДЕНИЕ 1 — лог `APPLY-PLAN-v3-changes.csv` УСТАРЕЛ (план прав) +Лог писался ДО фиксов `fix_ruki.py` / `fix_rockopop_track.py`. Три строки врут: + +| файл | лог говорит | в плане (верно) | +|---|---|---| +| `!Retro/Руки/Руки Вверх - Алешка.mp3` | `Руки` | **`Руки вверх`** | +| `!Rock&Folk/!rock_o_pop/АлисА - Стать севера.mp3` | `!rock_o_pop` | **`rock_o_pop`** | +| `!Rock&Folk/!rock_o_pop/Рок-Группа - Попса.mp3` | `!rock_o_pop` | **`rock_o_pop`** | +| `!Retro/Юрий Никулин/Постой паровоз.mp3` | есть | в плане путь `Постой паровоз.mp3`, файлов 3, все `Песни → Юрий Никулин` | + +Плюс 3 строки с `old_album` в CP1251-кракозябрах (`Øàëàâû`) — план хранит битый `cur_*` +как есть, лог записал уже декодированное. **Лог не трогаем, план — эталон.** + +### 🔴 РАСХОЖДЕНИЕ 2 — `genre` в диффе НЕ выдержан по правилу `scope` +Пример `!Pop, Club, Любэ/!Radio/w 2008-07` (38 файлов): +- ПАПКА-строки в диффе: `Blues · Dance · Electronic · House · Pop` (5) +- фактически `new_genre` в плане: **11 значений** — `Pop 16 · Dance 5 · House 5 · + Electronic 4 · Blues 2 · Trance 1 · Club 1 · Progressive House 1 · Electro House 1 · + Drum & Bass 1 · Hip-Hop 1` +- **7 значений не попали в дифф**: файл с таким значением в папке единственный → + правило «ПАПКА, если ≥2 файла» его отбросило. + +Итог: из 234 ТРЕК-строк **211 — по `genre`** и они дублируют значения, которые уже лежат +в плане как `new_genre`. ПАПКА-строки по genre: 700 (из 711); 585 уникальных ключей +`(folder,field)` при 711 строках ⇒ **126 лишних строк** (65 ключей с >1 `new`). +`old` заполнен только у 11 из 711 (8×``, 3 конкретных), у 700 — пусто. + +### 🔴 РАСХОЖДЕНИЕ 3 — цифры dry-run НЕ МОГУТ совпасть с диффом +``` +Дифф считает ГРУППЫ: album 28 · albumartist 6 · genre 911 = 945 строк +Dry-run считает ФАЙЛЫ: album 28 · albumartist 6 · genre 4359 (все файлы с пустым cur_genre) +``` +Ожидаемый вывод dry-run — по счётчикам полей прогона 27 сен: `TCON 4359`. +**Поштучное совпадение с 945 недостижимо by design.** + +### ⏳ Открытый вопрос к Alex (блокирует формулировку «dry-run совпал») +1. Эталон = план (файлы, `genre 4359`) или дифф (группы, `genre 911`)? Дифф пересобираем? +2. 126 лишних строк диффа схлопывать до одной на `(folder,field)` или множественные + `new` внутри папки — намеренный показ «сколько разных значений осталось»? + +--- + +## 🔴 ОТКРЫТЫЕ ДЕФЕКТЫ + +| Дефект | Факт | Статус | +|--------|------|--------| +| **Жанры не в тегах** | В БД `genre` пусто у всех 7861; прогон 27 сен не писал `TCON` | Скрипт исправлен, **прогон нужен** | +| Жанры в диффе | 427 строк / 911 групп, покрытие 7861 — не «правка», а повторная запись | Учтено | +| Лог v3 устарел | 3 строки + 1 путь расходятся с планом после `fix_ruki`/`fix_rockopop` | Решено: план — эталон, лог не пересобираем | +| Дифф: genre-группы | 211 ТРЕК-строк дублируют `new_genre`; 7 одиночек не добраны | **Ждём решения Alex** | + +--- + +## 📊 ЧИСЛА (факты) + +``` +Библиотека: 7861 живых файлов = строкам плана +Бэкапы: 535 файлов (6 папок, в .ndignore) +Боевой прогон: 27 сен, 7649/7649 ok, err=0, VERIFY 7649 +Поля прогона: TPE2 7213 · TCON 4359 · TALB 1659 · TPE1 381 · TRCK 344 · TIT2 8 +Поля плана (cur!=new): album 2031 · albumartist 7213 · genre 4359 · artist 381 · + title 8 · track 441 ; plan.changed=yes 7653 +Дифф v3: 945 строк (ПАПКА 711 · ТРЕК 234) + genre 911 · album 28 · albumartist 6 +Дифф на 100%: 7861 файл сопоставлен, не найдено 0 +Лог v3: 31 строка +``` + +--- + +## 🧨 ПИТФОЛЛЫ + +1. **`192.168.1.100` — чужая подсеть.** NAS: `mallexxx.duckdns.org`. Агент объявлял + «NAS недоступен» — **ложно**. +2. **`grep` по всему файлу даёт ложную тревогу.** Опечатки в колонке `title` = названия + песен, они и должны остаться. Проверять по НУЖНОЙ колонке. +3. **Фильтр шума снаружи генератора = регрессия.** Пересборка возвращает `track N/M`. + Фильтр должен быть ВНУТРИ сборщика диффа. +4. **`cur_*` в плане = снимок ДО прогона**, не текущее состояние базы. +5. **Запрос к БД без `NOT LIKE 'backup%'`** → бэкап всплывает как живое дерево. +6. **Navidrome не перечитывает теги** при скане/рестарте → дубли. Лечение: stop → + `rm data/navidrome.db*` → up -d. +7. **Детектор «правило корня не сработало» на `new_album`** даёт тысячи ложных + срабатываний, если не отсеять осмысленные альбомы. +8. **`album` для сборника** — правило корня применять НЕЛЬЗЯ, только если план не дал + целевого значения. +9. **Не сравнивать дифф и dry-run по сырым числам.** Дифф = ГРУППЫ, dry-run = ФАЙЛЫ. + Единицу счёта называть явно, иначе «не совпало» на пустом месте. +10. **Дифф с `scope=ПАПКА` проверять агрегацией по плану, а не поиском пути в плане** — + у ПАПКА-строки в колонке `path` лежит ПАПКА, не файл. Наивный чек даёт 711 ложных + «DIFF-PATH-NOT-IN-PLAN». +11. **ТРЕК-строка диффа ≠ `cur!=new`.** У genre ТРЕК-строки могут нести значение, + совпадающее с `cur_genre` (дубль групповой строки). Не считать их списком правок. +12. **Лог правок пересобирать ПОСЛЕ последнего фикса плана.** Иначе лог расходится с + планом (так и вышло: `fix_ruki`/`fix_rockopop` прошли после генерации лога). + +--- + +## ⚙️ ПОРЯДОК РАБОТЫ С БОЕВЫМИ ДАННЫМИ + +``` +коммит ДО → правка → заливка → ПРОВЕРКА ALEX → коммит ПОСЛЕ +``` +- `apply` / запись тегов — **только по прямой команде Alex** +- Мой `read back` ≠ «работает». Приёмка = видно в UI +- Ничего сверх команды без апрува + +--- + +## 📜 ИСТОРИЯ + +Полная хронология (сессии 2–29, все правки, откаты, разборы) — в бэкапе: +``` +~/.hermes/... — нет; файл рядом: +~/obsidian/personal/plans/music-artist-albumartist-repair.md.bak-20260927-210643 +``` + +Смежные доки: +- [[personal/tech/music-tags-repair-truenas]] — детали ремонта тегов +- [[personal/plans/tagwriter-container]] — контейнер-писатель +- [[family/how-to/navidrome-truenas-android]] — Navidrome + клиенты +- [[family/how-to/truenas-access]] — доступ к NAS (**читать перед SSH**) diff --git a/personal/tech/music-tags-repair-truenas.md b/personal/tech/music-tags-repair-truenas.md index d46c1711..681ad943 100755 --- a/personal/tech/music-tags-repair-truenas.md +++ b/personal/tech/music-tags-repair-truenas.md @@ -26,13 +26,25 @@ related: > ## 🔴 АКТУАЛЬНОЕ СОСТОЯНИЕ (2026-09-27, сессия 29-ОКТИ) — ЧИТАЙ ЭТО ПЕРВЫМ > > ✅ **КАНОННЫЙ ДИФФ v3 СОБРАН И ЗАКРЫТ:** `~/Downloads/music-tags/DIFF-base-vs-applyplan-v3.csv` -> — **945 записей**, `md5 bdb20c6ae00e7dfab4da2f76653fe084`. Поля: `album` 28 · -> `albumartist` 6 · `genre` 427. `track` — **0** (весь блок убран как шум, см. ниже). +> — **945 записей** (`ПАПКА` 711 · `ТРЕК` 234), `md5 bdb20c6ae00e7dfab4da2f76653fe084`. +> Поля: `album` 28 · `albumartist` 6 · **`genre` 911 групп / 427 уникальных имён**. +> `track` — **0** (весь блок убран как шум, см. ниже). > База 7861 ↔ план 7861, сопоставлено 7861, **не найдено 0** (фильтр `path NOT LIKE 'backup%'`). > Источник: `/tmp/apply-plan-v3.csv` (7861, из `new_*` `APPLY-PLAN.csv` + правило корня; > **31 правка**, лог с колонкой `reason` — `~/Downloads/music-tags/APPLY-PLAN-v3-changes.csv`). > Сборщик: `/tmp/build_canon_diff_v3.py`. > +> 🔴 **ВЕРИФИКАЦИЯ v3 (2026-09-27) — dry-run НЕ ЗАПУЩЕН, 3 расхождения.** Полный разбор — +> [[personal/plans/music-artist-albumartist-repair]] § ВЕРИФИКАЦИЯ v3 ПЕРЕД DRY-RUN. +> Коротко: (1) **лог `APPLY-PLAN-v3-changes.csv` УСТАРЕЛ** — писался до `fix_ruki.py`/ +> `fix_rockopop_track.py`, 3 строки врут (`Руки` вместо `Руки вверх`, `!rock_o_pop` вместо +> `rock_o_pop`), **эталон — план**; (2) **`genre` в диффе не выдержан по `scope`** — +> 211 из 234 ТРЕК-строк дублируют `new_genre`, 7 одиночек в `!Radio/w 2008-07` не добраны, +> 711 ПАПКА-строк дают 585 ключей `(folder,field)` ⇒ 126 лишних; (3) 🔴 **цифры dry-run +> НЕ МОГУТ совпасть с диффом: дифф = ГРУППЫ (`genre 911`), dry-run = ФАЙЛЫ (`genre 4359`).** +> Вопрос к Alex: эталон — план или дифф; схлопывать ли 126 лишних строк. Скрипты: +> `/tmp/verify_v3.py` · `/tmp/verify_v3b.py` · `/tmp/verify_v3c.py`. +> > 🔴 **ДЕФЕКТ СОРТИРОВКИ (найден Alex: «почему сортировки по филду нету в диффе») — ИСПРАВЛЕН.** > Сортировка обязана быть **ПО АЛФАВИТУ**: `album → albumartist → artist → genre → title → track`, > т.е. **`album` ПЕРЕД `albumartist`**. Скрипт писался с нуля и взял ЛОГИЧЕСКИЙ список