◂ База знанийRYA.AEShoot Day Ingest — ночной разбор съёмочного дняобновлено 26 сен 2026
Съёмочный день приезжает как карта без общего таймкода: у трёх камер и четырёх приёмников часы разъехались почти на час. Поэтому день собирается по речи. За ночь, без человека рядом: пословная расшифровка → диаризация → сквозные голоса по всему дню → часы и синхрон → сцены → кадры с описанием → страница дня. Утром человек принимает, а не разбирает — и ставит имена голосам, потому что это единственное, чего машина не имеет права решать сама.
Живой пример всего, что ниже — разобранный день YTEVO03: паспорт дня и слепок страницы приёмки (зона канала YTEVO, свой пароль). Съёмка и раскладка до этого — 2.2 Shoot Day SOP.
Красная линия: карты открываются только на чтение. Ничего не создаём, не переименовываем, не перемещаем и не удаляем на носителе — раскладка по устройствам (M4ROOT = FX3, ZVe1/, DJI Pocket 4p, DJI-1…4) сама по себе контекст: чем снято и с какого приёмника звук. Сцены собираются симлинками поверх, в проекте. И карту не чистим, пока rclone check --size-only не подтвердит на Drive имя и точный размер каждого файла → 0.2 Media Prep.

🌙3.1 · 1Зачем ночной разбор — и что именно происходит за ночь

Стадия scripts/01_prepare/0120_day_ingest/. Считает полностью автономно и сама себя проверяет: ночью рядом никого нет.

467 ГБ на карте~900 файлов на карте172 видео105 петличных единиц3 камеры4 приёмника DJI Mic
В разбор идут 277 единиц (172 видео + 105 звука) — это и есть гейт первой стадии. Остальное на карте — сайдкары, превью и .LRF.

Выездной день и студийный — два этапа

ЭтапКакой деньЧем описан деньРаскладкаЧеловек нужен
0120_day_ingestвыезд, «день из жизни»: много людей, сцены по месту и времениконстантами в common_day.py — сделан под YTEVO03, гейты литералами01_Source/{NN_Сцена}/CAM-*сцены и имена голосов — карточка 4
0121_studio_dayстудия курса: эксперт и продюсер, урок за урокомфайлом day.json — код, дата, карта, камеры, петлички, люди, стыки, ожидаемые числа01_Source/{блок}/{тема}/{урок}/CAM-*только выбор цвета на витрине лутов
Студийный день не форкает выездной: common_day считает пути YTEVO03 на самом импорте, поэтому нормировка звука и чистка расшифровки в 0121 скопированы из s2_audio/s3_transcribe с указанием источника. Новая смена того же спринта = копия day.json с другой датой.
📝 asr_mic→ 🎚 audio_cam→ 📝 asr_cam→ ⏱ sync→ 🖥 screencast→ 🗂 takemap→ 📄 transcript→ 🔗 layout→ ✂️ lavcut→ 🎨 board→ 🎞 proxy→ ✅ verify→ ❓ doubts→ 📄 report
cd ~/YTAI/scripts/01_prepare/0121_studio_day
python3 index.py                 # перепись карты → index.json, дальше карту никто не сканирует
python3 audio.py --only mic      # рабочий звук петличек 16 кГц, уровень по RMS
python3 night.py --dry-run       # что сделает ночь, ничего не запуская
python3 night.py                 # asr_mic → … → report
python3 night.py --from proxy    # продолжить с шага
  • Голоса — по железу, а не по диаризации: TX01 на эксперте, TX02 на продюсере. pyannote и реестр голосов здесь не нужны; transcript.py решает только проникание — микрофон эксперта слышит продюсера и наоборот.
  • Урок = результат расшифровки. takemap.py сопоставляет дубль с карточкой урока по редким словам (эксперт пересказывает, а не читает с суфлёра), screencast идёт раньше — в имени записи экрана уже стоит номер урока. Поэтому раскладка layout.py — после карты дублей, а не до.
  • Ночь встаёт на первом проваленном шаге — деления на HARD/SOFT здесь нет: раскладка на непроверенном синхроне разложит дубли по чужим урокам. Витрина лутов (board) — до прокси, иначе в комплект уедут старые кубы.
  • Утром: 00_Setup/{CODE}_day1.html — что снято и чем доказано, {CODE}_day1_doubts.html — спорные дубли с кадром и уликами. Расшифровка внутри — 3.6 Transcription, раскладка — 3.2 Source Structure.

