From 1d75d3f519934d02c982e632ca17109015b3f3fe Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Sun, 27 Sep 2026 14:29:22 +0600 Subject: [PATCH] [2026-09-27] eagle: personal/plans/music-artist-albumartist-repair.md personal/tech/id3-tag-repair.md --- .../plans/music-artist-albumartist-repair.md | 148 +++++++++++++++++- personal/tech/id3-tag-repair.md | 36 ++++- 2 files changed, 180 insertions(+), 4 deletions(-) diff --git a/personal/plans/music-artist-albumartist-repair.md b/personal/plans/music-artist-albumartist-repair.md index f1de3f43..abc90295 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: session10-done-va-author-class-cleared-spelling-normalized +status: session11-diff-audit-2-cosmetic-defects-sort-order-pending-alex tags: - music - metadata @@ -54,8 +54,33 @@ related: > > ✅ Класс `A2` **дочищен**: `find_va_misuse.py` → 0, `find_va_author.py` → остались только > 2 защитимые папки (`Блестящие, Фриске`, `Eminem,50cent`). -> -> ## 🔴 АКТУАЛЬНО НА КОНЕЦ СЕССИИ 9 (2026-09-27) + +## 🔴 АКТУАЛЬНО НА КОНЕЦ СЕССИИ 11 (2026-09-27) + +``` +APPLY-PLAN.csv 7861 строка md5 7679ee01a2aa8f28623b6fb8559d7381 +DIFF-new-vs-38.csv 5000 строк md5 53716eea5accbffe50dbc0ee3a8ef8f7 +tag-fix-plan.csv 7861 строка md5 203726ebfd2814e2328636df31337238 +``` + +**Аудит диффа проведён построчно. Данные корректны:** полнота сошлась +(`covered + file_lines == sum(field_counts)`), пустых полей 0, потерь правок нет. +Состав: `ТРЕК` 3751 · `ПАПКА` 1123 (569 папок) · `ТОЛЬКО-В-38` 85 · `НЕТ-В-38` 41. + +🔴 **Найдено 2 КОСМЕТИЧЕСКИХ дефекта отчёта (не данных):** +1. **Порядок блоков нечитаем** — 13 field-run блоков вместо 4, `scope` не входит в ключ + сортировки. Alex: «там album, albumartist, genre, потом снова album!» +2. **Хвост файла** — секции полноты `НЕТ-В-38`/`ТОЛЬКО-В-38` читаются как мусор. + +⏳ **ЖДЁТ ОТВЕТА ALEX:** номер варианта починки сортировки (1 — по папке ⭐ / 2 — добавить +`scope` в ключ / 3 — вариант 1 + вынести хвост в отдельный файл). См. «🔷 СЕССИЯ 11» в конце +документа. + +📌 **Метод-урок:** проверка «отсортировано?» через `data == sorted(data)` даёт `True`, +хотя порядок нечитаем. Структуру файла описывать **явным списком переходов** с номерами +строк, не агрегатом `Counter`. **Первый отчёт сессии («4 блока») был ошибочным — Alex поймал.** + +## 🔴 АКТУАЛЬНО НА КОНЕЦ СЕССИИ 9 (2026-09-27) > > ``` > APPLY-PLAN.csv 7861 строка md5 82492a0b2b93dbb6c7444a4040a21a03 @@ -3220,6 +3245,123 @@ APPLY-PLAN.csv.bak-before-bumer-20260927-142130 4. Контейнер `snapcur` на NAS (только чтение, `:ro`) — **не убран**, Alex не подтвердил. 5. Открытые вопросы, ответа НЕ было (не трогать): `Рэп/НТЛ` помечен Alex как `НТЛ` — учтено. +## 🔷 СЕССИЯ 11 (2026-09-27) — АУДИТ ПОДГОТОВКИ ДИФФА: 2 КОСМЕТИЧЕСКИХ ДЕФЕКТА + +**Задача:** пройти дифф построчно, валидировать адекватность (`DIFF-new-vs-38.csv`). + +### ✅ ЧТО ПРОВЕРЕНО И ПОДТВЕРЖДЕНО + +Артефакты на момент аудита (НЕ менялись этой сессией): + +``` +APPLY-PLAN.csv 7861 строка md5 7679ee01a2aa8f28623b6fb8559d7381 +DIFF-new-vs-38.csv 5000 строк md5 53716eea5accbffe50dbc0ee3a8ef8f7 +tag-fix-plan.csv 7861 строка md5 203726ebfd2814e2328636df31337238 +``` + +Состав диффа (подтверждён независимым парсером `csv.DictReader`): + +| scope | строк | примечание | +|---|---:|---| +| `ТРЕК` | 3751 | построчные правки | +| `ПАПКА` | 1123 | схлопнутые, 569 уникальных папок | +| `ТОЛЬКО-В-38` | 85 | файлы, которых нет в новом плане | +| `НЕТ-В-38` | 41 | файлы без строки в 38-м плане | + +По полям: `genre` 2509 · `track` 987 · `albumartist` 784 · `album` 319 · `artist` 233 · `title` 42. + +**Инвариант полноты сошёлся** — `covered + len(file_lines) == sum(field_counts)`, `assert` в +`diff_new_vs_38.py` не сработал. Потерь правок нет. Сортировка внутри каждого блока строгая: +`ПАПКА` по `(field, folder)`, `ТРЕК` по `(field, folder, path)`, обе секции хвоста по `path` — +нарушений 0. `scope`-порядок в файле: `ПАПКА → ТРЕК → НЕТ-В-38 → ТОЛЬКО-В-38`. + +### 🔴 ДЕФЕКТ 1 (найден Alex): порядок блоков нечитаем — 13 блоков вместо 4 + +Alex: «она не по полю! там album, albumartist, genere, потом сново album!». +Прав — первый ответ («файл отсортирован field-major, 4 блока») **был ошибочным**. + +**Реальная структура (13 field-run блоков, а не 4):** + +``` +ПАПКА: album(1-75) → albumartist(76-639) → artist(640-644) → genre(645-1114) → track(1115-1123) +ТРЕК: album(1124-1367) → albumartist(1368-1587) → artist(1588-1815) + → genre(1816-3854) → title(3855-3896) → track(3897-4874) +НЕТ-В-38 4875-4915 +ТОЛЬКО-В-38 4916-5000 +``` + +**Причина:** в `diff_new_vs_38.py` два независимых сортировщика, и `scope` **не входит в ключ**: + +```python +# строка 199 — секция ПАПКА +sorted(collapse_lines, key=lambda x: (fkey(x[1]), x[0])) +# строка 201 — секция ТРЕК +sorted(file_lines, key=lambda x: (fkey(x[2]), x[0], x[1])) +``` + +Поэтому блок `album` из ТРЕК идёт сразу за `track` из ПАПКА — визуально «album → albumartist +→ genre → снова album». Дубля нет, это **переход между секциями**, но читается как хаос. +Одна папка встречается до 5 раз в разных field-блоках. + +**Варианты починки (предложены Alex, ответа пока НЕТ):** + +| # | Что сделать | Оценка | +|---|---|---| +| **1** ⭐ | сортировать по `folder`, поле вторично — все правки папки рядом | рекомендуется | +| 2 | `key=(scope, field, folder)` — секции разделятся, прыжки папок останутся | минимальная правка | +| 3 | вариант 1 + вынести `НЕТ-В-38`/`ТОЛЬКО-В-38` в отдельный файл | чистит хвост | + +### 🔴 ДЕФЕКТ 2: хвост файла — не дифф, а отчёт полноты + +`НЕТ-В-38` (41) + `ТОЛЬКО-В-38` (85) = 126 строк после диффа. Alex: «в конце файла вообще +нипонятно че происходит». + +`ТОЛЬКО-В-38` — это **неизменённые файлы**, а не правки к применению: + +| расширение | строк | +|---|---:| +| `.ogg` | 40 | +| `.m4a` | 26 | +| `.wma` | 16 | +| `.mp3` | 2 | +| `.flac` | 1 | + +Это ровно те форматы, которые ID3-писатель не трогает (см. W-класс: писатель без фильтра +`.mp3` разрушает контейнеры). Секции существуют только как доказательство полноты покрытия. + +**Топ папок в `ТОЛЬКО-В-38`:** `Infected Mushroom/(2012) Army of Mushrooms` (26), +`Muse/2003 - Absolution` (14), `Кирпичи/2004 - let's rock!` (13), `!Рэп/НТЛ/wma` (13). + +### 🔴 УРОК МЕТОДА (зафиксировать) + +Проверка «отсортировано?» через `data == sorted(data)` по **кортежу целиком** даёт `True`, +даже когда блоки полей идут не по порядку — сортировка по `(field, folder)` математически +корректна, но семантически нечитаема. Смотреть надо **список переходов** (`prev != cur` → +новая строка), а не только факт монотонности. Первый отчёт («4 блока» и «сортировка строгая») +был построен на агрегированном `Counter` и пропустил 9 из 13 переходов. + +**Правило:** для отчёта о структуре файла выводить **явный список границ блоков** с номерами +строк, а не агрегат по `Counter`. + +### ⏭ СЛЕДУЮЩИЙ ШАГ (после сессии 11) + +1. **Ждёт ответа Alex:** номер варианта починки сортировки (1 / 2 / 3). +2. Глазами пройти `field=album` в диффе (ПАПКА-записи). +3. Затем `field=albumartist`. +4. Боевой прогон `--apply --verify` — **не запущен**, ждёт отдельного «go». +5. Контейнер `snapcur` на NAS (`:ro`) — **не убран**, Alex не подтвердил. + +### 🧰 ИНСТРУМЕНТЫ СЕССИИ 11 + +| Файл | Назначение | +|---|---| +| `/tmp/diff_audit.py` | порядок scope-секций + монотонность по каждому блоку + хвост файла | +| `/tmp/diff_audit2.py` | разбор «прыжков» (field-блоки) + расширения/папки `ТОЛЬКО-В-38` | +| `/tmp/diff_audit3.py` | **явный список переходов** `(scope, field)` с номерами строк — главный инструмент | + +⚠️ Все три — в `/tmp` (только чтение). Если аудит понадобится повторно — переписать в +`~/Downloads/music-tags/`. + ## 📊 ИТОГ СЕССИЙ 7-10: ~440 строк по четырём классам | Класс | Проявление | Детектор | Объём | diff --git a/personal/tech/id3-tag-repair.md b/personal/tech/id3-tag-repair.md index 5d8471eb..f97866a4 100755 --- a/personal/tech/id3-tag-repair.md +++ b/personal/tech/id3-tag-repair.md @@ -23,8 +23,12 @@ related: > Зеркало скилла `id3-tag-repair` (категория `media`, `~/.hermes/hermes-whale/skills/media/id3-tag-repair/`). > Скилл — для исполнения, этот док — для контекста проекта и истории. > -> ⚠️ **Скилл обновлён до v1.3.0** — добавлены правила **D1–D6** (слой диффа планов, +> ⚠️ **Скилл обновлён до v1.4.0** — добавлены правила **D1–D6** (слой диффа планов, > раздел «🔵 Слой ДИФФА планов» ниже). Полные формулировки — в `SKILL.md` скилла. +> +> ⚠️ **Обновлён до v1.5.0 (сессия 11):** правила **D9** (порядок блоков: монотонность ≠ +> читаемость) и **D10** (служебные секции полноты в хвосте диффа). См. тот же раздел, +> а также `personal/plans/music-artist-albumartist-repair.md` § «🔷 СЕССИЯ 11». ## 📁 Артефакты проекта @@ -359,6 +363,36 @@ z Другое…/C.Шнуров - Бумер (2003) 19 → Сергей Реакция Alex (со «стоп»): «**красную плесень в красную плесень - виа меа в виа меа - не объединять корень Другого в альбом**». +### 🔴 D9 — «отсортировано?» по агрегату пропускает нечитаемый порядок блоков + +`data == sorted(data)` по кортежу целиком даёт `True` для `DIFF-new-vs-38.csv`, хотя файл +состоит из **13 field-run блоков**, а не 4: секции `ПАПКА` и `ТРЕК` сортируются **независимо** +(`key=(fkey(field), folder…)`), `scope` в ключ не входит → `album` из `ТРЕК` идёт сразу за +`track` из `ПАПКА`, визуально «album → albumartist → genre → снова album». + +``` +ПАПКА: album → albumartist → artist → genre → track +ТРЕК: album → albumartist → artist → genre → title → track +``` + +Агрегированный `Counter(field)` показывает 4 «блока» и прячет 9 из 13 переходов. Одна папка +встречается до 5 раз, не подряд. + +**Правило:** для отчёта о структуре выводить **явный список границ блоков** (`prev != cur` → +новая строка) с номерами строк, а не агрегат по `Counter`. Монотонность ≠ читаемость. + +См. `personal/plans/music-artist-albumartist-repair.md` § «🔷 СЕССИЯ 11». + +### 🔴 D10 — секции полноты в хвосте диффа читаются как мусор + +`НЕТ-В-38` (41) + `ТОЛЬКО-В-38` (85) идут после правок и выглядят как сломанный хвост файла. +`ТОЛЬКО-В-38` — это **неизменённые** файлы: `.ogg` 40, `.m4a` 26, `.wma` 16, `.flac` 1, `.mp3` 2 +— ровно форматы, которые ID3-писатель не трогает. Это отчёт покрытия, а не правки. + +**Правило:** служебные секции полноты выносить в отдельный файл, либо явно помечать шапкой +«НЕ ПРАВКИ — контроль покрытия». Иначе человек, читающий дифф сверху вниз, принимает их за +дефект. + ### 🔴 A6 — разнобой написания серии + технические суффиксы в `album` Один релиз жил в четырёх написаниях, плюс `(CD1)`/`(CD2)` в значении: