[2026-09-26] eagle: family/how-to/vault-git-sync.md personal/plans/balda-mm-pr-plan.md personal/tech/balda-go-fx-pitfalls.md personal/tech/music-tags-repair-truenas.md
This commit is contained in:
1 parent
e200596c45
commit
036e7a7091
4 files changed
+272
-30
No files matched your search
@@ -1192,6 +1192,37 @@ git log --oneline --name-only <mой_первый_коммит>^..HEAD -- '<dir>
|
||||
Альтернатива без «удаления»: оставить файлы untracked, а из индекса убрать одним
|
||||
явным коммитом по команде Alex.
|
||||
|
||||
## 🔴 PR-гигиена: проверять состав ветки, а не свои коммиты
|
||||
|
||||
База ветки `004fda2f` (коммит **прошлой сессии**) затащила в PR **16 файлов `tools/`**
|
||||
(`apply-project-deltas.py`, `run-project-deltas.sh`, `deltas-mattermost*.json`,
|
||||
`.deltas-state.json`). В апстриме каталога `tools/` **нет вообще** — проверка:
|
||||
`git ls-tree upstream/main tools/` → пусто.
|
||||
|
||||
🔴 **Свои коммиты были чистыми**, но ветка — нет:
|
||||
```bash
|
||||
git log --oneline --name-only upstream/main..HEAD -- 'tools/' # → показал базу, не мои коммиты
|
||||
```
|
||||
Поэтому смотреть надо **состав PR**, а не свои коммиты:
|
||||
```bash
|
||||
git diff --name-only upstream/main...HEAD # все файлы PR
|
||||
git diff --name-only upstream/main...HEAD | grep -v '^tools/' # что должно остаться
|
||||
```
|
||||
|
||||
**Фикс — два шага, оба обязательны:**
|
||||
```bash
|
||||
echo '/tools/' >> .gitignore
|
||||
git rm -r --cached tools/ # 🔴 файлы ОСТАЮТСЯ на диске, уходят только из git
|
||||
```
|
||||
|
||||
⚠️ **`gitignore` НЕ отвязывает уже отслеживаемые файлы.** Без `git rm --cached` файлы
|
||||
останутся в индексе навсегда, сколько ни игнорь их.
|
||||
⚠️ `git rm -r --cached` уходит на **апрув** (рекурсивное удаление) — если апрув истёк,
|
||||
команда **не выполнилась**, состояние целое; проверить `git diff --cached --name-only`
|
||||
до повтора.
|
||||
⚠️ Артефакты деплоя (`mm-*.sh` ops-скрипты) в PR не шлём — только код транспорта,
|
||||
wiring, тесты, доки.
|
||||
|
||||
## Связанные заметки
|
||||
|
||||
- [[personal/projects/balda/balda-mattermost-connector]] — Фаза 2, где всё это найдено
|
||||
|
||||
@@ -18,8 +18,81 @@ related:
|
||||
---
|
||||
# Music Tags Repair — TrueNAS (7906 файлов)
|
||||
|
||||
> **Статус: ЭТАПЫ 1–2 ЗАВЕРШЕНЫ (2026-09-26), затем ПЕРЕДЕЛАНЫ после замечаний Alex. CSV v2 передан. Документы ревью залиты в vault и синкнуты. Правки файлов НЕ начаты.**
|
||||
> Следующий шаг — апрув Alex по CSV, затем бэкап + применение.
|
||||
> **Статус: ЭТАПЫ 1–2 ЗАВЕРШЕНЫ (2026-09-26). CSV v3 + ноты ревью отданы Alex. Правки файлов НЕ начаты.**
|
||||
> Следующий шаг — апрув Alex по нотам ревью, затем бэкап + применение.
|
||||
> Перед выдачей проведён **полный аудит всех 4774 строк** (`audit_plan.py` + `final_gate.py`) — найдено и исправлено 6 багов.
|
||||
|
||||
## 🔴 ВТОРАЯ ВОЛНА ИСПРАВЛЕНИЙ (2026-09-26, «Сам проверил весь файл на адекватность?»)
|
||||
|
||||
Alex: **«Сам проверил весь файл на адекватность? Чтобы я в очевидные вещи тебя не тыкал.»**
|
||||
Честный ответ был — **нет, полностью не проверил**: до этого гонялись только выборочные проверки
|
||||
(`find_bad_titles.py` — 5 метрик). Полный аудит по всем 4774 строкам нашёл **6 реальных багов**.
|
||||
|
||||
| # | Баг | Файлов | Как проявлялся | Фикс |
|
||||
|---|---|---:|---|---|
|
||||
| 1 | `artist = Сказки` | **238** | Папка-контейнер `!Детские/Сказки/` попадала в artist → Jellyfin показал бы 238 треков одним «исполнителем» | `NON_ARTIST` применяется к контейнеру; под деревом сказок одиночная папка идёт в **album**, artist пустой |
|
||||
| 2 | Mojibake выживал рядом с латиницей | **127** | `Èâàíóøêè International`, `Ìóìèé Òðîëëü vs DJ Scratchin` — guard по доле кириллицы **на всю строку** отвергал конверсию | `fix_encoding` переписан **пословно** (`re.split(r"(\s+)")`): битые слова чинятся, латиница не трогается |
|
||||
| 3 | Имя радиовыпуска как артист | **31** | `!Radio/y OOF/`, `v 2009-03 mIr.vEsNЫ` → artist | `is_release_folder()`: `!`-префикс, год, `RELEASE_WORDS`; плюс fallback на имя файла |
|
||||
| 4 | Номер склеен с названием | **17** | `11 Track 11`, `04 Yves Larock - Rise Up` | Срезание ведущего номера + `title<-filename(denumbered)` |
|
||||
| 5 | `album = '+'` | **10** | Папка `старые/+/` — только символы | `clean_folder()`: компонент без букв/цифр отбрасывается |
|
||||
| 6 | `©` как title | **1** | Значение из одних символов | `clean_value()` отвергает значение без `isalnum()` |
|
||||
|
||||
**Дополнительно поймано и исправлено:**
|
||||
- `Пилот/1999 Жывой Концерррт` — фильтр релизов убивал **легитимный альбом** с годом. Разделено: строгая проверка только для **слота артиста** (`dirs[-2]`), альбом может содержать год.
|
||||
- 18 правок без `source` → теперь помечаются `encoding/cleanup only`.
|
||||
- Ложные тревоги, разобранные вручную (НЕ баги): `Би-2/2001 Би-2`, `Рубль/Рубль`, `Сектор Газа/1989 - Сектор Газа` — **одноимённые альбомы**; `NTL`, `Eagles`, `Carl Orff` — реальная латиница; `NTL ft. MC Молодой`, `Flёur` — нормальные смешанные имена.
|
||||
|
||||
### 📊 Цифры после второй волны
|
||||
|
||||
| Метрика | v1 (отклонён) | v2 | **v3 (финал)** |
|
||||
|---|---:|---:|---:|
|
||||
| `fix` | 4601 | 4961 | **4774** |
|
||||
| `no_change` | 2946 | 2945 | 3132 |
|
||||
| `probe_failed` | 359 | 0 | **0** |
|
||||
| Ноты: «требует решения» | 9 | 9 | **296** |
|
||||
| Ноты: средняя | 2611 | 2611 | 2031 |
|
||||
| Ноты: высокая | 2341 | 2341 | 2447 |
|
||||
|
||||
> 📌 **«Требует решения» вырос 9 → 296 — это честнее.** Раньше вместо признания «источника нет»
|
||||
> подставлялся мусор (`Сказки`, `y OOF`). Теперь такие файлы явно идут в блок 1.
|
||||
|
||||
**Итоговые гейты (все PASS):**
|
||||
|
||||
| Проверка | Скрипт | Результат |
|
||||
|---|---|---|
|
||||
| Полный аудит по классам ошибок | `audit_plan.py` | mojibake = **0**, `generic_artist` = **0**, `numeric_title` — законные |
|
||||
| Полнота и отсутствие заглушек | `final_gate.py` | **PASS** — нет `probe_failed`, пустых title, U+FFFD, правок без источника |
|
||||
| Регресс-тесты | `test_plan2.py` | **65/65 PASS** |
|
||||
|
||||
**Оставшиеся флаги аудита — все проверены вручную и законны:** `album == artist` (49, одноимённые альбомы),
|
||||
`translit_kept` (83, реальная латиница), `mixed_script` (19, `NTL ft. MC Молодой`), `numeric_title` (15, `007`/`48`).
|
||||
|
||||
## 📡 SYNCTHING: ноты доехали, но найдено расхождение в расписании
|
||||
|
||||
Проверка по просьбе Alex («Проверь что syncthing всосал доку»). Первая проверка показала:
|
||||
`obsidian-syncthing` **отстал на 3 коммита**, нот в нём нет.
|
||||
|
||||
**Причина — не Syncthing.** Цепочка «bare repo → git-клон `obsidian-syncthing` → Syncthing → телефон»
|
||||
рвётся на **втором** шаге: job `sync-vault` в контейнере `hermes-taiga` расписан **`0 * * * *` — раз в час**,
|
||||
хотя в `[[family/how-to/vault-git-sync]]` записано «каждые 5 минут».
|
||||
|
||||
**Что сделано:** job триггернут вручную (`hermes cron run 29851c413903`). Проверено:
|
||||
|
||||
| Проверка | Значение |
|
||||
|---|---|
|
||||
| Клон `obsidian-syncthing` | ✅ HEAD `e200596`, 4 файла на месте |
|
||||
| Syncthing: очередь | ✅ `needFiles: 0`, `needItems: 0`, `needDeletes: 0` |
|
||||
| Синк с телефоном | ✅ `completion: 100`, `remoteState: valid` |
|
||||
| Ошибки | ✅ `errors: 0` |
|
||||
| Версия Syncthing | `v2.1.5 "Hafnium Hornet"`, папка `k5vyy-gzdgj` «Obsidian Vault» |
|
||||
|
||||
**Питфоллы синка этой сессии:**
|
||||
- 🔴 **Порт Syncthing `8384` слушает ТОЛЬКО внутри контейнера** — `curl` с хоста TrueNAS отдаёт пустоту.
|
||||
Запрос API делать через `docker exec syncthing curl -s -H "X-API-Key: …" http://localhost:8384/rest/…`.
|
||||
- ⚠️ **`obsidian-syncthing` — git-клон (remote `/vault.git`), а не Syncthing-папка.** Обновляет его
|
||||
Taiga по крону; Syncthing лишь раздаёт то, что уже в клоне. «Syncthing здоров» ≠ «док доехал».
|
||||
- ⚠️ **Скрипт диагностики синка** — `check_syncthing2.sh` (в `tools/music-tags/`): версия, статус папки,
|
||||
connections, completion для телефона. Писать в файл, а не инлайн — иначе `APIKEY=` в heredoc режется.
|
||||
|
||||
## 📋 ДОКУМЕНТЫ РЕВЬЮ В VAULT (2026-09-26)
|
||||
|
||||
@@ -30,9 +103,9 @@ CSV отдан не только файлом, но и **читаемыми но
|
||||
| Файл | Содержимое |
|
||||
|---|---|
|
||||
| `music-tags-review.md` | **Обзор** — сводка, ссылки на три блока |
|
||||
| `1-needs-decision.md` | **Требует решения** (9 файлов) — исполнителя взять неоткуда |
|
||||
| `2-medium-confidence.md` | **Средняя уверенность** (2611) — из имён файлов и папок |
|
||||
| `3-high-confidence.md` | **Высокая уверенность** (2341) — точная перекодировка |
|
||||
| `1-needs-decision.md` | **Требует решения** (296) — исполнителя взять неоткуда |
|
||||
| `2-medium-confidence.md` | **Средняя уверенность** (2031) — из имён файлов и папок |
|
||||
| `3-high-confidence.md` | **Высокая уверенность** (2447) — точная перекодировка |
|
||||
|
||||
**Формат (запрос Alex):** порядок от «требует решения» к «высокая уверенность»,
|
||||
каждый файл = чекбокс `- [ ] **имя.mp3**` + подпункты `field: старое → новое` + источник.
|
||||
@@ -40,10 +113,10 @@ CSV отдан не только файлом, но и **читаемыми но
|
||||
|
||||
**Генератор:** `render_grouped_doc.py` (Mac, `~/Developer/personal-os/tools/music-tags/`).
|
||||
|
||||
**Синк:** `bash ~/scripts/sync-vault.sh` → `Pushed ✓`, коммит `14e9f570`.
|
||||
Проверено в bare repo: `git ls-tree -r HEAD | grep music-tags` → 4 файла на месте.
|
||||
**Синк:** `bash ~/scripts/sync-vault.sh` → `Pushed ✓`. Последний коммит после второй волны
|
||||
залит, клон `obsidian-syncthing` обновлён до `e200596`, Syncthing раздал телефону (`completion: 100`).
|
||||
|
||||
> ⚠️ Блоки 2 и 3 — по 730–780 КБ, 5000+ строк. Obsidian открывает, но скролл тяжёлый.
|
||||
> ⚠️ Блоки 2 и 3 — по 580–790 КБ. Obsidian открывает, но скролл тяжёлый.
|
||||
> Облегчение — оглавление по папкам в начале каждого файла (клик → прыжок к разделу).
|
||||
> Если Alex попросит — разбить по категориям на отдельные файлы.
|
||||
|
||||
@@ -333,15 +406,19 @@ if cyr < 2: # одна буква — совпадение
|
||||
| # | Шаг | Статус |
|
||||
|---|---|---|
|
||||
| 1 | **Инвентаризация** read-only: `ffprobe` по 7906 файлам → CSV | ✅ **ГОТОВО (v2)** — `tag_inventory2.py`, `probe_failed`=0 |
|
||||
| 2 | **CSV с предлагаемым исправлением** → Alex | ✅ **ГОТОВО (v2)** — `~/Downloads/music-tags/tag-fix-plan.csv` |
|
||||
| 2a | **Ноты для ревью в Obsidian** → Alex (запрос Alex 2026-09-26) | ✅ **ГОТОВО** — `personal/plans/music-tags-review/`, синкнуто (`Pushed ✓`, коммит `14e9f570`) |
|
||||
| 3 | **Апрув Alex по CSV** → только после этого правки | ⏳ **ЖДЁМ** (v1 отклонён, v2 + ноты отданы) |
|
||||
| 2 | **CSV с предлагаемым исправлением** → Alex | ✅ **ГОТОВО (v3)** — `~/Downloads/music-tags/tag-fix-plan.csv`, 4774 `fix` |
|
||||
| 2a | **Ноты для ревью в Obsidian** → Alex (запрос Alex) | ✅ **ГОТОВО** — `personal/plans/music-tags-review/`, синкнуто + доехало до телефона |
|
||||
| 2b | **Полный аудит всех строк** (`audit_plan.py` + `final_gate.py`) → 6 багов исправлено | ✅ **ГОТОВО** (запрос Alex «Сам проверил весь файл?») |
|
||||
| 3 | **Апрув Alex по нотам ревью** → только после этого правки | ⏳ **ЖДЁМ** (v1 и v2 отклонены, v3 + ноты отданы) |
|
||||
| 4 | **Бэкап** — копировать **только перезаписываемые** файлы в `Music/backup/` | ⏳ |
|
||||
| 5 | **Ремонт** — перекодировка mojibake + восстановление из имён путей + чистка мусора | ⏳ |
|
||||
| 6 | **Приёмка** — Alex слушает выборку | ⏳ |
|
||||
|
||||
> 📌 **Что именно ждёт апрува:** 4961 `fix` из 7906. Alex проходит по трём нотам ревью,
|
||||
> 📌 **Что именно ждёт апрува:** 4774 `fix` из 7906. Alex проходит по трём нотам ревью,
|
||||
> отмечает чекбоксы. Ничего не применяется до его «go».
|
||||
>
|
||||
> 🔴 **Открытый вопрос к Alex:** расписание job `sync-vault` в Taiga — `0 * * * *` (раз в час),
|
||||
> хотя доки говорят «каждые 5 минут». Менять на `*/5 * * * *` или оставить?
|
||||
|
||||
### Ключевые решения по плану (правки Alex)
|
||||
|
||||
@@ -379,19 +456,25 @@ if cyr < 2: # одна буква — совпадение
|
||||
| `id3_direct.py` | **Прямой парсер ID3v2** из байтов файла (минуя `ffprobe`). Поддержка ID3v2.2/2.3/2.4, кодировок 0–3, extended header. Используется как fallback и как отладочный инструмент |
|
||||
| `analyse_inventory.py` | Анализ CSV инвентаря: доли вердиктов, проверка обратимости mojibake, разбор `lost`/`probe_failed` |
|
||||
| `build_fix_plan.py` | **Этап 2 (v1, устарел).** Содержал ранний выход по `probe_failed` — из-за него ДДТ отдавались пустыми |
|
||||
| `build_fix_plan2.py` | **Этап 2 (v2, актуальный).** Ранний выход убран, `prettify_translit` добавлен. Содержит `fix_encoding`, `clean_value`, `repair`, `split_artist_title`, `title_from_name`, `derive_from_path`, `prettify_translit` |
|
||||
| `build_fix_plan2.py` | **Этап 2 (v3, актуальный).** Пословный `fix_encoding`, `NON_ARTIST`-контейнеры, `is_release_folder`, `clean_folder`, `prettify_translit`, срезание ведущего номера. Функции: `_try_convert`, `has_release_in_path`, `fix_encoding`, `clean_value`, `clean_folder`, `repair`, `split_artist_title`, `title_from_name`, `derive_from_path`, `is_release_folder`, `prettify_translit` |
|
||||
| `audit_plan.py` | **ПОЛНЫЙ аудит плана по всем строкам** (не сэмплы). Классы: `damaged_output`, `mixed_script_artist`, `translit_kept`, `watermark`, `numeric_title`, `artist_equals_title`, `generic_artist`, `album_equals_artist`, `one_char_title`, `whitespace`, `no_visible_change` |
|
||||
| `final_gate.py` | **Гейт полноты перед выдачей.** Проверяет: совпадение числа строк с инвентарём, отсутствие заглушек (`probe_failed`/`investigation`), пустых title, U+FFFD, правок без `source`. Печатает PASS или точные строки |
|
||||
| `deepdive_audit.py` | Углублённый разбор крупнейших классов (`generic_artist`, `translit_kept`) — по папкам и сырым значениям |
|
||||
| `separate_moji.py` | Отделяет **настоящий mojibake** от **законной латиницы** (`NTL`, `Eagles`) по доле маркеров CP1251 |
|
||||
| `review_classes.py` | Печать контекста по каждому классу аудита, сгруппировано по папке — чтобы судить целым альбомом |
|
||||
| `check_syncthing2.sh` | **Диагностика синка**: версия Syncthing, статус папки, connections, completion для телефона. Запрос через `docker exec syncthing curl … :8384` |
|
||||
| `check_fix_plan.py` | Контроль качества плана: U+FFFD на выходе, пустые title/artist, сэмплы «до/после» по категориям |
|
||||
| `find_bad_titles.py` | Ищет недоработки: `TrackNN` в title, голые номера, пустой artist |
|
||||
| `check_ddt_album.py` | Печатает **полный набор сырых тегов** файлов по маске — для проверки «баг скрипта vs так в файле» |
|
||||
| `diagnose_probe_failures.py` | Анализ заголовков файлов, упавших в `probe_failed`: ID3-версия, `hdr_ok`, размеры |
|
||||
| `test_encoding_guard.py` | **32 регресс-теста.** Защита от порчи корректного UTF-8 (`Björk`, `Saint-Saëns`, `Noël`) + `split_artist_title` |
|
||||
| `test_plan2.py` | **Регресс-тесты v2.** Включая отказ сплита на event-именах (`НАШЕСТВИЕ 2009 - ДЕНЬ ВТОРОЙ` остаётся целиком в title) |
|
||||
| `test_encoding_guard.py` | **32 регресс-теста (v1).** Защита от порчи корректного UTF-8 (`Björk`, `Saint-Saëns`, `Noël`) + `split_artist_title` |
|
||||
| `test_plan2.py` | **65 регресс-тестов (v3, актуальный).** Пословная конверсия смешанных строк, короткие токены (`7Á`→`7Б`), контейнеры не становятся артистом, release-папки, отказ сплита на event-именах |
|
||||
| `render_grouped_doc.py` | **Генератор нот для Obsidian.** CSV → 3 блока по уверенности + обзор, группировка по папкам, чекбоксы, оглавление |
|
||||
|
||||
| Артефакт | Где | Что |
|
||||
|---|---|---|
|
||||
| CSV-инвентарь v2 | `/mnt/RED_2TB/storage/tmp/tag-inventory2.csv` (NAS) → `~/Downloads/music-tags/tag-inventory.csv` (Mac) | 7906 строк, колонка `source`, `probe_failed`=0 |
|
||||
| **CSV-план правок v2** | `~/Downloads/music-tags/tag-fix-plan.csv` (Mac, 2.2 МБ) | **Отдан Alex 2026-09-26.** 4961 `fix` / 2945 `no_change` / 0 `probe_failed` |
|
||||
| **CSV-план правок v3** | `~/Downloads/music-tags/tag-fix-plan.csv` (Mac, ~2.2 МБ) | **Отдан Alex 2026-09-26 (финал).** 4774 `fix` / 3132 `no_change` / 0 `probe_failed` |
|
||||
| Копия БД Jellyfin | `/tmp/jf-copy.db` (Mac) | Для чтения API-ключа (см. `[[family/how-to/jellyfin-config]]`) |
|
||||
| Копия плана на NAS | `/tmp/tag-fix-plan.csv` (NAS) | Для запуска `id3_direct.py`/`check_ddt_album.py` с хостовым Python |
|
||||
| **Ноты ревью в vault** | `personal/plans/music-tags-review/` (4 файла) | Обзор + 3 блока по уверенности; **вход для апрува Alex**, синкнуто |
|
||||
@@ -436,6 +519,14 @@ if cyr < 2: # одна буква — совпадение
|
||||
- 🔴 **`execute_code` требует апрува** — Alex явно сказал: **«Без аппрува команды используй! Скрипты пиши»**. Писать исполняемое в файл (`write_file`) → запускать через `terminal`. Не инлайн.
|
||||
- 🔴 **Наивная перекодировка CP1251→Latin-1 портит корректный UTF-8** (`Saint-Saëns` → `Saint-Saлns`). Обязателен guard по доле кириллицы (см. выше).
|
||||
- 🔴 **`ffprobe` молча отдаёт ПУСТЫЕ теги** при битом фрейме внутри (напр. `comment='eng'`) — при `exit=0` и валидном JSON. Нельзя считать «пусто от `ffprobe`» доказательством отсутствия тегов. Нужен fallback-парсер ID3 (`id3_direct.py`).
|
||||
- 🔴 **Guard по доле кириллицы на ВСЮ строку ломает смешанные значения.** `Èâàíóøêè International` — битая кириллица + настоящая латиница; соотношение на строку не проходит порог, и mojibake **выживает**. Конвертировать **пословно** (`re.split(r"(\s+)")`), плюс второй проход по одиночным буквам (`Василий Ê`) при условии, что соседнее слово конвертировалось.
|
||||
- 🔴 **Токены с пунктуацией вне Latin-1 (`Ãëþê'OZA`) не конвертируются целиком** — `encode("latin-1")` падает на апострофе. Нужен посимвольный проход с проверкой итоговой доли кириллицы (≥50%).
|
||||
- 🔴 **Папка-контейнер (`Сказки`, `Разное`, `Различные исполнители`) — не артист.** Прямая подстановка `d_artist` даёт 238 файлов с одним «исполнителем». Контейнерный уровень отбрасывается; под деревом сказок одиночная папка идёт в **album**, artist пустой.
|
||||
- 🔴 **Папки релизов (`!Radio`, `y OOF`, `v 2009-03 mIr.vEsNЫ`) — не артисты.** Признаки: `!`-префикс, год в имени, `RELEASE_WORDS` (`radio`, `chart`, `mix`, `окtoberfest`…).
|
||||
- ⚠️ **Фильтр релизов не должен применяться к альбомам.** `Пилот/1999 Жывой Концерррт` содержит год, но это легитимный альбом. Проверять **только слот артиста** (`dirs[-2]`), не все компоненты пути.
|
||||
- ⚠️ **Значения из одних символов (`©`, `+`, `(17)`) — мусор.** И для тегов (`clean_value`), и для папок (`clean_folder`) — отвергать, если нет ни одной буквы/цифры.
|
||||
- ⚠️ **Ведущий номер, склеенный с названием (`11 Track 11`, `04 Yves Larock - Rise Up`),** — срезать регекспом и брать имя файла.
|
||||
- ⚠️ **Проверка «без источника» может ложно срабатывать** на правках, где изменились только пробелы/водяные знаки. Помечать такие явно (`encoding/cleanup only`), а не оставлять пустым `source`.
|
||||
- 🔴 **Ранний `continue` по «нераспознанному» вердикту = потеря файлов.** Именно так 359 файлов ушли заглушками, а ДДТ — без artist/title. **Неизвестный вход обрабатывать общей логикой, а не пропускать.**
|
||||
- 🔴 **Нельзя отдавать пользователю вывод, не проверив сэмплы проблемных групп.** CSV v1 ушёл Alex без проверки `probe_failed` и `!Retro` — и был справедливо раскритикован. Проверка = прогон `check_fix_plan.py` + `find_bad_titles.py` + выборочный `check_ddt_album.py`.
|
||||
- ⚠️ **Правка скриптов только локально → `scp` заново.** `sed -i` на NAS применён быть не должен (была такая ошибка, исправлена).
|
||||
@@ -445,20 +536,30 @@ if cyr < 2: # одна буква — совпадение
|
||||
### 🧠 ГЛАВНЫЙ ПРОЦЕССНЫЙ УРОК ЭТОЙ СЕССИИ
|
||||
|
||||
Alex: **«Ты бы хоть постеснялся не проверив мне файл сувать!»**
|
||||
Alex (вторая волна): **«Сам проверил весь файл на адекватность? Чтобы я в очевидные вещи тебя не тыкал.»**
|
||||
|
||||
Порядок работы, который себя оправдал **после** исправления:
|
||||
**Ключевое различие, которое стоило двух итераций: выборочная проверка ≠ полный аудит.**
|
||||
После первой правки были «пройдены все проверки» — но это были 5 метрик на сэмплах. Полный аудит
|
||||
по всем 4774 строкам нашёл ещё **6 багов**, крупнейший — 238 файлов с `artist = Сказки`.
|
||||
|
||||
Порядок работы, который себя оправдал:
|
||||
|
||||
1. Написать скрипт **в файле** (`write_file`) — не инлайн, не `execute_code`.
|
||||
2. Прогнать **автотесты** на краевых случаях (латиница с умляутами, дефисы, номера).
|
||||
3. Прогнать **контрольные проверки** на реальном выводе: U+FFFD, пустые поля, оставшийся мусор.
|
||||
4. **Посмотреть сэмплы «до/после» глазами** по каждой проблемной группе.
|
||||
5. Проверить **сырые данные конкретного файла**, прежде чем спорить «это баг / не баг».
|
||||
6. **Только потом** отдавать пользователю.
|
||||
2. Прогнать **автотесты** на краевых случаях (латиница с умляутами, дефисы, номера, смешанные строки).
|
||||
3. **Прогнать ПОЛНЫЙ аудит по всем строкам**, а не по сэмплам (`audit_plan.py`).
|
||||
4. **Прогнать гейт полноты** (`final_gate.py`) — заглушки, пустые поля, правки без источника.
|
||||
5. Посмотреть сэмплы «до/после» глазами по каждой проблемной группе.
|
||||
6. Проверить **сырые данные конкретного файла**, прежде чем спорить «это баг / не баг».
|
||||
7. Отделить **настоящие дефекты от законных случаев** (`separate_moji.py`, `review_classes.py`):
|
||||
`NTL`/`Eagles` — латиница, `Би-2/2001 Би-2` — одноимённый альбом.
|
||||
8. **Только потом** отдавать пользователю.
|
||||
|
||||
Три бага были пойманы пунктами 3–4 **до** выдачи. Пункт 5 отличает «баг скрипта» от «так в файле» (случай ДДТ).
|
||||
**Заглушка `needs investigation` в отчёте — это не результат, а моя недоработка.**
|
||||
**Заглушка `needs investigation` в отчёте — это не результат, а недоработка.**
|
||||
**«Требует решения» — законный исход, но должен быть явным, а не замаскированным мусором.**
|
||||
|
||||
### 🐞 Три бага, пойманные ДО выдачи CSV (файлы не пострадали)
|
||||
### 🐞 Девять багов, пойманных ДО выдачи (файлы не пострадали)
|
||||
|
||||
**Первая волна (3 бага, сэмплами):**
|
||||
|
||||
| # | Баг | Как пойман | Фикс |
|
||||
|---|---|---|---|
|
||||
@@ -466,9 +567,12 @@ Alex: **«Ты бы хоть постеснялся не проверив мне
|
||||
| 2 | `Camille Saint-Saëns` → `Camille Saint-Saлns` — перекодировка ломала корректный UTF-8 | `check_fix_plan.py`, сэмплы «partial» | Guard по доле кириллицы в результате (≥50%, ≥2 буквы) |
|
||||
| 3 | Управляющие байты (`\x1d`) в ID3 «чинились» вместо пометки | Просмотр сэмплов | `CONTROL_RE` → такие значения отвергаются, берётся имя файла |
|
||||
|
||||
> 🔑 **Методический вывод:** контроль качества плана (`check_fix_plan.py`) на сэмплах
|
||||
> «до/после» поймал все три бага. Без этого CSV ушёл бы Alex с испорченными предложениями.
|
||||
> **Всегда проверять вывод скрипта на сэмплах до передачи пользователю.**
|
||||
**Вторая волна (6 багов, полным аудитом):** см. таблицу «ВТОРАЯ ВОЛНА ИСПРАВЛЕНИЙ» в начале документа —
|
||||
`artist = Сказки` (238), mojibake рядом с латиницей (127), имя радиовыпуска как артист (31),
|
||||
номер склеен с названием (17), `album = '+'` (10), `©` как title (1).
|
||||
|
||||
> 🔑 **Методический вывод:** сэмплы ловят грубые ошибки, полный аудит — системные.
|
||||
> Оба нужны. Без полного аудита CSV v2 ушёл бы Alex с 238 файлами «исполнитель Сказки».
|
||||
|
||||
## Связанные заметки
|
||||
|
||||
|
||||
Reference in new issue
Block a user