Почему общего таймкода нет

  • Часы устройств разъехались за день почти на час: FX3 +56:19,5 · ZV-E1 +1:01:01 · Pocket −0,85 с. Это решённые поправки из clocks.json, а не ошибка измерения: камерный TC на этом дне не был засинхронизирован, хотя 2.2 требует Free Run.
  • Sony: время и длительность — из посайдкарного *M01.XML (CreationDate со своим смещением зоны, от часов машины не зависит). Длительность = Duration / captureFps.
  • Pocket: время — из имени файла; контейнерный creation_time отстаёт от имени на 0–4 с.
  • DJI Mic: имя файла = BWF creation_time; поле time_reference игнорируется — в нём три несовместимые популяции (верное время / ноль / сдвиг −1:09:32).
  • 210 WAV на карте = 105 записей × 2: DJI пишет каждый дубль дважды, _orig.wav (32 bit float с передатчика) и _edit.wav. В разбор идёт только _orig: _edit на пяти дублях короче и к картинке не подходит.

Тринадцать стадий, в порядке исполнения

📇 s0 перепись→ 🎚 s2 звук→ 📝 s3 слова→ 🗣 s4 диаризация→ 🧬 s5 голоса→ ⏱ s6 часы→ 🖼 s7 кадры→ 👁 s8 VLM→ 🎬 s1b сцены→ 🔗 s10 раскладка→ 📄 s9 страница→ 🎞 s11 прокси→ ✅ verify
СтадияЧто делаетГейт — из кода, не из прозыЖёсткость
s0_indexffprobe + Sony *M01.XML + BWF → index.jsonвидео == 172 и звук == 105 и список проблем пустHARD
s2_audioрабочий звук 16 кГц из исходниковпетличных единиц ровно 105, брака ≤ 2HARD
s3_transcribeпословная расшифровка {w,s,e}транскрипт у каждой петлички и слов ≥ 20 000HARD
s4_diarizepyannote + центроиды голосовтурнов ≥ 95 % петличекHARD
s5_voicesсквозная склейка голосов по всему днюкластеров ≥ 2, конфликтов ≤ 2 % от cannot_link (минимум 1)SOFT
s6_wordsyncграф часов по речикамер ≥ 2, стыков ≥ 3, худший дрейф ≤ 10 сSOFT
s7_framesконтактные листы 3×2листов ≥ 150SOFT
s8_vlm«что в кадре», Qwen2.5-VLописаний ≥ 140, одна фраза ≤ 20 % клиповSOFT
s1b_scenesблоки → сцены, локальной LLM из закрытого спискасцен ≥ 8 и размещено ≥ 200SOFT
s10_layout01_Source/{сцена}/{камера} симлинкамиссылок ≥ 50SOFT
s9_day_htmlстраница дня + бриф на телефон≥ 60 КБ и свежее каждого своего источникаHARD
s11_proxyпрокси-комплектготовых ≥ 170SOFT
verifyприёмка по артефактам, а не по журналамday_check.ok is trueSOFT
Номера стадий историчные — порядок исполнения задаёт список STAGES в run_night.py. Привязка к конкретному дню (пути, устройства, подписи сцен, известные стыки авто-сплита) живёт в common_day.py; про гейты это, к сожалению, неверно — см. карточку 2.
⚠️ Гейт s6 ловит развал, а не отсутствие кадра — и это осознанно. Кадровой точности на речевом шаге не бывает: речь даёт 0,6–0,9 с, поэтому порог 10 с. На этом дне все четыре стыка авто-сплита остались «не ок» — 0 из 4, максимум 3,0 с, — и это нормальный результат ночи: до кадра доводит 4.2 Audio Fine Sync (0,6–0,9 с → 1–3 мс). Требовать 0,5 с от речевого синхрона — значит заваливать гейт на исправном дне.
⚠️ HARD провалена — конвейер встаёт. SOFT провалена — веха в Telegram и идём дальше без неё. Это решение, а не недосмотр: без прокси-комплекта или без VLM-описаний день всё равно разобран, а без расшифровки или без страницы дня — нет.
python3 run_night.py            # весь конвейер, каждая стадия резюмируемая
python3 run_night.py --from s6   # с этой стадии и дальше
python3 run_night.py --only s5
python3 verify.py                # приёмка по артефактам
Управление на ходу — флаги-файлы в ~/.cache/ytai/{CODE}/: PAUSE (встать между файлами) · STOP (выйти) · ALL_DONE (ставит сам). Смежное: 3.6 Transcription (mlx-whisper и pyannote), 4.1 Multicam Word-Sync (s6 зовёт именно его), 3.4 Proxy, 0.3 Storage (метки носителей).
Итог ночи, до человека: 277 единиц переписано, 86 062 слова пословно, речь нашлась в 161 единице, 29 кластеров голосов, названо 7 сцен из 14, размещены все 172 клипа — по речи решены 40, остальные 132 доехали на уже решённой Δ своей камеры. Мёртвого звука 27 клипов, тишины 45. Итог после приёмки человеком — совсем другие числа, они в карточке 5.

