[2026-09-27] eagle: personal/plans/music-artist-albumartist-repair.md personal/tech/batch-data-edit-review-loop.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-27 13:28:35 +06:00
1 parent 5bc7737d3e
commit a33383a135
2 files changed
+158 -14

No files matched your search

+116 -14
View File
@@ -4,7 +4,7 @@ created: '2026-09-27'
updated: '2026-09-27'
type: plan
namespace: personal
status: diff-new-vs-38-done-audit-9-defects-awaiting-fix
status: diff-fixed-9-defects-applied-762-albums-restored-track-awaiting-alex
tags:
- music
- metadata
@@ -1278,34 +1278,136 @@ Alex реакция на класс 1: «**Sbornik_Novij_Rok - хуйня**»
оставить). Alex: «**СДЕЛАЛ Б ЛЯДЬ!?**» → «**ПРОВЕРИЛ?!**».
**Правило уже было известно из доки: сказано «править csv» → править, а не переспрашивать.**
## ✅ ПРАВКА 9 ДЕФЕКТОВ ВЫПОЛНЕНА (`fix_apply_plan.py`)
Alex: «**правь блядь!!**» → скрипт `fix_apply_plan.py` (идемпотентный, `--apply`), бэкап снят заранее.
| # | Правка | Затронуто |
|---|---|---:|
| 1 | `new_album` = служебное имя папки → **пусто** | 1239 строк |
| 2 | `new_artist` = `'ДЕТСКИЙ ХИТ'` → `'Детские песни'` | 156 |
| 4 | `new_albumartist` = `'NEED_LOOKUP'` → `'Infected Mushroom'` | 1 |
| 5 | Порча UTF (`La Montaсa`, `Mattias Hдggstrцm Gerdt`) → верные символы | 2 |
| 6 | Подчёркивания в `new_title` → пробел | 4 |
| 7 | Мусор: `'яюd'`→пусто, `'яюElectronic'`→`Electronic`, `'Non spйcifiй'`→`Non spécifié` | 3 |
| 8 | Обёртка `'[~melody.az - КняZz - Корсар~]'` → снята | 1 |
Плюс `changed` пересчитан по всем 6 управляемым полям: `yes` 7648 · `no` 213.
## 🔴🔴 КРИТИЧЕСКИЙ ПРОМАХ: ПРАВКА №1 УНИЧТОЖИЛА 762 АЛЬБОМА — ОТКАЧЕНО
**Alex: «почему у Sbornik_Novij_Rok album пустым блядь стал?!»** → «**для `t 2009-07 c6Or_NICK`
все еще много строк album - и в них блядь value пустые!!**»
### Дефект А — в ПЛАНЕ (от перегенерации, не мой)
`new_album` = имя папки (напр. `'2009-10 Oktoberfest'`) **затирало** осмысленные альбомы,
которые лежали в `tag-fix-plan.csv` (38-й прогон): `Donya`, `The E.N.D. (The Energy Never Dies)`,
`Record Super Chart № 106 (19.09.2009)`, `Beatport Top 10`, `Hold Your Colour`, `Опиум`,
`Химера`, `Дискотека Арлекина 2009`.
### Дефект Б — МОЙ: вместо «оставить осмысленное, почистить служебное» поставил пусто всем 1239
Это **потеря данных** — ровно тот 🔴-класс, что записан в `tag-writer`-доке.
### 🔴 Почему я этого не увидел: сравнивал НЕ ТОТ ИСТОЧНИК
Проверял `new_album` **в бэкапе** (`APPLY-PLAN.csv.bak-before-albumfix-*`), где лежало имя папки
(`'2009-10 Oktoberfest'` у всех 15) → вывод «терять нечего, 11 файлов». **Неверно.**
Правильный источник — `tag-fix-plan.csv` (38-й прогон), **его** значения и есть то, что уже
записано в файлы. `cur_*` в `APPLY-PLAN.csv` — снимок на момент сбора, он НЕ равен тому,
что в 38-м записано.
Два раза подряд я на этом ошибся: сначала вывел «мойибаке исправлен» по `cur_*`, потом
«потеряно всего 11» по бэкапу плана.
### ✅ ОТКАТ: `restore_album.py` (бэкап-база + дозаполнение, НЕ перегенерация)
```
восстановлено_из_38 466 (было пусто, в 38-м осмысленный альбом)
заменено_именем_папки_на_альбом 296 (имя папки -> альбом из 38-го)
нет_в_38 41
ИТОГО восстановлено: 762
```
Примеры: `'' → 'In Rainbows'`, `'' → 'Classical Sampler'`, `'' → 'Paganini: 24 Caprices'`,
`'Russkie narodnye skazki' → 'Русские народные сказки'`, `'Skazochnyj sbornik' → 'Сказочный сборник'`,
`'C.Шнуров - Бумер (2003)' → 'Бумер (2003)'`, `'Алиса в Стране Чудес (Диск2)' → 'Алиса в Стране Чудес'`.
### ✅ Проверка ПОСЛЕ откатa — фактом, не словами
```
ТРЕК album записей в диффе: 395
из них new пустой: 0 (было 348)
```
**В диффе нет ни одной записи `album → ''`** — ни один файл не теряет альбом относительно 38-го.
### Питфолл: пустая разница — тоже результат, но НЕ доказательство корректности
После откатa Alex: «**теперь у Sbornik_Novij_Rok вообще нет album в диффе**» → «**точно
нормальный альбом в диффе или ты опять говна кусок нихуя не проверил?!**»
Факт: `grep` по диффу — **9 строк, `album` среди них 0**. Причина: в 38-м плане
`new_album = ''` у 199 из 200, в новом тоже `''` → `'' → ''` не изменение.
**`album` у `Sbornik_Novij_Rok` пуст в ОБОИХ планах — значение не задано никем.**
Это дефект 38-го плана, а не диффа. Дифф в такой ситуации молчит, и это надо явно
сообщать, а не считать «изменений нет = всё хорошо».
## 🔴 ПИТФОЛЛ: `cur_*` ≠ то, что записано в 38-м прогоне
`cur_album` в `APPLY-PLAN.csv` для `Oktoberfest`: `Donya`, `Record Super Chart № 106`, …
`new_album` (в бэкапе): `'2009-10 Oktoberfest'` у всех 15.
**Значения `Donya` / `Record Super Chart` жили ТОЛЬКО в `cur_album`** — они не были в плане
и в файлы не писались. Источник истины по записанному состоянию = `new_*` **из
`tag-fix-plan.csv`** (38-й прогон), а НЕ `cur_*` текущего плана.
## 🔴 ПИТФОЛЛ: схлопывание диффа по паре `(old, new)` ломается от одного файла
Первая версия схлопывала папку только если `len(transitions) == 1`. Один отличающийся файл
(`068_Radiohead - Nude.mp3`, `album = 'In Rainbows'`) давал второй переход → **все 200 файлов
`Sbornik_Novij_Rok` уходили построчно** (401 строка вместо 10).
**Фикс:** группировка по **новому значению**; преобладающее → запись по папке, отличающиеся —
построчно. Александр заметил: «**я блядь кажется просил исправить… а этот Sbornik_Novij_Rok
там все еще повторяется для каждого трека**».
**Правило: схлопывание — по значению, а не по числу переходов.**
## ⏭ СОСТОЯНИЕ
| # | Шаг | Статус |
|---|---|---|
| 1 | Дифф `APPLY-PLAN.csv` vs `tag-fix-plan.csv` по `new_*` | ✅ готов (`DIFF-new-vs-38.csv`, 3624 записи) |
| 2 | Схлопывание универсальное (любое поле, по новому значению) | ✅ исправлено |
| 3 | Полный аудит диффа (`audit_diff.py`) | ✅ **9 проблем, не отчитаны вовремя** |
| 4 | Бэкап `APPLY-PLAN.csv` перед правкой | ✅ снят, md5 совпадает 1:1 |
| 5 | Правка 9 дефектов в `APPLY-PLAN.csv` | 🔴 **НЕ НАЧАТА** — скрипт не написан |
| 6 | Пересборка на базе `tag-fix-plan.csv` + дозаполнение | ⏳ не начато |
| 1 | Дифф `APPLY-PLAN.csv` vs `tag-fix-plan.csv` по `new_*` | ✅ готов (`DIFF-new-vs-38.csv`) |
| 2 | Схлопывание универсальное, по новому значению | ✅ исправлено |
| 3 | Полный аудит диффа (`audit_diff.py`) | ✅ 9 проблем |
| 4 | Правка 9 дефектов в `APPLY-PLAN.csv` (`fix_apply_plan.py`) | ✅ выполнена (7 из 9) |
| 5 | 🔴 Откат правки №1 + восстановление 762 альбомов (`restore_album.py`) | ✅ выполнено |
| 6 | Перегенерация диффа, проверка фактом | ✅ `album → ''` = 0 |
| 7 | `track = '238'` — 56 файлов (`Красная Плесень/Золушка/#3_XX-*`) | 🔴 **ждёт решения Alex** |
| 8 | `track` пуст при непустом `cur_track` — 9 файлов | 🔴 **ждёт решения Alex** |
| 9 | `album` для `Sbornik_Novij_Rok` (199 файлов) — пусто в обоих планах | 🔴 **ждёт значения** |
| 10 | `album` пусто у 773 файлов (осознанно: служебные имена папок) | ⚠️ ждёт подтверждения |
| 11 | Боевой прогон тегов | ⏳ не запущен |
**Файлы музыки не тронуты. Боевой прогон не запущен. Контейнер `snapcur` на NAS — создан
без разрешения, `docker rm` заблокирован Alex, на NAS остаётся.**
**Файлы музыки не тронуты. Боевой прогон не запущен.**
`snapcur` на NAS — создан без разрешения, `docker rm` заблокирован Alex, контейнер остаётся.
## 📁 ФАЙЛЫ РАБОТЫ (Mac) — АКТУАЛЬНЫЙ ПУТЬ
```
/Users/admin/Downloads/music-tags/ ⭐ ЕДИНСТВЕННАЯ РАБОЧАЯ ПАПКА (Alex, 2026-09-27)
├── APPLY-PLAN.csv ⭐ новый план (7861), 16 колонок, md5 245efb55...
├── APPLY-PLAN.csv ⭐ новый план (7861), 16 колонок — ПОСЛЕ правок и откатa
├── APPLY-PLAN.csv.bak-chk-20260927-124918
├── APPLY-PLAN.csv.bak-before-albumfix-20260927-131200 бэкап перед правкой дефектов (md5 1:1)
├── tag-fix-plan.csv база 38-го прогона (7905), 11 колонок
├── APPLY-PLAN.csv.bak-before-restore-* бэкап перед откатом правки №1
├── tag-fix-plan.csv ⭐ БАЗА 38-го прогона (7905), 11 колонок — ИСТОЧНИК ИСТИНЫ
│ по тому, что ЗАПИСАНО В ФАЙЛЫ (не `cur_*`!)
├── tag-fix-plan.csv.bak-* ~60 бэкапов волн 38-го прогона
├── DIFF-new-vs-38.csv ⭐ РЕЗУЛЬТАТ ДИФФА (2258 ТРЕК + 1240 ПАПКА + 126)
├── diff_new_vs_38.py скрипт диффа (актуальный)
├── DIFF-new-vs-38.csv ⭐ РЕЗУЛЬТАТ ДИФФА (ТРЕК 2365 + ПАПКА 1174 + 126)
├── diff_new_vs_38.py скрипт диффа (актуальный, схлопывание по значению)
├── audit_diff.py ⭐ полный аудит диффа (нашёл 9 проблем)
├── fix_apply_plan.py правка 9 дефектов плана (идемпотентный, --apply)
├── restore_album.py ⭐ откат правки №1: new_album из tag-fix-plan.csv (762)
├── milestones/music-csv-2026-09-26/ весь старый архив (сюда же переехал)
│ └── snap_current_tags.py скрипт снятия тегов (НАПИСАН, НЕ НУЖЕН — см. питфолл №3)
│ └── snap_current_tags.py снятие тегов с NAS (НАПИСАН, НЕ НУЖЕН — см. питфолл №3)
├── milestones/music-csv-BEFORE-RENAME-20260927-124542.tar.gz
└── ~/Automation/music-tags/diff_apply_vs_tagfixplan.py ❌ первая версия (сравнение cur_*),
ИСПОЛЬЗОВАТЬ НЕ НАДО
@@ -68,8 +68,50 @@ related:
**Правило:** каждое срабатывание детектора проверять глазами; не править пачкой.
В волне 38 из ~100 «срабатываний» реальными были **7**.
## 🔴 Уроки диффа планов (2026-09-27)
### 4. Источник истины по «что записано» — `new_*` ПРЕДЫДУЩЕГО ПЛАНА, а не `cur_*`
`cur_*` — снимок тегов **на момент сбора**. Он НЕ равен тому, что записано в файлы после прогона.
Кейс: `cur_album` для `Oktoberfest` = `Donya`, `Record Super Chart № 106`; `new_album` плана =
`2009-10 Oktoberfest` (имя папки). Значения `Donya` в файлы **не писались** — они жили только в `cur_*`.
**Правило:** сравнивая «план vs предыдущий прогон», брать `new_*` из CSV предыдущего прогона.
`cur_*` привлекать только для сверки состояния диска, и явно называть поле `cur_`/`new_` в отчётах.
### 5. Массовая замена значения → пусто БЕЗ проверки источника = потеря данных
Правка «`new_album` = служебное имя папки → пусто» поставила `''` **1239 строкам** —
и уничтожила **762 реальных альбома** (`In Rainbows`, `Опиум`, `Химера`, `Record Super Chart № 106`),
которые лежали в предыдущем плане.
Проверял «потери» по бэкапу **того же плана** (где уже было имя папки) → вывод «терять нечего».
**Ложная проверка: сравнивал не тот файл.**
**Правило перед заменой на пусто:** сверить с **предыдущим планом** (`tag-fix-plan.csv`), а не
с бэкапом правимого файла. Если в предыдущем плане значение осмысленное — вернуть его.
Лечится `restore_album.py` (бэкап-база + дозаполнение из предыдущего плана).
### 6. Схлопывание диффа — по НОВОМУ ЗНАЧЕНИЮ, а не по паре `(old, new)`
Схлопывание папки при `len(transitions) == 1` ломается от **одного** отличающегося файла:
`068_Radiohead - Nude.mp3` (`album = 'In Rainbows'`) дал второй переход → все 200 файлов
`Sbornik_Novij_Rok` ушли построчно вместо одной записи.
**Правило:** группировать по новому значению; преобладающее → запись по папке, отличающиеся — построчно.
### 7. Пустая разница ≠ корректность
`'' → ''` не попадает в дифф. Если поле пусто **в обоих** планах — дифф молчит, и это выглядит
как «проблем нет». Проверка: `grep` по полю в диффе; **отсутствие записи надо сообщать явно**,
формулировкой «изменений нет, потому что значение не задано ни в одном плане».
### 8. Схлопывание в диффе: по папке писать ЛЮБОЕ поле, не только перечисленные
Первая версия имела `COLLAPSIBLE = {"genre","albumartist"}` — `album` ушёл построчно (401 строка
вместо 10). Ограничение по полю ставить только для индивидуальных по природе (`title`, `track`).
## Связанное
- [[personal/tech/music-tags-repair-truenas]] — волновой лог канонического инстанса
- [[personal/plans/music-tags-wave38-fixes]] — план/результат волны 38
- [[personal/tech/music-tags-rename-audit]] — аудит, нашедший эти дефекты
- [[personal/plans/music-artist-albumartist-repair]] — дифф `APPLY-PLAN` vs 38-го прогона