🛡3.1 · 2Три слоя самовосстановления — и что такое гейт

Ночью рядом никого нет. Значит, конвейер обязан сам заметить, что стадия соврала, и сам подняться после любого падения.

слой 1 · гейты
Гейты стадий

Успех = код возврата 0 И гейт пройден. Иначе пауза 60×попытка и повтор, до трёх раз, потом стадия failed и веха в Telegram. Статус done пишется только после гейта — поэтому ему можно верить при рестарте.

слой 2 · присмотр
supervisor.sh

Тик 600 с, живёт до 144 тиков (сутки) и сам гаснет. Жив ли прогон — если нет, поднимает. Карты нет → ждёт, а не падает. На внутреннем диске меньше 8 ГБ → ставит PAUSE, снимает при 15 ГБ. Вехи в Telegram каждый третий тик.

слой 3 · живучесть
keepalive.sh под launchd

Ничего не считает: проверяет, что присмотр жив, и поднимает его. Лежит на внутреннем диске, поэтому переживает передёрг карты, смерть присмотра и перезагрузку. При STOP/PAUSE/ALL_DONE или без карты не делает ничего.

⚠️ Гейт проверяет смысл артефакта, а не факт файла. os.path.exists как гейт запрещён: файл может быть обрезком прошлой попытки — существует, весит много и показывает вчерашнюю правду. Эталон формулировки — настоящий гейт страницы дня:
страница годна, только если она СВЕЖЕЕ каждого своего источника
  размер ≥ 60 000 байт
  mtime({CODE}_day.html) > mtime(index | audio | voices | clocks |
                                scenes | sheets_meta | scene_desc .json)
⚠️ Гейты пока держат абсолюты этого дня — прямо в run_night.py. Числа 172, 105, 150, 140, 200, 170, 20000 вписаны литералами и настроены на день из 172 клипов. На следующем дне их придётся переписать или вынести в common_day.py. Это известный долг, а не переносимость: «стадия работает на любом дне» — пока неправда.
⚠️ Так это задумано. Так это в тот раз не стояло. В ночь на 20.09 третьего слоя не было: plist лежит выключенным (.ae.rya.ytevo03-supervisor.plist.disabled), а собственного plist у keepalive.sh нет вообще. Ночь держали слои 1–2 и человек: 34 падения и полтора часа холостого цикла, потому что run_stage верил статусу done раньше, чем спрашивал гейт. Это починено. Но прежде чем писать «у нас работает launchd-job», надо завести plist на keepalive.sh.
  • Логи launchd — на внутреннем диске (~/Library/Logs/ytai/). Путь на /Volumes/… убивает job с EX_CONFIG 78 ещё до старта питона: агент не дождётся монтирования тома.
  • Гейт спрашивается до запуска — готовое не переделывается, и повторный прогон стоит секунды.
  • Если ту же стадию запустили руками, оркестратор ждёт чужой процесс (опрос 30 с, максимум 4 часа), а не пишет второй раз в те же файлы.
  • Каждая стадия — отдельный процесс со своим интерпретатором: s3, s4, s5, s15 под venv с torch, s8 под venv с VLM, s1b под venv с локальной LLM, остальное — системным python3. Запуск обёрнут в caffeinate -dimsu, иначе мак уснёт на середине.

🎚3.1 · 3Сквозные голоса и реестр канала

YTs/{КАНАЛ}/{КАНАЛ}_voices.json — один человек, один ID на все проекты канала.

ГруппаКто этоПример
Aядро канала — те, кто ведёт и держит линиюYTEVO-A1 герой линии «день из жизни»
Bгости — приходят на конкретную съёмкуYTEVO-B1 священник, гость дня
Cдополнительная команда — съёмка, звук, помощьYTEVO-C1 продюсер и оператор
Номер внутри группы — порядок значимости, его ставит человек. Люди и боты продакшна как таковые — 0.5 Team & Bots.
💡 Ради чего реестр существует — voiceprints. Отпечаток = центроид голоса, снятый с подтверждённого человеком кластера. На следующей съёмке голос узнаётся сам, без вопроса «кто это». Состояние реестра YTEVO на 20.09: людей 7, с отпечатком 4, узнано 0 — первый день, узнавать ещё не с чем.
  • В реестр пишутся только подтверждённые человеком имена. Машина по своей догадке сюда не пишет никогда: ошибка здесь расходится по всем будущим проектам канала.
  • Отпечатки текущего проекта исключаются из сравнения. Иначе голос «узнаёт» собственный слепок, снятый с него же, — и уверенность оказывается нарисованной.
  • Один человек — один отпечаток на проект, снятый с самого длинного кластера.
⚠️ Полосы расстояний меряются на каждом прогоне и уезжают. Порог брать из voice_cards.json → измерено_на_этом_дне, а не из константы реестра.
ПолосаИзмерено на этом днеКонстанта реестра
«тот же человек», p950,303 — пар 8 200, медиана 0,187D_SAME = 0,326
«разные люди», p050,334 — пар 226, медиана 0,738D_MAYBE = 0,377
На пересборке того же дня «разные» уехали с 0,377 на 0,334, и зазор между полосами сжался с 0,051 до 0,031. «Разные» меряются только между дикторами, слышными на одной дорожке — то есть в одной акустике; «тот же» — между узлами внутри кластера.
⚠️ Сравнивать центроиды кластеров, а не отдельные узлы. Разброс узлов внутри заведомо правильного голоса здесь 0,393…0,406 — сам выше полосы «разные люди». Проверка по узлам кричала бы на героя дня и на гостя-священника одновременно. И два порога не путать: карточки голосов кладут в чистоту same_p95, а проверка «имя собрано из далёких частей» берёт diff_p05.
⚠️ dominant_share — это не доля чужой речи. Это доля дорожек, где голос самый громкий, и считается она только по спорным дорожкам — тем, где слышно больше одного диктора: на дорожке, где голос один, доминировать не над кем. У человека без петлички она низкая по определению. Порог отказа: спорных ≥ 4 и dominant_share < 0,5 → имя не предлагается, это похоже на чужую речь, просочившуюся в микрофоны, а не на человека.
python3 voice_registry.py --enroll            # отпечатки подтверждённых голосов
python3 voice_registry.py --enroll --only "Имя"   # только этих, флаг повторяемый
python3 voice_registry.py --enroll --hold "Имя"   # всех, кроме этих
python3 voice_registry.py --match             # примерить, ничего не пишет
python3 voice_registry.py --list
Уверенность у разных имён одного дня бывает разной — писать всех скопом нельзя, для этого и есть --only / --hold.

🙋3.1 · 4Приёмка человеком — имя голосу ставит только человек

Вторая половина стадии в run_night не входит и гоняется руками: ночь довозит кластеры, имя ставит человек. Всё ниже — правила, при которых он ставит его один раз и правильно.

📋 s12 лист решений→ 🎧 s15 карточки голосов→ 🖥 s14 страница приёмки→ 🙋 человек правит↺ ✍️ s13 применить→ 🪪 s16 паспорт→ 🎚 registry --enroll
PY=~/YTAI/environment/.venv_transcribe/bin/python
python3 s12_decisions.py            # лист решений decisions.json
$PY     s15_voice_cards.py          # отрывки, кадры, улики — ТОЛЬКО под venv
python3 s14_review_page.py          # страница приёмки {CODE}_review.html
# человек правит на странице → «Сохранить» → файл в ~/Downloads
cp ~/Downloads/{CODE}_decisions_*.json {работа}/decisions.json
python3 s13_apply_decisions.py --dry-run && python3 s13_apply_decisions.py
python3 s16_day_passport.py
python3 voice_registry.py --enroll
⚠️ s13 сам пересобирает s10 → s9 → s12 → s15 → s14, и s12 с s15 в этой цепочке обязательны: переносы дорожек рождают новые кластеры — на этом дне 16 штук, #72…#87, — и лист, собранный до них, показывает голоса, которых уже нет. s15 гонять venv-питоном. Как выглядит результат — страница приёмки дня YTEVO03, слепок v22.

Отрывок должен отвечать на вопрос «кто это»

Петличка пишет всю комнату: многодикторными оказались 111 отрывков из 135 (82 %). Выбирать кусок по длине и числу слов поэтому мало — человек слышит соседа и опознаёт не того. Отбор идёт по ступеням чистоты, и чистота стоит выше длины: rank = ступень × 10 + счёт, разрыв в 10 не перебить ни счётом, ни штрафами.

СтупеньЧто значитОтрывков
soloво всём файле слышен только он31
cleanсвоя реплика, чужой речи в окне нет вовсе97
mostlyего речи ≥ 80 % окна и начинается не с соседа7
gluedсклейка 2–3 своих реплик одной дорожки0 — не понадобилась
dirtyничего из перечисленного — честная пометка, и не первым0
Счётчики — из последней пересборки, 20.09.2026 23:53: 135 отрывков на 86 голосов. ⚠️ Они пересчитываются на каждом прогоне s15 — читать как порядок величин, а не как константу. Durable здесь — лестница и правило ранга.
  • Окно режется по соседу с зазором 0,15 с, и коридор строится вокруг СВОБОДНОГО куска реплики. Считать только по репликам, лежащим целиком вне нашей, мало: чужая речь, накрывшая реплику-кандидата, границ не двигала.
  • «Начинается с него» = в первые 0,5 с не говорит кто-то ДРУГОЙ. Требование «он уже звучит» пометило «несколько человек» девять чистых отрывков, где перед словами просто воздух: окно нарочно берёт до 0,6 с тишины.
  • Имена файлов отрывков позиционные (v03_02.m4a = «второй отрывок третьего голоса»): меняешь правила отбора — бампай PIPE_VER, иначе кэш подсунет к новому отрывку старый звук и кадр от другой минуты дня.
  • К каждой вынесенной человеком дорожке отрывок обязателен, даже если отбор её не взял: иначе правка есть в файле решений, а на странице её не видно и не отменить.
⚠️ Закрытый список — это категории, а не только имена. Кроме имён в extra_options живут «съёмочная группа», «священник в храме», «собеседник», «случайный прохожий», «радио / телевизор / фон», «несколько человек», «кто-то ещё», «не речь (пение, музыка, эхо)», «понять нельзя» — девять подписей, и реестр канала перебивает список дня целиком. Наружу едет подпись, а не id: PICK = "name:кто-то ещё" неотличим от имени. Поэтому s13 не склеивает кластеры по совпадению категории — иначе два разных «кто-то ещё» становятся одним голосом, а категория попадает в список людей дня наравне с героем. На этом дне категориями закрыты 28 кластеров из 86: «не речь» 21, «понять нельзя» 5, «кто-то ещё» 2.
⚠️ Спрашиваем один раз. Каждое новое имя рождает новые пары «часть ↔ база», и проверка находила их снова и снова — человек прошёл один и тот же круг четырежды. Пара, показанная в прошлый раз (voice_far_seen.json), при повторном появлении считается принятой: человек её видел и имя не поменял. Подтверждённые расхождения живут в voice_far_ok.json. Оба файла не удалять — это ответы человека, а не кэш.
💡 Решение принимается там, где лежит звук. Наверху страницы приёмки — блок «Надо решить: N»: в каждом пункте звук, улики и тот же список выбора, что на карточке голоса, решать прямо там и потом «Сохранить» внизу. Пункт = вопрос, что послушать и что будет, если не решать; кнопка «✓ проверил, это он» снимает сомнение машины и уходит в decisions.json как подтверждённые_расхождения. Необязательное — хвосты у людей с уже снятым отпечатком и собственные переносы дорожек — отдельно, под «Можно пропустить». Счётчик в заголовке пересчитывается на ходу; пусто — «Решать нечего — всё подтверждено». Формулировать действием, а не числом:
«Имя»: #20 (0.5 мин) — это он или другой?
   По голосу расходится с основным #1 на 0.467 — сильнее, чем обычно расходятся
   разные люди (0.334). Открой #20 ниже, послушай. Это он — жми «проверил».
   Не он — поставь на карточке #20 другое имя.
«Расстояние 0.558 при полосе 0.334» не говорит ничего. «Открой #86, послушай, если не он — поставь другое имя» говорит. Расхождение вдвое дальше порога идёт в «Надо решить» даже на коротком куске: грубая ошибка не становится мелкой оттого, что кусок короткий.
Итог приёмки 20.09: 5 людей со сквозными ID, 1 безымянный и 0 нерешённого. Безымянный — #89, 1,1 мин, отделённый split_track от голоса оператора: человек его видел и оставил номером. Это ответ, а не забывчивость, — и паспорт обязан показать его именно так.

🪪3.1 · 5Паспорт дня — итог одним файлом

Два выхода: {CODE}_passport.html человеку — один лёгкий файл, открывается с телефона — и {CODE}_day_passport.json следующему этапу. Паспорт ничего не решает и не правит: только собирает уже принятое. Не назван голос — здесь он останется «Голос N», а не получит догадку.

277 файлов172 видео105 звук14 сцен86 голосов5 людей1 без имени
YTEVO-A1
герой дня · группа A, номер 1
194,4 мин union442,8 мин по файламдублирование ×2,2818 кластеров11 приёмников6 сцен
собран из кластеров #1 #9 #20 #22 #37 … #91 · отпечаток в реестре есть · слышен на CAM-A_FX3 CAM-B_ZVE1 CAM-C_Pocket TX00…TX03
Так выглядит одна строка «кто говорит». Целиком — паспорт дня YTEVO03, рядом с ним тот же паспорт машине.
⚠️ Минуты — объединение по стенным часам, а не сумма по файлам. Одна фраза пишется двумя-четырьмя приёмниками сразу, и сумма по файлам завышает время человека вдвое. Путать шкалы нельзя: человек принимает решения по этим числам.
ЧеловекМинут (union)«По файлам»
YTEVO-A1 герой дня194,4442,8
YTEVO-B1 гость-священник74,8215,6
YTEVO-A2 ведущая56,6127,6
YTEVO-C1 продюсер и оператор55,0105,3
YTEVO-A3 продюсер канала0,30,3
  • Люди: сквозной ID канала, роль, минуты по обеим шкалам, из каких кластеров собран, на каких приёмниках записан, в каких сценах и сколько в каждой, есть ли отпечаток в реестре.
  • Сцены: время по стенным часам, состав файлов, камеры, кто говорит и сколько. У каждого блока — confidence и why: поставлено человеком или машиной. Ночь назвала 7 сцен из 14, остальные проставил человек.
  • Категории, не ставшие людьми: «не речь», «понять нельзя», «кто-то ещё» — отдельно от списка людей, чтобы не попасть в него по ошибке.
  • Что осталось решить — поле нерешённое. На этом дне оно пусто, и это проверяемое утверждение, а не бодрость.
Куда паспорт идёт дальше: 4.5 Ingest — сцены и имена говорящих в маркеры таймлайна; 3.2 Source Structure — предложенные сцены на приёмку перед тем, как файлы поедут; 3.5 Transcript Doc — расшифровка по ролям.

Рядом с паспортом: карта дня и проверка проекта

python3 daymap.py       --project "/Volumes/…/YTEVO03_Plechko_day"   # → 00_Setup/{CODE}_day_map.xmind
python3 project_check.py --project "/Volumes/…/YTEVO03_Plechko_day"   # → 00_Setup/{CODE}_project_check.html
  • daymap.py — майндкарта дня из тех же файлов, что страница дня, руками не набирается. Четыре ветки: ДЕНЬ (сцена → блоки, камеры, голоса, клипы), ЛЮДИ, ВЫПУСКИ (выпуск → главы; помечено «ЧЕРНОВИК» — замысел, положенный на фактические сцены, а не снятый с ката), ЧТО ГДЕ (проект, прокси, транскрипты, цвет, Drive). У студийного дня своя — 0121_studio_day/daymap.py --day, ветки блок → тема → урок.
  • project_check.py — самодостаточна ли папка, числами: вес по папкам и свободное место · симлинки (битые, наружу проекта; битые .LRF — не потеря, их заменяет прокси) · медиа файлами и ссылками в 01_Source · прокси-комплект (таймкод, дорожки, битность, разрешение, fps, цветовые теги) · проявка · валидатор ингеста · есть ли карта .xmind. Параметры прокси снимаются через 16_proxy/1601_build/contract.py, своей копии нет.
  • ⚠️ Это не приёмка прокси. Контракт сверяет прокси С ОРИГИНАЛОМ, а оригиналы на Drive — страница честно печатает только то, что видно по самой прокси. Полная приёмка — на пересборке, 3.4 Proxy.
⚠️ Пятый человек остался без отпечатка: речи 19,7 с при пороге 20,0. Обидно близко, но порог не снижать — слепок короче двадцати секунд шумный и потом отравит узнавание на всех следующих съёмках канала. Ждать следующей съёмки.

⚠️3.1 · 6Грабли, оплаченные этой ночью

Звук и уровни

  • Уровень петличек считать по RMS, а не по пику. DJI Mic 3 пишет 32 bit float, и пик там штатно выше нуля — здесь до +31,9 dBFS. Нормировка по пику срезала файл на 33 дБ целиком: речь уезжала на −54 dBFS, pyannote переставал слышать её вовсе (0 турнов там, где в расшифровке нормальный диалог), а whisper выдавал 186 слов вместо тысяч. Теперь усиление по RMS к −20 dBFS плюс лимитер на транзиенты и отдельный гейт «копия тише исходника». Подробнее — 2.2 Звук DJI.
  • level=disabled у alimiter обязателен. По умолчанию лимитер сам подтягивает выход в потолок — и тот запас, ради которого он ставился, исчезает.
  • -0.0 в Python ложно. (r.get('max_db') or -99) превращает честный ноль в −99 и прячет ровно те файлы, которые ищешь.
  • .LRF у Pocket в разборе не участвует. Звук там есть, но выигрыш 1,5 минуты за ночь, а дорожка на 21 мс короче оригинала: на пословных таймкодах это риск без выгоды.
  • verbose=False у mlx_whisper рисует прогресс-бар. Молчит только None — иначе лог ночи вырастает до гигабайтов.

Время, имена, кэш

  • MEDIAPRO.XML врёт про камеру. Карта ZV-E1 однажды побывала в FX3 и до сих пор объявляет ILME-FX3A. Модель брать только из посайдкарного modelName → 2.1.2 ZV-E1.
  • Длительность Sony = Duration / captureFps, не через tcFps: иначе 50p-клипы удваиваются.
  • Стыки авто-сплита сверять по именам файлов, не по creation_time: у Pocket контейнерное время отстаёт от имени на 0–4 с, и честное решение провалило бы гейт на ровном месте.
  • GROUPS — встроенный массив bash (идентификаторы групп пользователя). Присваивание молча игнорируется, цикл идёт по 250 395 398…. Имя занято, брать другое.
  • Имена файлов отрывков позиционные — меняешь правила отбора, бампай PIPE_VER, иначе кэш подсунет старый звук и кадр от другой минуты дня.
  • Цитаты голоса собирать по словам внутри его реплик. Целый сегмент whisper длиннее реплики и тащит соседа: у героя дня первой цитатой стояла фраза ведущей. s5_voices.py --samples-only пересобирает цитаты, не перекластеризовывая — полный прогон раздаёт номера заново и смывает решения человека.
  • Известный живой дефект: torchcodec в venv сломан (libavutil.56.dylib не найден). pyannote читает звук фолбэком и сыплет предупреждениями — работает, но починить стоит.
Ночь кончилась, когда страница дня свежее своих источников, все клипы размещены, а карта не тронута. Имя голосу ставит человек — и ставит один раз. Дальше → 3.2 Source Structure.