{
 "provenance": {
  "derived_by": "основная сессия (Claude Opus 5) 2026-09-10 из meta-function.json и 16 карточек сцен",
  "revised_by": "проход двух опровергателей на переобучение (goPure / бухгалтерский сервис / датчик протечки), 2026-09-10; 35 возражений перепроверены по ledger.json, кадровым полосам и коду харнесса, результат — в refutation_log",
  "NOT_done": "1) Третий опровергатель (по свидетельствам: искать сцену оригинала, где инвариант не выполняется) НЕ выполнен. 2) Ни один model-критерий (11 шт.) на выходе Omni НЕ прогонялся: `run.py validate` возвращает по ним строку-заглушку ('model_checks': 'run per criterion with run_model_check(...)'), вызывающего кода нет; они помечены implementation_status='not runnable'. 3) Требуемые изменения харнесса, названные в implementation_gap, НЕ внесены: флаг --language в run.py, теги has_product / inciting_event / unit на планах ledger, замкнутый словарь крупностей и id персонажей в прочтении стыка, учёт extra_media в кэше video_model.analyze, временное увеличение (magnified_clip) для model-проверок, привязка C-SCENE-02 к единицам, доли вместо констант в C-EDIT-02/03/05. До этих правок часть measured-критериев проверяет не то, что заявлено в pass_if. 4) Самопроверка на оригинале (self-test-on-original.json) прогоняет только measured-ветку и НЕ перепрогнана после этой ревизии: числа в ней относятся к прежним формулировкам. 5) Ни одно поле этого файла не измеряет удержание, конверсию или эффективность продукта и не может их измерить.",
  "status": "ревизия после прохода на переобучение; пригоден как feedback loop с оговорками из implementation_status каждого критерия"
 },
 "preamble": "Критерии описывают МЕХАНИЗМ, а не существительные этого фильма. Роли и предметы оригинала заменены слотами (см. `slots`): «носитель изменения», «инициатор», «измеритель», «носитель продукта», «получатель». Ни один критерий не вправе требовать болезни, семьи, ребёнка или телесного «до/после».\n\nОбратная связь: сгенерированный материал прогоняется тем же харнессом (`run.py identify → measure → windows → joins → ledger`), после чего `run.py validate --criteria .../criteria.json`. Провал критерия называет единицу для перегенерации.\n\nКЛАССЫ СВИДЕТЕЛЬСТВА (правило проекта: измеренное ≠ оценка модели ≠ интерпретация) — поле `evidence_class`:\n  measured — PTS, ASR-клок, кадры; считается автоматически по ledger.json;\n  measured-on-model-reading — считается автоматически, но по СТРОКОВЫМ полям прочтения видеомодели (who_is_framed, scale, gesture_state_at_join, continuity_check, метка говорящего). Это ОЦЕНКА. `check.method` у таких критериев оставлен 'measured' только потому, что их id зарегистрированы в atomic/validate.py; вердикт зависит от прочтения и должен читаться как оценка;\n  model — видеомодель получает сгенерированный фрагмент ВМЕСТЕ с соответствующим оригинальным и судит по механизму;\n  human — проверяет человек по названной процедуре;\n  external — проверка вне atomic/validate.py (scripts/production_policy.py, scripts/reference_generation.py).\n\nЧТО ЗЕЛЁНЫЙ ПРОГОН НЕ ЗНАЧИТ. Он не свидетельствует ни о качестве картинки и звука, ни об удержании, ни о продажах. Из 47 критериев автоматически считаются 15 measured, и это НЕ 15 различных проверок: 13 зарегистрированы в atomic/validate.py (из них 3 — псевдонимы других: C-STRUCT-05 вызывает функцию C-EDIT-07, C-SCENE-02 — C-EDIT-05, C-BOARD-02 — C-EDIT-01; 1 всегда unknown без разметки — C-SCRIPT-06), ещё 2 — внешние (C-VOICE-04, C-VIDEO-04). 12 model-критериев прогонять нечем (implementation_status='not runnable'), 20 — human. Прогон без выполненных пунктов implementation_gap НЕ является полным.",
 "criteria": [
  {
   "id": "C-SCRIPT-01",
   "phase": "script",
   "statement": "Фильм открывается инициирующим событием, а не подготовкой к нему: первое, что зритель получает, — уже содержание конфликта. Событие может быть произнесённым ИЛИ показанным.",
   "why": "Оригинал начинается прямо с оглашения; нет ни одного плана-установки до первого слова. Совпадение события с речью — свойство ЭТОГО фильма, а не правило: беззвучное открытие (капля, показание прибора, письмо на экране) выполняет тот же механизм.",
   "evidence_in_original": [
    "S01/SH001: слово «Your» в 0.00 (ASR); первый кадр — уже общий план кабинета",
    "self-test-on-original.json → C-SCRIPT-01: first_word_s 0.0, shots_before_first_word []"
   ],
   "check": {
    "method": "measured",
    "procedure": "Прогнать сгенерированный фильм через `run.py identify/measure/ledger`. Для произнесённого события — время начала первого слова и число планов до него. Для показанного события — план с тегом `inciting_event: true` в ledger (тег переносится из раскадровки).",
    "pass_if": "Инициирующее событие (произнесённое ИЛИ показанное) начинается ≤1.0 s от начала фильма, и до него не более одного плана.",
    "reference_fragment": "analysis/original-atomic/fragments/joins/J001.mp4 (0–4 s оригинала)"
   },
   "on_fail": "Перегенерировать первую сцену: убрать вступительные планы, начать с реплики-события.",
   "not_overfit_note": "Требование — «начать с события», а не «начать с медицинской цифры» и не «начать с реплики». Событием может быть счёт, письмо, отказ, показание датчика, мокрое пятно на полу.",
   "evidence_class": "measured",
   "implementation_status": "partially implemented",
   "implementation_gap": "atomic/validate.py:120-128 (opens_with_the_event) читает ТОЛЬКО слова (w['start_s']) и при отсутствии речи возвращает pass=False. Фильм, открывающийся беззвучным событием, провалит проверку дважды — по времени первого слова и по числу планов до него. Требуется: (1) тег `inciting_event` на плане в ledger сгенерированного фильма; (2) при отсутствии тега и первом слове позже 1.0 s возвращать unknown, а не fail. Поле `events` в ledger.json уже существует и может нести этот тег. check.method менять нельзя — id зарегистрирован в atomic/validate.py."
  },
  {
   "id": "C-SCRIPT-02",
   "phase": "script",
   "statement": "Каждая единица закрывает один вопрос и открывает другой; выходной вопрос отличается от входного.",
   "why": "Так собран весь оригинал: трасса «вход → событие → выход» в каждой из 16 карточек показывает смену вопроса.",
   "evidence_in_original": [
    "S01 → «что с этим делать?»",
    "S02 → «поверила ли дочь?»",
    "S05 → «что скажет наставник?»",
    "S12 → «что скажет цифра?»"
   ],
   "check": {
    "method": "human",
    "procedure": "Выписать по сценарию для каждой сцены пару (входной вопрос, выходной вопрос) и сверить, что они не совпадают и что выходной вопрос отвечает следующая сцена.",
    "pass_if": "Ни одной единицы, где выходной вопрос равен входному или где выходной вопрос не подхвачен следующей единицей.",
    "reference_fragment": "analysis/original-atomic/cards/final/*.json → поле information"
   },
   "on_fail": "Переписать единицу: добавить событие, меняющее состояние, либо удалить единицу. Сам тест удаления вынесен в отдельный критерий C-SCRIPT-14.",
   "not_overfit_note": "Вопрос может быть любым — про деньги, срок, доверие; медицинский вопрос ничем не выделен.",
   "evidence_class": "human",
   "implementation_status": "human procedure only"
  },
  {
   "id": "C-SCRIPT-03",
   "phase": "script",
   "statement": "Повторное объяснение того же предмета допускается только при смене слушателя И стандарта доказательства.",
   "why": "Оригинал объясняет продукт дважды и оба раза оправдывает это: ребёнку — метафорой, взрослому скептику — механизмом, личным числом и критерием подлинности.",
   "evidence_in_original": [
    "S06 77.3–114.2: «the little pipes that carry your blood»",
    "S09 159.7–223.7: S-allyl cysteine, «My pressure is 121 over 78», «Take it two months»"
   ],
   "check": {
    "method": "human",
    "procedure": "Для каждой пары сцен с одинаковым предметом объяснения выписать: кто слушает и какое доказательство принимает.",
    "pass_if": "Если предмет объясняется больше одного раза — у каждого повтора другой слушатель И другой тип доказательства. Ни один из типов доказательства не является утверждением о свойствах нашего продукта без собственного источника (ворота C-SCRIPT-09).",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W06-explanation.mp4 и W09-father-mentor-1.mp4"
   },
   "on_fail": "Свести повторы в один или сменить слушателя/уровень доказательства во втором.",
   "not_overfit_note": "Не про «ребёнка и отца»: слушателями могут быть партнёр и бухгалтер, жилец и мастер — важна смена бремени доказательства. ВНИМАНИЕ: шаблон оригинала «механизм + личное число + критерий подлинности» переносить как шаблон запрещено — личное число и механизм действия чужого продукта входят в do_not_transfer. Переносится смена стандарта доказательства, а не его содержание.",
   "evidence_class": "human",
   "implementation_status": "human procedure only"
  },
  {
   "id": "C-SCRIPT-04",
   "phase": "script",
   "statement": "Согласие не снимает сомнение: после решения звучит возражение, которое остаётся без ответа.",
   "why": "Оригинал даёт скепсису отдельный голос уже ПОСЛЕ согласия и не закрывает его.",
   "evidence_in_original": [
    "S10 231.4: «Okay. Thank you. I'll try it.»",
    "S11 233.26–234.70: «And what if it doesn't work?» — ответа нет, мать больше не говорит в фильме"
   ],
   "check": {
    "method": "human",
    "procedure": "Найти в сценарии реплику сомнения после решения и проверить, что на неё нет опровергающего ответа.",
    "pass_if": "Есть минимум одна такая реплика, и она не «закрыта» аргументом.",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W11-decision-doubt.mp4"
   },
   "on_fail": "Добавить сцену сомнения после решения либо убрать успокаивающий ответ.",
   "not_overfit_note": "Сомневаться может кто угодно — партнёр, супруг, коллега; сомнение не обязано быть про здоровье.",
   "evidence_class": "human",
   "implementation_status": "human procedure only"
  },
  {
   "id": "C-SCRIPT-05",
   "phase": "script",
   "statement": "Инициатор и бенефициар — разные лица, и заслуга вслух возвращается инициатору. Инициатор — человек.",
   "why": "Финал оригинала переадресует благодарность, и это единственная развязка отношений в фильме.",
   "evidence_in_original": [
    "S14 289.98–292.34: «Thank your daughter. She's the one who came knocking.»",
    "S15 294.59–299.39: «My seven-year-old snuck out in the dark to save my life»"
   ],
   "check": {
    "method": "human",
    "procedure": "Проверить по сценарию: кто запустил действие, кто получил выгоду, есть ли реплика возврата заслуги.",
    "pass_if": "Инициатор ≠ бенефициар; инициатор — человек, понёсший цену за своё действие; есть явная реплика/действие возврата заслуги ему. Продукт, прибор, уведомление или алгоритм инициатором не считаются.",
    "reference_fragment": "analysis/original-atomic/fragments/joins/J104.mp4"
   },
   "on_fail": "Добавить реплику возврата заслуги; если инициатор и бенефициар совпали — переписать завязку.",
   "not_overfit_note": "Инициатором может быть сотрудник, сосед, друг, сантехник; «ребёнок» — только один из вариантов. Ограничение «только человек» добавлено по возражению: в ролике, где будит прибор, слот инициатора норовит занять сам прибор, и развязка вырождается в «спасибо датчику» — продуктоцентричную конструкцию, которую мета-функция исключает. Прибор остаётся инструментом и может быть носителем события (C-BOARD-03).",
   "evidence_class": "human",
   "implementation_status": "human procedure only"
  },
  {
   "id": "C-SCRIPT-06",
   "phase": "script",
   "statement": "Носитель продукта входит в кадр только после того, как заданный вопрос или потребность его вызвали.",
   "why": "Предмет появляется в оригинале лишь после прямого вопроса «What is it?» и приглашения показать. Переносится ПОРЯДОК (вопрос → носитель), а не доля хронометража.",
   "evidence_in_original": [
    "Вопрос «What is it?» 110.89 → первое появление пакета 118.30 (36.3% хронометража)",
    "self-test-on-original.json → C-SCRIPT-06: status 'unknown', 'no has_product tags on shots' — проверка выключена уже на оригинале"
   ],
   "check": {
    "method": "measured",
    "procedure": "В ledger.json сгенерированного фильма найти первый план с тегом `has_product: true` (тег ставится при сборке ledger из раскадровки, где для каждого кадра назван носитель продукта) и первую реплику/действие, потребовавшие его. Для продукта без физической формы носитель называется явно (экран приложения, папка отчёта, подпись в акте); если носителя нет вовсе — критерий помечается N/A с письменной причиной.",
    "pass_if": "Первое появление носителя продукта позже вопроса/потребности, которые его вызвали. Доля хронометража (не раньше 25%) — мягкое предупреждение в отчёте, а не блокировка: у профилактического продукта носитель обязан появиться ДО события, и порядок «вопрос → носитель» остаётся единственным жёстким условием.",
    "reference_fragment": "analysis/original-atomic/fragments/events/E05-garlic-gasp-x4.mp4 (рецепт в JSON рядом)"
   },
   "on_fail": "Сдвинуть появление продукта позже и добавить вопрос, который его вызывает.",
   "not_overfit_note": "Порог 25% — не «36% как в Resilia». Для профилактического продукта (датчик, страховка, регулярная услуга) он вреден: прибор покупают и ставят ДО события, после чего ещё нужны датированный отрезок (C-STRUCT-02) и проверка (C-SCRIPT-08). Жёсткое условие — только порядок «вопрос → носитель».",
   "evidence_class": "measured",
   "implementation_status": "requires ledger tag — сейчас всегда unknown",
   "implementation_gap": "Разметки has_product не пишет ни один шаг харнесса (identify/measure/whole/windows/joins/events/ledger); ключи плана в ledger.json: duration_s, end_s, first_word_offset_s, id, join_in, join_out, model_observations, speakers, speech, start_s, words. atomic/validate.py:132-140 при отсутствии тегов возвращает {'pass': None}. Требуется: шаг тегирования (`run.py ledger --tag-product SHxxx,...` либо поле носителя в раскадровке, переносимое в ledger) и отдельный статус N/A для продуктов без носителя, чтобы «выключено» не путалось с «не проверено». Порог 25% в коде жёсткий (frac >= 0.25) и должен стать предупреждением. check.method менять нельзя — id зарегистрирован в atomic/validate.py."
  },
  {
   "id": "C-SCRIPT-07",
   "phase": "script",
   "statement": "Обещание, данное вслух, исполняется на экране.",
   "why": "Оригинал не оставляет обещаний неисполненными: сказанное ночью выполняется утром, в кадре.",
   "evidence_in_original": [
    "S07 133.11–137.67: «tomorrow morning I'll come with you and I'll explain it to your father myself» → S09 159.7: он сидит за столом семьи с пакетом"
   ],
   "check": {
    "method": "human",
    "procedure": "Выписать все обещания и проверить наличие сцены исполнения.",
    "pass_if": "Каждое произнесённое обещание имеет сцену исполнения либо явную сцену отказа от него.",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W07-garlic-reveal.mp4"
   },
   "on_fail": "Добавить сцену исполнения или убрать обещание из реплики.",
   "not_overfit_note": "Обещание может быть о звонке, визите, отчёте — не обязательно о «приходе к отцу».",
   "evidence_class": "human",
   "implementation_status": "human procedure only"
  },
  {
   "id": "C-SCRIPT-08",
   "phase": "script",
   "statement": "Критерий успеха назван персонажем ДО проверки, и проверка идёт по той же шкале и с тем же свидетелем, что зафиксировали проблему.",
   "why": "Оригинал заранее объявляет, что считается успехом, и возвращается к тому же измерителю. Переносится тождество ШКАЛЫ и свидетеля, а не наличие внешнего числового прибора.",
   "evidence_in_original": [
    "S11 235.28–239.14: «something that isn't just hiding the number» — критерий назван до проверки",
    "S13 266.57–268.93: тот же врач, тот же кабинет, «132 over 91» против «161 over 98»",
    "Тождество измерителя здесь обеспечено тем, что угроза хроническая и измеряется прибором, существующим до и после, — это свойство ЭТОГО продукта, а не механизма"
   ],
   "check": {
    "method": "human",
    "procedure": "Найти реплику, называющую критерий, и единицу проверки; сверить, что шкала и свидетель те же. Свидетель может быть субъективным (то же зеркало, тот же собеседник, тот же ежедневный обход). Отдельно проверить, что новый измеритель ради проверки не введён.",
    "pass_if": "(а) критерий успеха назван персонажем до проверки; (б) проверку выполняет тот же измеритель — тот же человек, то же место, тот же документ/прибор/счёт или тот же повторяемый ритуал (или его прямой аналог на той же шкале); (в) ради проверки не введён новый измеритель, которого не было в постановке проблемы; (г) числовой результат допускается ТОЛЬКО если у нашего продукта есть собственный письменный источник этого числа (ворота C-SCRIPT-09); квазиобъективный «замер» изобретать запрещено; (д) если успех = отсутствие события, шкала предъявляется как измеримый ноль (счёт на 0, сухой пол под прибором, акт без замечаний), а не репликой «ничего не случилось»; (е) если измеритель текстовый (строка акта, сумма счёта, показание на экране), показание читаемо в кадре ≥2 s И принято человеком в кадре (взгляд, реакция, реплика-подтверждение) — это диегетический текст, а не субтитр (C-VIDEO-02).",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W13-clinic-return.mp4"
   },
   "on_fail": "Добавить реплику критерия в единицу решения; вернуть исходную шкалу и свидетеля в единицу результата; при успехе-без-события предъявить измеримый ноль.",
   "not_overfit_note": "Измерителем может быть отчёт, счёт, показание датчика, срок, зеркало, реплика близкого — не обязательно врач и не обязательно число. Пересечения сняты ссылками: геометрия зеркальной единицы — C-STRUCT-01, геометрия пары «до/после» — C-PASS-03, здесь — только тождество измерителя и шкалы.",
   "evidence_class": "human",
   "implementation_status": "human procedure only"
  },
  {
   "id": "C-SCRIPT-09",
   "phase": "script",
   "statement": "Ворота do_not_transfer: ни одно утверждение о свойствах продукта, механизме действия, сроке результата, скидке, гарантии, дефиците, рейтинге или национальном происхождении знания не перенесено из референса; у каждого такого утверждения в сценарии есть собственный письменный источник по нашему продукту.",
   "why": "meta-function.json/do_not_transfer перечисляет девять запретов, и ни один из 39 прежних критериев их не проверял. При этом C-SCRIPT-03 и C-SCRIPT-08 своими примерами подталкивают автора к переносу шаблона «механизм + личное число + критерий подлинности» — то есть к сгенерированному заявлению об эффективности.",
   "evidence_in_original": [
    "meta-function.json/do_not_transfer: «медицинские диагнозы и утверждения о лечении»; «конкретные цифры давления как доказательство эффективности продукта»; «утверждения “очищает артерии”, “заменяет таблетки” и любые заявления о механизме действия чужого продукта»; «критика врачей и лекарств»; «чужие скидки, гарантии и заявления о дефиците (“до 70%”, “30 дней”, “партия закончится”)»; «“номер один на Amazon” и ссылки на отзывы»; «этническая или географическая “секретность” знания»; «титры-субтитры оригинала»; «исходный хронометраж 325.68 s, 16 единиц, 110 планов как норматив»",
    "Перебор criteria[].check.pass_if прежней редакции: ни одного упоминания этих запретов"
   ],
   "check": {
    "method": "human",
    "procedure": "Выписать ИЗ СЦЕНАРИЯ И ИЗ РАСКАДРОВКИ полный список оценочных и числовых утверждений (о свойстве, механизме, сроке, цене, гарантии, дефиците, рейтинге, происхождении знания), включая утверждения, сделанные КАРТИНКОЙ (телесное «до/после», визуальная демонстрация действия продукта). Для каждого указать источник по нашему продукту. Отдельно сверить список с девятью пунктами do_not_transfer.",
    "pass_if": "Ноль утверждений без письменного источника по нашему продукту И ноль совпадений с любым пунктом meta-function.json/do_not_transfer. Визуальное утверждение об эффективности (сгенерированный признак действия продукта) считается утверждением и подпадает под то же правило.",
    "reference_fragment": "analysis/original-atomic/meta-function.json → do_not_transfer"
   },
   "on_fail": "Убрать утверждение из сценария или предъявить его источник. При отсутствии источника единица переписывается, а не смягчается формулировкой.",
   "evidence_class": "human",
   "implementation_status": "human procedure only",
   "not_overfit_note": "Блокирующий критерий. Категории с регулируемыми заявлениями (уход за кожей, БАД, финансы, медицина) ломаются именно здесь: перенесённое из референса «личное число» или «механизм действия» выглядит как соблюдение формата, а является чужим заявлением об эффективности."
  },
  {
   "id": "C-SCRIPT-10",
   "phase": "script",
   "statement": "Тест слушателя: каждый, кто позже принимает решение, ранее показан слышащим или видящим основание для него.",
   "why": "Прямой пункт meta-function.json/earnedness, не покрытый ни одним прежним критерием. Самый частый дефект адаптаций: персонаж соглашается на то, о чём зритель не видел, чтобы он слышал.",
   "evidence_in_original": [
    "meta-function.json/earnedness: «Каждый, кто позже принимает решение, ранее показан слышащим основание для него (тест слушателя)»",
    "S09/карточка: отец слышит механизм 171.39–192.91, личное свидетельство 197.41–198.93 и критерий подлинности 202.49–220.89 — и только затем, в S10 231.4, говорит «Okay. Thank you. I'll try it.»"
   ],
   "check": {
    "method": "human",
    "procedure": "Выписать все решения сценария. Для каждого найти более ранний план, где решающий показан слышащим или видящим основание, и указать его номер и время.",
    "pass_if": "Ни одного решения без более раннего плана, где решающий показан принимающим основание. Исключение допускается только там, где приём основания дан не лицом, а скоростью ответа (S09: наставник, паузы 0.28 / 0.32 / 0.18 s), и это записано явно.",
    "reference_fragment": "analysis/original-atomic/cards/drafts/S09.json → listening"
   },
   "on_fail": "Добавить план, где решающий показан принимающим основание, либо перенести решение позже.",
   "evidence_class": "human",
   "implementation_status": "human procedure only",
   "not_overfit_note": "Основание может быть услышано, прочитано или увидено; «слушатель» — роль, а не человек у стола."
  },
  {
   "id": "C-SCRIPT-11",
   "phase": "script",
   "statement": "Последствие события удержано: в единице, где звучит проблема, не звучит её решение.",
   "why": "Шаг 2 псевдокода meta-function: `withhold(event.consequence)` — «managing it» без плана лечения. Именно удержание последствия держит вопрос открытым; ни один прежний критерий не запрещал выдать решение вместе с проблемой.",
   "evidence_in_original": [
    "meta-function.json/pseudocode: `if event.is_information: say_it_whole(on=wide_or_authority_shot); withhold(event.consequence)  # «managing it» без плана лечения (S01)`",
    "S01: факт назван целиком, план действий не назван — выходной вопрос «что с этим делать?»"
   ],
   "check": {
    "method": "human",
    "procedure": "Для единицы, где событие оглашается, выписать: что названо и что удержано. Сверить, что удержанное не названо в той же единице ни репликой, ни картинкой.",
    "pass_if": "В единице оглашения проблемы факт звучит целиком, а его последствие или способ решения не назван — ни репликой, ни носителем продукта в кадре.",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W01-clinic.mp4"
   },
   "on_fail": "Убрать решение из единицы оглашения и перенести его в следующую единицу.",
   "evidence_class": "human",
   "implementation_status": "human procedure only",
   "not_overfit_note": "Сопряжено с C-SCRIPT-06 (носитель продукта входит после вопроса) и C-SCRIPT-02 (выходной вопрос отличается от входного), но проверяет другое: не порядок появления продукта, а то, что решение НЕ выдано вместе с проблемой."
  },
  {
   "id": "C-SCRIPT-12",
   "phase": "script",
   "statement": "Заданный вопрос закрывается наблюдаемым действием с носителем, а не следующей репликой.",
   "why": "Инвариант meta-function, не покрытый прежним набором: C-SCRIPT-06 сторожил только ВРЕМЯ появления продукта, но не то, что ответом служит действие.",
   "evidence_in_original": [
    "meta-function.json/invariants: «Вопрос закрывается действием с предметом, а не ещё одной репликой»",
    "S06: «What is it?» 110.89 → «Come, let me show you» 111.91 → S07: шкаф 115.7 → пакет на столе 118.30 → имя «Aged garlic» 119.79"
   ],
   "check": {
    "method": "human",
    "procedure": "Для каждого прямого вопроса о продукте или о выходе из положения найти первый план ДЕЙСТВИЯ с носителем и посчитать по сценарию число реплик между вопросом и этим планом.",
    "pass_if": "Между вопросом и первым планом действия с носителем не более двух реплик, и ответом служит действие, а не объяснение.",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W07-garlic-reveal.mp4"
   },
   "on_fail": "Заменить объясняющие реплики планом действия с носителем.",
   "evidence_class": "human",
   "implementation_status": "human procedure only",
   "not_overfit_note": "Носителем действия может быть предмет, экран, документ или подпись; «пойти и показать» — механизм, а не мизансцена кухни."
  },
  {
   "id": "C-SCRIPT-13",
   "phase": "script",
   "statement": "Скептик получает признак, который может проверить сам, и названный срок проверки.",
   "why": "Переносимая часть трёхступенчатой проверки в S09: скептику дают не только объяснение, но и самопроверяемый критерий подлинности и условие срока. Механизм в meta-function описан, обратной связи под него не было.",
   "evidence_in_original": [
    "S09/карточка: «What's the difference?» 167.93 → механизм 171.39–192.91; «And you take this yourself?» 193.19 → личное свидетельство 197.41–198.93; «How do I know it's the real thing?» 199.15 → критерий подлинности 202.49–220.89 и условие срока 221.x"
   ],
   "check": {
    "method": "human",
    "procedure": "Найти реплику скептика и ответ на неё. Проверить, что ответ содержит признак, проверяемый самим скептиком без нашего участия, и названный срок проверки. Сверить оба с воротами C-SCRIPT-09.",
    "pass_if": "Ответ скептику содержит (а) признак, который скептик может проверить сам, и (б) названный срок проверки; ни (а), ни (б) не перенесены из референса и не являются заявлением о свойствах продукта без собственного источника.",
    "reference_fragment": "analysis/original-atomic/cards/drafts/S09.json → information"
   },
   "on_fail": "Добавить самопроверяемый признак и срок либо убрать сцену скептика — иначе скепсис закрывается авторитетом, а не проверкой.",
   "evidence_class": "human",
   "implementation_status": "human procedure only",
   "not_overfit_note": "Переносится СТРУКТУРА ответа (самопроверяемый признак + срок), а не его содержание. Конкретные признаки оригинала («тёмно-янтарные», «20 месяцев») и его число «121 over 78» переносить запрещено (C-SCRIPT-09)."
  },
  {
   "id": "C-SCRIPT-14",
   "phase": "script",
   "statement": "Тест удаления: для каждой единицы указано, какая следующая единица становится немотивированной при её удалении.",
   "why": "Прямой пункт meta-function.json/earnedness, упоминавшийся прежде только в on_fail C-SCRIPT-02 и не бывший проверкой.",
   "evidence_in_original": [
    "meta-function.json/earnedness: «Единица заслужила место, если её удаление делает следующую единицу немотивированной (тест удаления)»"
   ],
   "check": {
    "method": "human",
    "procedure": "Составить таблицу «единица → что становится немотивированным при её удалении». Пустая клетка = единица не заслужила места.",
    "pass_if": "У каждой единицы названа конкретная следующая единица, теряющая мотивировку при её удалении. Ноль пустых клеток.",
    "reference_fragment": "analysis/original-atomic/cards/final/*.json → information"
   },
   "on_fail": "Удалить единицу либо дать ей событие, от которого зависит следующая.",
   "evidence_class": "human",
   "implementation_status": "human procedure only",
   "not_overfit_note": "Тест применим к любому числу единиц и к любой длине фильма; он же — главный инструмент сокращения хронометража без потери механизма."
  },
  {
   "id": "C-STRUCT-01",
   "phase": "structure",
   "statement": "Открывающая единица возвращается зеркально: тот же носитель свидетельства (человек, место, прибор или документ), та же геометрия кадра, обратный знак.",
   "why": "Зеркало — главный структурный замок оригинала. Переносится совпадение геометрии и носителя свидетельства, а не присутствие человека-свидетеля.",
   "evidence_in_original": [
    "S01/SH001 ↔ S13/SH096 (общий план кабинета)",
    "S01/SH006 ↔ S13/SH102 (вставка рук)",
    "S01/SH007 ↔ S13/SH103 (безмолвный двухплан)"
   ],
   "check": {
    "method": "model",
    "procedure": "Дать видеомодели два фрагмента — открывающую и результирующую единицы сгенерированного фильма — и соответствующие фрагменты оригинала; спросить, повторяются ли место, носитель свидетельства и типы планов при обратном знаке события. Оба фрагмента подавать через magnified_clip(factor=2..4).",
    "pass_if": "Модель находит совпадение места и минимум двух типов планов (общий + реакция/вставка) при противоположном знаке события. Совпадение носителя свидетельства обязательно; если носитель — не человек (ночной коридор, место под мойкой, тот же документ), совпадения по месту и типам планов достаточно, и человек-свидетель не требуется.",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W01-clinic.mp4 + W13-clinic-return.mp4"
   },
   "on_fail": "Переснять сцену результата в геометрии открывающей сцены (то же место, тот же свидетель, те же крупности).",
   "not_overfit_note": "Зеркалить можно любую исходную ситуацию: тот же кабинет, тот же стол переговоров, тот же ночной коридор, тот же пол под мойкой. Требовать «того же свидетеля» как человека запрещено — в зеркальной единице людей может не быть вовсе (все спят), и выдумывать персонажа ради формального совпадения нельзя.",
   "evidence_class": "model",
   "implementation_status": "not runnable",
   "implementation_gap": "model-проверки не имеют вызывающего кода: validate() возвращает строку-заглушку вместо результатов; magnified_clip в run_model_check не применяется; кэш analyze() не учитывает extra_media (сгенерированный клип передаётся именно как extra_media), поэтому после перегенерации дубля повторный прогон под тем же именем вернёт СТАРЫЙ вердикт."
  },
  {
   "id": "C-STRUCT-02",
   "phase": "structure",
   "statement": "Между решением и результатом лежит датированный отрезок обычной жизни без доказательств.",
   "why": "Оригинал показывает восемь недель бытом, ни разу не давая измерения — именно это удерживает вопрос открытым. Датировка титром — свойство источника, а не механизма.",
   "evidence_in_original": [
    "S12 245.1–265.8: ни цифры, ни врача",
    "fragments/strips/SH088.jpg: на кадрах 245.1–247.4 s вжжённый белый титр «WEEK 2» — единственный показанный в оригинале способ датировки",
    "meta-function.json/do_not_transfer: «титры-субтитры оригинала (наблюдение источника не разрешает генерировать субтитры)»",
    "в каждом отрезке — одно завершённое бытовое действие с инициатором"
   ],
   "check": {
    "method": "human",
    "procedure": "Проверить наличие единицы-периода, способ её датировки и отсутствие в ней измеримого доказательства. Отсутствие измерения проверяется по пословному ASR-клоку отрезка: в нём не должно быть числа-результата или реплики о результате.",
    "pass_if": "Есть минимум один датированный отрезок между решением и проверкой; датировка несётся ОДНИМ ИЗ разрешённых носителей: произнесённая реплика с датой, предметный маркер (календарь, счёт, чек, смена сезона или одежды, отметка в документе) или композитная карточка, собранная в МОНТАЖЕ. Генерировать титр внутри дубля запрещено (C-VIDEO-02). В датированном отрезке не звучит измерение результата (проверяется по ASR-клоку отрезка).",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W12-montage.mp4"
   },
   "on_fail": "Добавить датированный бытовой отрезок с разрешённым носителем датировки; убрать преждевременное доказательство; заменить сгенерированный титр монтажной карточкой или предметным маркером.",
   "not_overfit_note": "Датировка — любая («день 3», «через месяц», «после второго счёта»); четыре или восемь недель ничем не выделены. Для неанглийской локализации это ещё и техническое ограничение: Omni Flash 360p не отрисует кириллический титр читаемо, и любой сгенерированный титр проваливает C-VIDEO-02 даже при верном написании.",
   "evidence_class": "human",
   "implementation_status": "human procedure only"
  },
  {
   "id": "C-STRUCT-03",
   "phase": "structure",
   "statement": "Коммерческая часть продолжает показанное будущее, а не прерывает его.",
   "why": "В оригинале продающий текст идёт закадрово поверх бытовых планов, без единого плана говорящего и без отдельной товарной вставки.",
   "evidence_in_original": [
    "S15 295.3–322.0: пять статичных планов (крыльцо, кухня, сад, парк, стол), продукт только в руках дочери 300.3–305.6"
   ],
   "check": {
    "method": "model",
    "procedure": "Дать видеомодели финальный блок сгенерированного фильма и S15 оригинала; спросить, показаны ли в продающей части те же люди в обычной жизни и есть ли отдельные товарные вставки/планы говорящего.",
    "pass_if": "В продающей части присутствуют носители изменения истории в их изменившейся обычной жизни, и предложение не открывает новую тему.",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W15-close-offer.mp4"
   },
   "on_fail": "Перегенерировать финальный блок: заменить товарные вставки планами жизни персонажей с продуктом в руках.",
   "not_overfit_note": "Не про сад и собаку: важно, что предложение идёт поверх того будущего, ради которого велась история. Запреты «говорящая голова» и «товарная вставка» вынесены из pass_if в style_observations по возражению: для услуги без предмета второй запрет пуст, и критерий вырождался в домашнее правило.",
   "style_observations": [
    "НАБЛЮДЕНИЕ ИСТОЧНИКА, не условие приёмки: в S15 нет ни одного плана «говорящая голова» и нет продукта отдельно от человека (кроме финальной карточки). Записано как проектное правило рядом с C-VIDEO-02/C-VIDEO-04, а не как вывод о механизме: финал с одним планом говорящего владельца может соблюдать механизм полностью."
   ],
   "evidence_class": "model",
   "implementation_status": "not runnable",
   "implementation_gap": "см. C-STRUCT-01: вызывающего кода для model-проверок нет; magnified_clip не применяется; кэш не учитывает extra_media."
  },
  {
   "id": "C-STRUCT-04",
   "phase": "structure",
   "statement": "Карточка предложения — немая, один план, после последнего произнесённого слова.",
   "why": "Оригинал отделяет графику от истории вспышкой и оставляет её без звука на время чтения.",
   "evidence_in_original": [
    "S16: последнее слово «here.» 321.59 → вспышка 321.7–322.0 → карточка 322.033–325.682, 3.9 s тишины, 0 людей"
   ],
   "check": {
    "method": "measured",
    "procedure": "В ledger.json сгенерированного фильма: время последнего слова, время начала последнего плана, число планов после него.",
    "pass_if": "Последний план начинается после конца последнего слова, длится ≥2.5 s и является единственным планом до конца файла.",
    "reference_fragment": "analysis/original-atomic/fragments/strips/SH110.jpg"
   },
   "on_fail": "Пересобрать финал: перенести карточку за последнее слово и дать ей один непрерывный план.",
   "not_overfit_note": "Содержание карточки (скидка, гарантия, номер) — слот, и его перенос из референса запрещён воротами C-SCRIPT-09. Переносится только позиция карточки, её немота и одноплановость. Карточка собирается в МОНТАЖЕ, а не генерируется видеомоделью — это именованное исключение из C-VIDEO-02, чтобы два критерия не противоречили друг другу.",
   "evidence_class": "measured",
   "implementation_status": "implemented",
   "implementation_gap": "Зависит от языка ASR-прогона (см. slots.применимость.язык): на неанглийской дорожке время последнего слова недостоверно, и критерий обязан быть unknown, а не pass."
  },
  {
   "id": "C-STRUCT-05",
   "phase": "structure",
   "statement": "Длительность плана в монтаже задаёт завершение действия, а не норматив.",
   "why": "Измеренный разброс длин планов в оригинале — от 1.00 s до 8.20 s при медиане 2.3 s.",
   "evidence_in_original": [
    "ledger.json: min 1.00 s (SH049 123.133–124.133, SH066), max 8.20 s (SH104 286.2–294.4), медиана 2.3 s",
    "self-test-on-original.json → C-STRUCT-05: {min: 1.0, max: 8.2, median: 2.333}",
    "S09/SH067 (177.233–184.767, 7.534 s) не разрезан, потому что жест внутри фразы не завершён",
    "S14/SH104 8.2 s — вся единица одним планом без единой склейки"
   ],
   "check": {
    "method": "measured",
    "procedure": "Посчитать по ledger.json сгенерированного фильма распределение длин ПЛАНОВ В МОНТАЖЕ и отдельно — длин ДУБЛЕЙ по журналу генерации.",
    "pass_if": "(а) длины планов в монтаже разнообразны: есть план ≥4 s и план ≤1.5 s; (б) у каждого плана в раскадровке записано, каким завершением действия задана его длина; (в) длина ДУБЛЯ выбирается из 4/6/8/10 s и укладывается в ±25% к длине плана в монтаже, а короткий план получается подрезкой хвоста дубля (C-VOICE-04); (г) ни один план не обрывает незавершённое действие носителя (проверяется C-SCENE-01).",
    "reference_fragment": "analysis/original-atomic/ledger-shots.md"
   },
   "on_fail": "Перегенерировать/перемонтировать единицы с однородными длинами: удлинить планы с незавершённым действием, подрезать хвосты дублей под короткие вставки.",
   "not_overfit_note": "Числа 1.0/8.2 s — не норматив, а доказательство того, что норматива нет. Прежняя редакция называла min 0.20 s (SH093) и max 7.53 s (SH067) — это опровергнуто собственным ledger.json (SH093 = 1.70 s, 258.0–259.7; максимум — SH104 8.20 s). Занижённый минимум приглашал нарезать вставки в 5 кадров, которых в оригинале нет и которых Omni Flash не выдаст.",
   "evidence_class": "measured",
   "implementation_status": "partially implemented (alias of C-EDIT-07)",
   "implementation_gap": "atomic/validate.py: `@measured('C-STRUCT-05') def duration_follows_action(...): return shot_length_variety(ledger, crit)` — это ТОТ ЖЕ результат, что у C-EDIT-07, посчитанный дважды. Различающие условия (б) и (в) не реализованы: они требуют раскадровки с полем «чем задана длина» и журнала генерации с длиной дубля. Пункт (а) остаётся общим с C-EDIT-07 и не должен засчитываться как вторая независимая проверка. check.method менять нельзя — id зарегистрирован в atomic/validate.py."
  },
  {
   "id": "C-PASS-01",
   "phase": "passport",
   "statement": "У каждого носителя изменения постоянная идентичность и отдельно описанное изменяемое состояние; изменение подтверждается кадром, а не титром.",
   "why": "В оригинале лицо и одежда персонажа опознаваемы во всех единицах. Носитель изменения — слот: им может быть человек, место, предмет, прибор или документ.",
   "evidence_in_original": [
    "Отец: S01 (сидит, опущенная голова) → S12 (бег во дворе) → S13 (поднятая ладонь, улыбка) — носитель-человек, и меняется ПОВЕДЕНИЕ, а не телесный признак",
    "Титры недель не заменяют показанного действия",
    "strips SH001.jpg + SH091.jpg"
   ],
   "check": {
    "method": "model",
    "procedure": "Дать видеомодели по одному фрагменту с носителем из начала и из конца сгенерированного фильма; спросить: тот же ли это носитель (человек | место | предмет | прибор | документ, названный в паспорте единицы) и что именно изменилось видимо. Оба фрагмента подавать через magnified_clip(factor=2..4). Идентичность человека дополнительно сверяется с утверждённым паспортом персонажа по кадровым полосам (frame_strip по каждому дублю).",
    "pass_if": "Модель опознаёт того же носителя во всех его появлениях; ноль дублей с несовпадением лица, одежды или тождества предмета относительно паспорта.",
    "reference_fragment": "analysis/original-atomic/fragments/strips/SH001.jpg + SH091.jpg"
   },
   "on_fail": "Перегенерировать паспорт носителя и пересобрать единицы с расхождением идентичности.",
   "not_overfit_note": "Критерий разделён по возражению: здесь — ТОЛЬКО идентичность носителя. Требование наблюдаемого изменения вынесено в C-PASS-04. Носителем изменения может быть квартира (пятно на потолке → свежая краска), пол под мойкой (мокрый → сухой), акт проверки (с замечаниями → без), распорядок владельца. Требовать, чтобы изменение читалось на теле человека, запрещено: в ролике про датчик за интервал истории ни один человек не меняется наблюдаемо, и телесное «до/после» в косметике — это заявление об эффективности (C-SCRIPT-09).",
   "evidence_class": "model",
   "implementation_status": "not runnable",
   "implementation_gap": "см. C-STRUCT-01. Дополнительно: идентичность при подубльной генерации Omni дрейфует (класс дефекта «чужой свитер», зафиксирован в C-PASS-02), а 360p и ~1 кадр/с эндпоинта (memory/kie-gemini-video-endpoint-limits.md) не разрешают мелкие признаки — поэтому опорой служит паспорт и кадровые полосы, а прочтение модели — второй голос."
  },
  {
   "id": "C-PASS-02",
   "phase": "passport",
   "statement": "Владение действием, доступом и предметом закреплено: кто держит носитель, кто его передаёт, кто им распоряжается.",
   "why": "Оригинал явно проводит предмет по рукам: шкаф → стол → руки дочери → руки отца → ладонь с капсулами. Механизм — цепочка передачи, а не физичность предмета.",
   "evidence_in_original": [
    "S07/SH052 130.6 передача дочери",
    "S09/SH062 159.74 передача отцу",
    "S11/SH082 231.8 капсулы на ладони отца"
   ],
   "check": {
    "method": "human",
    "procedure": "Составить таблицу «носитель → кто держит/распоряжается → в какой единице получил» по сценарию и сверить с раскадровкой. Носителем может быть и нематериальное: доступ к учётной системе, логин, ключ, папка первички, право подписи, доверенность, право говорить от лица компании.",
    "pass_if": "Нет единицы, где персонаж распоряжается предметом ИЛИ доступом, который он не получил в кадре.",
    "reference_fragment": "analysis/original-atomic/fragments/events/E06-pouch-handover-x4.mp4"
   },
   "on_fail": "Добавить сцену передачи или исправить владельца в раскадровке.",
   "not_overfit_note": "Ошибка «чужой свитер/чужая проблема» из прошлой продакшн-сессии — тот же класс дефекта. Расширение на нематериальные носители добавлено по возражению: у услуги предмета нет, таблица оказывалась пустой, и критерий проходил вакуумно — при том что тот же дефект возвращался как сцена, где исполнитель распоряжается документами, доступ к которым ему в кадре никто не давал.",
   "evidence_class": "human",
   "implementation_status": "human procedure only"
  },
  {
   "id": "C-PASS-03",
   "phase": "passport",
   "statement": "Состояния «до» и «после» носителя изменения снимаются в одной геометрии.",
   "why": "Только одинаковая расстановка делает изменение читаемым, а не заявленным.",
   "evidence_in_original": [
    "S01/SH001 и S13/SH096 — тот же кабинет, та же посадка семьи, та же позиция врача",
    "strips SH001.jpg + SH096.jpg"
   ],
   "check": {
    "method": "model",
    "procedure": "Дать видеомодели кадры «до» и «после» из сгенерированного фильма и спросить, совпадают ли место, ракурс и расстановка и что именно различается. В вопросе называть НОСИТЕЛЯ из паспорта единицы, а не «персонажей». Оба фрагмента подавать через magnified_clip(factor=2..4).",
    "pass_if": "Модель подтверждает совпадение места, ракурса и расстановки; различие — только в состоянии носителя (человека, места, предмета, прибора или документа).",
    "reference_fragment": "analysis/original-atomic/fragments/strips/SH001.jpg + SH096.jpg"
   },
   "on_fail": "Пересобрать сцену «после» в геометрии сцены «до».",
   "not_overfit_note": "Геометрия любая — важно её совпадение, а не конкретный кабинет. Пара «до/после» может вообще не содержать людей: потолок соседа с пятном ↔ тот же потолок после ремонта; пол под мойкой мокрый ↔ сухой; тот же стол с коробкой первички ↔ тот же стол с подписанным актом. Требовать «различие только в состоянии персонажей» запрещено — на паре без персонажей модель вернёт fail или мусор.",
   "evidence_class": "model",
   "implementation_status": "not runnable",
   "implementation_gap": "см. C-STRUCT-01."
  },
  {
   "id": "C-PASS-04",
   "phase": "passport",
   "statement": "Изменение носителя наблюдаемо: в фильме есть минимум один носитель-человек, чьё ПОВЕДЕНИЕ (осанка, темп, готовность отвечать, инициатива) меняется видимо. Меняться его тело не требуется.",
   "why": "Вторая половина прежнего C-PASS-01, выделенная в отдельный критерий: идентичность и наблюдаемое изменение — разные требования с разными способами проверки.",
   "evidence_in_original": [
    "Отец: S01 (сидит, опущенная голова) → S12 (бег во дворе) → S13 (поднятая ладонь, улыбка) — меняется поведение",
    "Титры недель не заменяют показанного действия",
    "strips SH001.jpg + SH091.jpg"
   ],
   "check": {
    "method": "model",
    "procedure": "Дать видеомодели фрагмент с носителем-человеком из начала и из конца сгенерированного фильма, ОБА через magnified_clip(factor=2..4); спросить, что именно изменилось видимо в его поведении. Прочтение модели принимается только как второй голос к письменному описанию изменения в паспорте.",
    "pass_if": "Названо минимум одно наблюдаемое изменение ПОВЕДЕНИЯ носителя-человека, не связанное с титром. Признак, который продаёт продукт (состояние кожи, вес, показатель организма), засчитывать в качестве наблюдаемого изменения ЗАПРЕЩЕНО: сгенерированный признак действия продукта — визуальное заявление об эффективности (C-SCRIPT-09).",
    "reference_fragment": "analysis/original-atomic/fragments/strips/SH001.jpg + SH091.jpg"
   },
   "on_fail": "Добавить единицу, где поведение носителя меняется наблюдаемо; убрать сгенерированный телесный признак, если он подменял изменение.",
   "evidence_class": "model",
   "implementation_status": "not runnable",
   "implementation_gap": "model-проверки не имеют вызывающего кода: atomic/validate.py:236 возвращает 'model_checks': 'run per criterion with run_model_check(...)' — строку вместо результатов. Кроме того: (1) run_model_check передаёт оба клипа БЕЗ временного увеличения, хотя magnified_clip (setpts 2–4×, fragments.py:32) применялся при чтении стыков и событий оригинала (passes.py:92,104), а эффективная частота дискретизации эндпоинта ~1 кадр/с (memory/kie-gemini-video-endpoint-limits.md) — паузы 0.62 s, фазы жеста и опережение 0.15–0.40 s судье физически не видны; (2) кэш analyze() сравнивает только ('prompt_sha256','media','generation_config','model') и НЕ учитывает extra_media (video_model.py:75-80), а сгенерированный клип передаётся именно как extra_media — после перегенерации дубля повторный прогон под тем же именем вернёт СТАРЫЙ вердикт. Требуется: шаг `run.py validate --model-checks`, обязательное magnified_clip(factor=2..4) для обоих клипов и sha256 сгенерированного клипа в имени записи доказательства; extra_media — в набор полей сравнения кэша.",
   "not_overfit_note": "Носители изменения в целом могут быть нечеловеческими (квартира, документ, счёт) — это C-PASS-01. Здесь требуется ровно один человек с наблюдаемой сменой поведения, чтобы фильм не выродился в демонстрацию продукта. Разрешение 360p и ~1 кадр/с эндпоинта не позволяют судить о мелких телесных признаках, поэтому опорой служит поведение."
  },
  {
   "id": "C-BOARD-01",
   "phase": "storyboard",
   "statement": "У каждого кадра есть входной стимул, наблюдаемое изменение и причина следующего кадра.",
   "why": "В оригинале каждый план отвечает на текущий вопрос и уступает место тому, чего сам показать не может.",
   "evidence_in_original": [
    "S01: «общий не может показать удар по отцу; лицо отца не может показать снимок; врач не может показать руки; руки не могут показать ребёнка»"
   ],
   "check": {
    "method": "human",
    "procedure": "Для каждого кадра раскадровки выписать стимул, изменение и причину перехода.",
    "pass_if": "Ни одного кадра без всех трёх полей.",
    "reference_fragment": "analysis/original-atomic/cards/final/S01.json → editing.why_cut"
   },
   "on_fail": "Дописать причину или удалить кадр.",
   "not_overfit_note": "Правило про причину кадра, а не про клинику.",
   "evidence_class": "human",
   "implementation_status": "human procedure only"
  },
  {
   "id": "C-BOARD-02",
   "phase": "storyboard",
   "statement": "Соседние кадры с одним и тем же носителем в кадре различаются крупностью, осью или составом кадра. Проверяется ПО РАСКАДРОВКЕ, до генерации.",
   "why": "Во всех 109 измеренных стыках оригинала соседние планы различаются; двух похожих поз подряд нет ни разу. Дефект дешевле поймать в раскадровке, чем в готовом монтаже.",
   "evidence_in_original": [
    "Адьюдикация: кандидаты стыка 61.9 и 63.8 в S05 отклонены — вместо склейки план держат 3.67 s",
    "Исключение, найденное самопроверкой: J106 (300.1 s) соединяет два плана «мужчина и девочка, средний» — но это РАСТВОРЕНИЕ между разными местами внутри финального монтажа, то есть сжатие времени, а не рваная склейка."
   ],
   "check": {
    "method": "measured",
    "procedure": "До генерации: для каждой пары соседних кадров раскадровки сверить ЗАЯВЛЕННЫЕ крупность (замкнутый словарь ECU/CU/MCU/MS/MW/WS/EWS), ось и состав кадра, а носителя называть идентификатором паспорта (P1/P2/…), а не описанием внешности. Прочтение видеомодели (C-EDIT-01) используется как второй голос при расхождении.",
    "pass_if": "Ноль пар соседних кадров раскадровки, соединяемых ЖЁСТКОЙ склейкой, у которых совпадают и носитель, и крупность, и ось (растворения между разными местами не считаются). При отсутствии заявленных полей — unknown, а не pass.",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W05-threshold-kitchen.mp4"
   },
   "on_fail": "Заменить один из планов другой крупностью/осью или объединить их в один удержанный план.",
   "not_overfit_note": "Прямой ответ на отклонённый владельцем шестисекундный монтаж из двух похожих поз. Формулировка «носитель в кадре» вместо «говорящий» добавлена по возражению: правило должно корректно применяться и к бессловесным предметным планам (капля → лужа), и к однородному касту, где модель назовёт обоих собеседников «man» и завалит здоровый восьмёрочный монтаж.",
   "evidence_class": "measured-on-model-reading (пока реализация — псевдоним C-EDIT-01)",
   "implementation_status": "partially implemented (alias of C-EDIT-01)",
   "implementation_gap": "atomic/validate.py: `@measured('C-BOARD-02') def adjacent_shots_differ(...): return no_similar_pose_join(ledger, crit)` — это тот же результат, что у C-EDIT-01, посчитанный дважды, и он ПОСТФАКТУМ по стыкам, а не по раскадровке. Требуется отдельная реализация по board.json (крупность/ось/носитель на кадр). Кроме того, унаследованные от C-EDIT-01 дефекты: сравниваются свободные строки прочтения модели (в оригинале 24 написания крупности на ~6 значений — «medium shot» ×45 / «medium» ×36 / «ms» ×4; «medium close-up» ×38 / «mcu» ×18; и 102 варианта who_is_framed), поэтому реальная склейка двух одинаковых поз, описанная как «MCU» и «medium close-up», не будет поймана; при joins_checked == 0 или при отсутствии полей проверка возвращает pass (validate.py:62,67), а обязана возвращать unknown. check.method менять нельзя — id зарегистрирован в atomic/validate.py."
  },
  {
   "id": "C-BOARD-03",
   "phase": "storyboard",
   "statement": "Носитель продукта в кадре что-то делает или что-то принимает; пэкшота — упаковки или логотипа без события — внутри истории нет.",
   "why": "В оригинале продукт ни разу не снят как товар отдельно от персонажа — до финальной карточки. Переносимое здесь — запрет на предмет, который ничего не делает, а не требование человека в кадре.",
   "evidence_in_original": [
    "S07/SH052, S09/SH062, S11/SH082, S15 300.3–305.6 — везде руки в кадре",
    "Контрпример из meta-function.json/counterexamples (S04): «10.6 s, ноль слов, ноль получателей… Реакция вынесена за границу единицы» — оригинал сам допускает единицу без получателя внутри неё"
   ],
   "check": {
    "method": "model",
    "procedure": "Дать видеомодели все планы сгенерированного фильма с носителем продукта; спросить, происходит ли в каждом из них наблюдаемое событие или приём события. Оба фрагмента подавать через magnified_clip(factor=2..4).",
    "pass_if": "Ноль планов, где носитель продукта показан без события и без изменения (упаковка, логотип, пэкшот). План, где продукт САМ является носителем события (прибор мигает и пищит, приложение выводит уведомление, из принтера выходит акт), разрешён при условии, что приём события человеком показан в этой или в следующей единице (C-SCENE-04). Для продукта без физической формы носитель называется явно (экран приложения, папка отчёта, подпись в акте) и правило применяется к нему; если носителя нет вовсе — критерий помечается N/A с письменной причиной, а не pass.",
    "reference_fragment": "analysis/original-atomic/fragments/strips/SH052.jpg"
   },
   "on_fail": "Перегенерировать пэкшоты как планы с событием или с рукой/персонажем; для продукта-носителя события добавить единицу приёма.",
   "not_overfit_note": "Правило про событие, а не про пакет чеснока и не про присутствие человека. Прежняя редакция («планов с продуктом без человека нет») запрещала центральный план ролика о датчике — 03:12, все спят, прибор мигает под мойкой — то есть саму единицу засвидетельствованного изменения; и одновременно была пуста для услуги без предмета.",
   "evidence_class": "model",
   "implementation_status": "not runnable",
   "implementation_gap": "см. C-STRUCT-01."
  },
  {
   "id": "C-BOARD-04",
   "phase": "storyboard",
   "statement": "Слушатель имеет собственный кадр в каждой сцене, где событие чего-то ему стоит.",
   "why": "Оригинал показывает получателя отдельно ровно тогда, когда цена события для него высока.",
   "evidence_in_original": [
    "S01: отдельные планы отца, рук матери и дочери",
    "S09: слушатель показан 8 раз за сцену"
   ],
   "check": {
    "method": "human",
    "procedure": "По раскадровке проверить: для каждого персонажа, чью жизнь меняет событие сцены, есть отдельный кадр.",
    "pass_if": "Нет персонажа, который платит цену события и ни разу не показан отдельно в этой сцене.",
    "reference_fragment": "analysis/original-atomic/fragments/joins/J005.mp4"
   },
   "on_fail": "Добавить кадр реакции этого персонажа.",
   "not_overfit_note": "Исключение зафиксировано в оригинале (S09: наставник не показан слушающим) — правило применяется к тем, кому событие дорого. Порядок получателей и тест слушателя вынесены в отдельные критерии C-BOARD-05 и C-SCRIPT-10: здесь проверяется только НАЛИЧИЕ собственного кадра.",
   "evidence_class": "human",
   "implementation_status": "human procedure only"
  },
  {
   "id": "C-BOARD-05",
   "phase": "storyboard",
   "statement": "Ключевое событие получает минимум двух показанных получателей, и они идут по возрастанию цены события для них; каждый следующий добавляет то, чего не показал предыдущий.",
   "why": "Центральный механизм meta-function (шаг 3 псевдокода и invariants[2]), не покрытый прежним набором: C-BOARD-04 требовал лишь, чтобы у платящего персонажа был СВОЙ кадр, но ничего не говорил о порядке и о приросте смысла.",
   "evidence_in_original": [
    "meta-function.json/pseudocode: `for listener in sorted(who, key=lambda p: cost[p])` с комментарием «от наименьшей цены к наибольшей»",
    "meta-function.json/invariants[2]: «Один факт получает нескольких получателей… S01: SH001 оглашение (общий) → SH002 лицо отца → SH006 вставка рук матери → SH007 безмолвный взгляд дочери»",
    "S13: SH096 цифра → SH097 отец → SH102 руки → SH103 дочь"
   ],
   "check": {
    "method": "human",
    "procedure": "Для ключевого события выписать таблицу «получатель → цена события для него → номер кадра → что этот кадр добавляет». Сверить порядок кадров с порядком возрастания цены.",
    "pass_if": "У ключевого события ≥2 показанных получателя; порядок их кадров совпадает с порядком возрастания цены события для них; у каждого следующего кадра названо то, чего не показал предыдущий. Единица без получателей допустима, если реакция явно перенесена в следующую (C-SCENE-04).",
    "reference_fragment": "analysis/original-atomic/fragments/joins/J005.mp4"
   },
   "on_fail": "Переставить кадры получателей по возрастанию цены; добавить второго получателя; убрать кадр, ничего не добавляющий.",
   "evidence_class": "human",
   "implementation_status": "human procedure only",
   "not_overfit_note": "Получателем может быть кто угодно, включая того, кому событие стоит меньше всех и кто идёт первым. Цена — не эмоция, а то, что персонаж теряет или обязан сделать."
  },
  {
   "id": "C-SCENE-01",
   "phase": "scene",
   "statement": "Наблюдаемое действие носителя начинается, развивается и завершается внутри одного дубля.",
   "why": "Оригинал ни разу не склеивает две фазы одного движения; именно это делает движение непрерывным. Носителем действия может быть человек, прибор, жидкость или документ.",
   "evidence_in_original": [
    "S01/SH006: рука входит 11.95 → накрывает 12.40 — один план",
    "S11/SH086: приём капсулы целиком за 3.3 s без склейки",
    "S07/SH053: левая рука на плечо ≈134.9 → пауза → правая ладонь на «explain» 136.2–136.6"
   ],
   "check": {
    "method": "model",
    "procedure": "Дать видеомодели каждый дубль сгенерированного фильма через magnified_clip(factor=2..4) и спросить: начинается ли видимое действие носителя внутри дубля и завершается ли оно до его конца.",
    "pass_if": "В каждом дубле, где есть действие носителя, оно и начинается, и завершается внутри дубля (или явно продолжается в следующем без склейки внутри фазы). Действие может принадлежать человеку, прибору, жидкости или документу: у него должны быть начало, ход и завершение.",
    "reference_fragment": "analysis/original-atomic/fragments/events/E02-hand-contact-x4.mp4"
   },
   "on_fail": "Перегенерировать дубль с большей длительностью, чтобы действие уместилось целиком.",
   "not_overfit_note": "Действие любое: рука на плечо, подпись документа, поворот вентиля, вода, добравшаяся до порога, лист, выходящий из принтера. Формулировка «жест» заменена на «наблюдаемое действие носителя» по возражению: обязательные дубли без тела (датчик мигает под мойкой, уведомление всплывает на экране) по букве прежней редакции содержали ноль жестов.",
   "evidence_class": "model",
   "implementation_status": "not runnable",
   "implementation_gap": "model-проверки не имеют вызывающего кода: atomic/validate.py:236 возвращает 'model_checks': 'run per criterion with run_model_check(...)' — строку вместо результатов. Кроме того: (1) run_model_check передаёт оба клипа БЕЗ временного увеличения, хотя magnified_clip (setpts 2–4×, fragments.py:32) применялся при чтении стыков и событий оригинала (passes.py:92,104), а эффективная частота дискретизации эндпоинта ~1 кадр/с (memory/kie-gemini-video-endpoint-limits.md) — паузы 0.62 s, фазы жеста и опережение 0.15–0.40 s судье физически не видны; (2) кэш analyze() сравнивает только ('prompt_sha256','media','generation_config','model') и НЕ учитывает extra_media (video_model.py:75-80), а сгенерированный клип передаётся именно как extra_media — после перегенерации дубля повторный прогон под тем же именем вернёт СТАРЫЙ вердикт. Требуется: шаг `run.py validate --model-checks`, обязательное magnified_clip(factor=2..4) для обоих клипов и sha256 сгенерированного клипа в имени записи доказательства; extra_media — в набор полей сравнения кэша."
  },
  {
   "id": "C-SCENE-02",
   "phase": "scene",
   "statement": "После решающей информации идёт безмолвное удержание ≥1 s — именно после неё, а не где-нибудь в фильме.",
   "why": "Оригинал дочитывает реакцию на лице, а не проговаривает её.",
   "evidence_in_original": [
    "S01/SH007 1.97 s",
    "S13/SH103 2.83 s",
    "S10/SH078 ≈1.95 s"
   ],
   "check": {
    "method": "measured",
    "procedure": "Найти в ledger.json сгенерированного фильма планы без слов длиннее 1 s и сверить их положение с границами единиц: удержание должно начинаться в пределах 5 s после конца реплики, несущей плохую новость, и после реплики решения.",
    "pass_if": "Есть минимум по одному безмолвному плану ≥1 s, начинающемуся в пределах 5 s после конца реплики плохой новости И после реплики решения.",
    "reference_fragment": "analysis/original-atomic/fragments/strips/SH007.jpg"
   },
   "on_fail": "Добавить безмолвный дубль реакции после соответствующей реплики.",
   "not_overfit_note": "Молчание — универсальный приём; к болезни отношения не имеет. Отличие от C-EDIT-05: там — наличие безмолвных удержаний в фильме вообще (постфактум, доля), здесь — их ПРИВЯЗКА к решающим репликам.",
   "evidence_class": "measured",
   "implementation_status": "partially implemented (alias of C-EDIT-05)",
   "implementation_gap": "atomic/validate.py: `@measured('C-SCENE-02') def silent_hold_after_decisive_info(...): return silent_reaction_holds(ledger, crit)` — реализация просто считает ≥3 безмолвных плана ГДЕ УГОДНО в фильме, привязка к единицам молча теряется. Фильм с тремя безмолвными планами в финальном монтаже пройдёт критерий, не имея ни одного удержания после ключевой новости. Требуется: поле `unit`/`scene` на плане в ledger и на репликах, и проверка окна 5 s после названных реплик. check.method менять нельзя — id зарегистрирован в atomic/validate.py."
  },
  {
   "id": "C-SCENE-03",
   "phase": "scene",
   "statement": "Пауза перед ответом принадлежит лицу спрашивающего.",
   "why": "В оригинале ожидание ответа показано на том, кто спросил, а не на том, кто отвечает.",
   "evidence_in_original": [
    "S02: план дочери SH012 держится 1.0 s без голоса и принимает закадровое начало ответа «Yeah,»",
    "S13/SH100: 0.62 s молчания на лице отца перед его же ответом"
   ],
   "check": {
    "method": "model",
    "procedure": "Дать видеомодели фрагмент вопрос-ответ сгенерированного фильма и соответствующий фрагмент оригинала, ОБА через magnified_clip(factor=2..4); спросить, чьё лицо занимает паузу.",
    "pass_if": "В минимум одной паре «вопрос — ответ» пауза показана на лице спрашивающего/ожидающего.",
    "reference_fragment": "analysis/original-atomic/fragments/events/E03-car-reassurance-x4.mp4"
   },
   "on_fail": "Перемонтировать: удержать план спрашивающего на паузу и дать началу ответа зайти за кадр.",
   "not_overfit_note": "Работает в любом диалоге, где ответ важен спрашивающему. Без временного увеличения проверка бессмысленна: измеренная пауза оригинала в этом критерии — 0.62 s (S13/SH100), а эндпоинт даёт судье ~1 кадр/с.",
   "evidence_class": "model",
   "implementation_status": "not runnable",
   "implementation_gap": "model-проверки не имеют вызывающего кода: atomic/validate.py:236 возвращает 'model_checks': 'run per criterion with run_model_check(...)' — строку вместо результатов. Кроме того: (1) run_model_check передаёт оба клипа БЕЗ временного увеличения, хотя magnified_clip (setpts 2–4×, fragments.py:32) применялся при чтении стыков и событий оригинала (passes.py:92,104), а эффективная частота дискретизации эндпоинта ~1 кадр/с (memory/kie-gemini-video-endpoint-limits.md) — паузы 0.62 s, фазы жеста и опережение 0.15–0.40 s судье физически не видны; (2) кэш analyze() сравнивает только ('prompt_sha256','media','generation_config','model') и НЕ учитывает extra_media (video_model.py:75-80), а сгенерированный клип передаётся именно как extra_media — после перегенерации дубля повторный прогон под тем же именем вернёт СТАРЫЙ вердикт. Требуется: шаг `run.py validate --model-checks`, обязательное magnified_clip(factor=2..4) для обоих клипов и sha256 сгенерированного клипа в имени записи доказательства; extra_media — в набор полей сравнения кэша."
  },
  {
   "id": "C-SCENE-04",
   "phase": "scene",
   "statement": "Сцена без адресата допустима, если реакция явно перенесена в следующую единицу.",
   "why": "Оригинал держит 10.6 s без слов и без получателя, а ответ (открытая дверь и имя) отдаёт следующей сцене.",
   "evidence_in_original": [
    "S04 44.0–54.6: 0 слов, 0 получателей; «Lily?» звучит уже в S05 55.23"
   ],
   "check": {
    "method": "human",
    "procedure": "Проверить по сценарию: у каждой бессловесной сцены есть следующая сцена, принимающая её действие.",
    "pass_if": "Нет бессловесной сцены, действие которой не подхвачено.",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W04-street-door.mp4"
   },
   "on_fail": "Добавить сцену-приёмник или убрать бессловесную сцену.",
   "not_overfit_note": "Путь, ожидание, дорога — универсальные бессловесные единицы.",
   "evidence_class": "human",
   "implementation_status": "human procedure only"
  },
  {
   "id": "C-VOICE-01",
   "phase": "voice",
   "statement": "Реплика-реакция начинается через 0.15–1.2 s после конца стимула ВНУТРИ ОДНОЙ единицы; мгновенный ответ допустим только там, где скорость и есть свидетельство.",
   "why": "Измеренные паузы оригинала: 1.2 s между вопросом дочери и ответом отца; 0.18–0.32 s у наставника, отвечающего скептику. Межсценовые разрывы паузами не являются.",
   "evidence_in_original": [
    "S02: «right?» 22.70 → «Yeah,» 23.90",
    "S09: паузы наставника 0.28 / 0.32 / 0.18 s",
    "Пересчёт по ledger.json: из 40 «пауз» 5 длиннее 3 s и ВСЕ межсценовые; внутрисценовый максимум 2.69 s; в диапазоне 0.8–3.0 s — 6"
   ],
   "check": {
    "method": "measured",
    "procedure": "По ledger.json сгенерированного фильма посчитать паузы между соседними репликами разных участников ВНУТРИ одной единицы. Счёт обрывается на границе единицы, на затемнении/растворении и на разрыве >3 s. Паузу «дорогого ответа» проверять на паре «вопрос → ответ», отмеченной в карточке единицы.",
    "pass_if": "Медиана внутрисценовых пауз при смене говорящего 0.15–1.2 s; есть минимум одна пауза 0.8–2.5 s перед ответом, который персонажу дорого дать.",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W02-car.mp4"
   },
   "on_fail": "Перегенерировать реплику с явной инструкцией на паузу перед ответом.",
   "not_overfit_note": "Диапазон пауз проверяется на фактическом звуке любой локализации, НО пословный клок и метки говорящих берутся англоязычным ASR: atomic/measure.py:79 задаёт language='en' по умолчанию, run.py:41 вызывает words() без языка, CLI-флага языка нет. Предусловие: `run.py measure --language <язык дорожки>`; до проброса флага критерий на неанглийской дорожке помечается unknown, а не pass. Метки говорящих для адаптации брать в первую очередь из плана дубля (в раскадровке у дубля назван говорящий), а текстовое выравнивание использовать как второй голос.",
   "evidence_class": "measured-on-model-reading (пословный клок измерен, метка говорящего — оценка)",
   "implementation_status": "partially implemented",
   "implementation_gap": "atomic/validate.py:174-186 (reply_pauses) считает паузы между соседними словами при ЛЮБОЙ смене метки говорящего по ВСЕМУ фильму, без ограничения на смежность внутри единицы, и не имеет верхней границы (`max(pauses) >= 0.8`). На самом оригинале критерий засчитан разрывом 19.84 s: конец «number.» 239.14 (S11) → «Let's» 258.98 (монтаж недель), внутри которого лежат затемнение 244.6–245.1 и два растворения. Медиана по пересчёту 0.44 s (в self-test 0.46 — верхняя медиана). Требуется: (1) поле `unit`/`scene` на плане в ledger и обрыв счёта на границах единиц, затемнениях и разрывах >3 s; (2) верхняя граница 2.5 s вместо открытого ≥0.8; (3) метка «дорогого ответа» из карточки единицы. ОТДЕЛЬНО: метки говорящих — не измерение, а оценка (ledger.py:26-55 label_speakers присваивает их difflib-выравниванием токенов ASR по тексту видеомодели); разметка держится на демографически разном касте оригинала (['doctor','girl','man','older man','older woman','woman']). При однородном касте две роли получат одну метку, смены говорящего исчезнут и проверка обязана возвращать unknown, а не считать паузы внутри реплики одного человека. check.method менять нельзя — id зарегистрирован в atomic/validate.py."
  },
  {
   "id": "C-VOICE-02",
   "phase": "voice",
   "statement": "Заверение, в которое не верят, звучит с отводом взгляда или улыбкой, а реакция адресата не показывается.",
   "why": "Оригинал разводит слова и тело: отец говорит «I'm gonna be fine», опуская взгляд, а лицо дочери на этих словах не показано.",
   "evidence_in_original": [
    "S02/SH013 24.1–25.53: улыбка и опущенный взгляд",
    "реакция дочери на «fine» не показана (SH014 руки, SH015 затылок)"
   ],
   "check": {
    "method": "model",
    "procedure": "Дать видеомодели фрагмент заверения из сгенерированного фильма и S02 оригинала, ОБА через magnified_clip(factor=2..4); спросить, расходятся ли слова и телесное поведение и показана ли реакция адресата.",
    "pass_if": "Модель фиксирует расхождение слов и тела; реакция адресата на ключевое слово не показана.",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W02-car.mp4"
   },
   "on_fail": "Перегенерировать дубль с указанием на отвод взгляда; убрать план реакции адресата.",
   "not_overfit_note": "Приём работает везде, где герой успокаивает, не имея оснований.",
   "evidence_class": "model",
   "implementation_status": "not runnable",
   "implementation_gap": "model-проверки не имеют вызывающего кода: atomic/validate.py:236 возвращает 'model_checks': 'run per criterion with run_model_check(...)' — строку вместо результатов. Кроме того: (1) run_model_check передаёт оба клипа БЕЗ временного увеличения, хотя magnified_clip (setpts 2–4×, fragments.py:32) применялся при чтении стыков и событий оригинала (passes.py:92,104), а эффективная частота дискретизации эндпоинта ~1 кадр/с (memory/kie-gemini-video-endpoint-limits.md) — паузы 0.62 s, фазы жеста и опережение 0.15–0.40 s судье физически не видны; (2) кэш analyze() сравнивает только ('prompt_sha256','media','generation_config','model') и НЕ учитывает extra_media (video_model.py:75-80), а сгенерированный клип передаётся именно как extra_media — после перегенерации дубля повторный прогон под тем же именем вернёт СТАРЫЙ вердикт. Требуется: шаг `run.py validate --model-checks`, обязательное magnified_clip(factor=2..4) для обоих клипов и sha256 сгенерированного клипа в имени записи доказательства; extra_media — в набор полей сравнения кэша."
  },
  {
   "id": "C-VOICE-03",
   "phase": "voice",
   "statement": "Закадровый рассказ включается только после того, как персонаж заслужил право говорить от первого лица.",
   "why": "В оригинале VO появляется лишь после того, как заслуга переадресована, — до этого фильм только показывает.",
   "evidence_in_original": [
    "S14 289.98–292.34 переадресация → S15 294.59 первое закадровое слово «My»"
   ],
   "check": {
    "method": "human",
    "procedure": "Проверить по сценарию момент первого закадрового слова относительно сцены, дающей герою это право.",
    "pass_if": "Первое закадровое слово звучит после сцены, где герой получает основание говорить о произошедшем.",
    "reference_fragment": "analysis/original-atomic/fragments/joins/J105.mp4"
   },
   "on_fail": "Перенести начало VO позже или добавить сцену, дающую основание.",
   "not_overfit_note": "Право может давать любая сцена признания — благодарность, вердикт, отчёт.",
   "evidence_class": "human",
   "implementation_status": "human procedure only"
  },
  {
   "id": "C-VOICE-04",
   "phase": "voice",
   "statement": "Ни одно слово, действие или значимая реакция не теряются при допуске длительности ±25%.",
   "why": "Правило проекта: фактическая длительность может отличаться на ±25%, но не за счёт пропусков.",
   "evidence_in_original": [
    "harness/owner-output-policy.json; REFERENCE-GENERATION-CONTRACT.md"
   ],
   "check": {
    "method": "measured",
    "procedure": "Две независимые проверки. (1) Длительность: `scripts/production_policy.py::review_output_policy` на фактических дублях — сравнение ведётся с длиной ПЛАНА В МОНТАЖЕ, а не с квантованной длиной задания (4/6/8/10 s). (2) Полнота реплики: `run.py measure --language <язык дорожки>` и сверка пословного ASR-клока с авторским текстом по нормализованному совпадению (регистр, пунктуация и дефисы отбрасываются).",
    "pass_if": "(а) фактическая длительность в пределах [длина плана в монтаже × 0.75, × 1.25]; (б) каждое слово авторского текста найдено в ASR-клоке дубля при нормализованном совпадении ≥0.95; при более низком совпадении или при несовпадении языка дорожки и языка ASR-прогона критерий помечается unknown, а НЕ pass.",
    "reference_fragment": "соответствующий оригинальный фрагмент сцены",
    "implemented_by": "scripts/production_policy.py::review_output_policy (только пункт «а») + run.py measure (пункт «б» НЕ реализован)"
   },
   "on_fail": "Перегенерировать дубль. Ускорение и потеря слов, действий или реакций не допускаются. Удаление ХВОСТА дубля (кадров после последнего слова и после завершения действия) обрезкой в смысле этого запрета не является и разрешено — иначе квантование задания до 4/6/8/10 s делает недостижимыми короткие планы, которых требует C-EDIT-07.",
   "not_overfit_note": "Проектное правило, действует для любого продукта. Языковая независимость касается САМОГО правила, но не харнесса: пословный клок жёстко берётся англоязычным ASR (measure.py:79, run.py:41), поэтому для неанглийской дорожки язык измерения обязан быть объявлен в отчёте.",
   "evidence_class": "external + measured",
   "implementation_status": "partially implemented",
   "implementation_gap": "scripts/production_policy.py:30-43 проверяет ТОЛЬКО ±25% длительности и булев флаг subtitles_observed; проверки присутствия всех слов авторского текста там нет вообще. Требуется отдельная реализация пункта «б» с порогом на нормализованное совпадение и с явным языком ASR-прогона (run.py не имеет флага --language; atomic/measure.py:79 берёт 'en')."
  },
  {
   "id": "C-VIDEO-01",
   "phase": "video",
   "statement": "В дубле с людьми — не более одного законченного действия; дубли-вставки и удержания реакции без события допускаются и помечаются в раскадровке как hold/insert.",
   "why": "Оригинал держит план ровно до конца одного действия — это и задаёт длину. Но он же держит вставки и удержания вовсе без действия.",
   "evidence_in_original": [
    "S12: восемь планов, в каждом один жест (улыбка, касание, подход, переход бега в шаг, поза смеха, встречный взгляд, поворот)",
    "Контрпримеры из ledger.json: SH018 (1.966 s, 0 слов, «The tablet screen showing a Google search bar»), SH020 (1.467 s, 0 слов, «tablet screen»), SH110 (3.649 s, 0 слов, 0 людей, «Product pouch on a table with text overlays»)",
    "meta-function.json/counterexamples, S16: «0 людей, 3.9 s тишины, длительность задана чтением, а не действием»"
   ],
   "check": {
    "method": "model",
    "procedure": "Дать видеомодели каждый дубль через magnified_clip(factor=2..4) и спросить: сколько законченных действий носителя он содержит. Сверить с типом дубля, заявленным в раскадровке (action | hold | insert).",
    "pass_if": "В дубле, заявленном в раскадровке как action, ровно одно законченное действие носителя: ноль — недопустимо, два и более — повод разрезать. В дубле, заявленном как hold или insert, ноль действий допустим и является нормой.",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W12-montage.mp4"
   },
   "on_fail": "Разделить дубль на два, перегенерировать с одним действием, либо перевести дубль в тип hold/insert в раскадровке.",
   "not_overfit_note": "Учитывает ограничение Omni Flash: короткие дубли лучше держат одно действие. Слово «телесное» убрано по возражению: обязательные дубли без тела (датчик мигает, вода добирается до порога, уведомление на экране, лист из принтера) по прежней букве обязаны были провалиться, а требование «ноль недопустимо» прямо конфликтовало с C-EDIT-05/C-SCENE-02, которые ТРЕБУЮТ безмолвных неподвижных удержаний.",
   "evidence_class": "model",
   "implementation_status": "not runnable",
   "implementation_gap": "model-проверки не имеют вызывающего кода: atomic/validate.py:236 возвращает 'model_checks': 'run per criterion with run_model_check(...)' — строку вместо результатов. Кроме того: (1) run_model_check передаёт оба клипа БЕЗ временного увеличения, хотя magnified_clip (setpts 2–4×, fragments.py:32) применялся при чтении стыков и событий оригинала (passes.py:92,104), а эффективная частота дискретизации эндпоинта ~1 кадр/с (memory/kie-gemini-video-endpoint-limits.md) — паузы 0.62 s, фазы жеста и опережение 0.15–0.40 s судье физически не видны; (2) кэш analyze() сравнивает только ('prompt_sha256','media','generation_config','model') и НЕ учитывает extra_media (video_model.py:75-80), а сгенерированный клип передаётся именно как extra_media — после перегенерации дубля повторный прогон под тем же именем вернёт СТАРЫЙ вердикт. Требуется: шаг `run.py validate --model-checks`, обязательное magnified_clip(factor=2..4) для обоих клипов и sha256 сгенерированного клипа в имени записи доказательства; extra_media — в набор полей сравнения кэша."
  },
  {
   "id": "C-VIDEO-02",
   "phase": "video",
   "statement": "Ни одного субтитра, титра-реплики или служебной графики поверх кадра. Диегетический текст в кадре субтитром не является.",
   "why": "Правило владельца для всего проекта. Титры в оригинале — свойство источника и не дают права генерировать их.",
   "evidence_in_original": [
    "Оригинал содержит крупные белые титры (наблюдение: fragments/strips/SH088.jpg, «WEEK 2» на кадрах 245.1–247.4); проектное правило запрещает генерировать их",
    "REFERENCE-GENERATION-CONTRACT.md: «Never generate or add subtitles… Any newly generated take with subtitles fails retention even if their spelling is correct»"
   ],
   "check": {
    "method": "human",
    "procedure": "(1) `scripts/production_policy.py::check_subtitle_options` — отклонить явные опции в теле задания ДО траты. (2) По каждому дублю построить `fragments.frame_strip` и просмотреть полосу; результат передать в `scripts/production_policy.py::review_output_policy` как subtitles_observed. Без просмотра статус остаётся 'pending', а не 'pass'.",
    "pass_if": "Ноль текстовых наложений речи и служебной графики поверх кадра в любом дубле и в финальном монтаже. НЕ считаются нарушением: диегетический текст внутри мира кадра (строка документа, экран прибора, сумма счёта, дата на письме, вывеска) и финальная карточка предложения, СОБИРАЕМАЯ В МОНТАЖЕ (C-STRUCT-04), а не генерируемая видеомоделью.",
    "reference_fragment": "—",
    "implemented_by": "scripts/production_policy.py::check_subtitle_options (опции задания) + review_output_policy (запись человеческого наблюдения)"
   },
   "on_fail": "Перегенерировать дубль без субтитров; дубль с субтитрами не допускается к монтажу даже при верном тексте.",
   "not_overfit_note": "Проектное правило, действует для любого продукта. Различение диегетического текста добавлено по возражению: без него набор загонял автора в неразрешимый угол — C-SCRIPT-08 и C-PASS-01 требуют предъявить измерение, а измеритель у многих продуктов живёт как текст (строка акта, сумма счёта, показание на экране), зачитывать который вслух неестественно. Для неанглийской озвучки риск самовольно вжжённых субтитров выше, поэтому просмотр полос обязателен по каждому дублю.",
   "evidence_class": "human (+ external запись результата)",
   "implementation_status": "human procedure only",
   "implementation_gap": "Автоматической проверки пикселей нет: review_output_policy:34-38 принимает subtitles_observed как ГОТОВЫЙ булев результат человеческого просмотра (None → 'pending'), а check_subtitle_options:22-27 проверяет только поля 'subtitles','captions','generate_subtitles',… в теле задания и не видит титров, которые модель вжигает сама. Метод изменён с 'measured' на 'human' по возражению: критерий не входит в список id, зарегистрированных в atomic/validate.py, и прежняя пометка 'measured' читалась как автоматический зелёный. Вернуть 'measured' можно только после внедрения OCR-детектора текста по кадрам дубля."
  },
  {
   "id": "C-VIDEO-03",
   "phase": "video",
   "statement": "Через стык сохраняются поза, предмет, одежда и направление света — не хуже, чем в оригинале.",
   "why": "Порог откалиброван по измеренному оригиналу, а не по идеализированному образу источника.",
   "evidence_in_original": [
    "Пересчёт continuity_check по ledger.json: 7 стыков из 109 (6.4%) несут зафиксированное несовпадение",
    "Жёсткие склейки: J069 218.9 «man's hands move from table to bag», J084 274.6 «doctor's posture shifts from upright to leaning», J025 54.6 «girl's distance from door varies», J080 247.4 «elliptical jump from lying to sitting» — все четыре про позу/положение, ни одного про костюм, тождество предмета или свет",
    "Растворения между единицами: J099 249.9 «position changes from sitting to standing during the dissolve», J106 300.1 «Girl's outfit changes», J107 305.7 «Wardrobe change» — костюм расходится ТОЛЬКО на мягких переходах"
   ],
   "check": {
    "method": "model",
    "procedure": "Прогнать `run.py joins` на сгенерированном фильме: тот же промпт transition-window спрашивает про несовпадения позы/взгляда/предметов/света. Разнести результат по типу стыка (жёсткая склейка внутри единицы / мягкий переход между единицами) и посчитать долю.",
    "pass_if": "(а) на ЖЁСТКИХ склейках: ноль несовпадений костюма, тождества предмета и направления света. Дрейф позы или расстояния допускается — оригинал даёт его на 2 из 90 жёстких склеек (J069, J084) — но каждый случай выписывается в отчёт поимённо; (б) на РАСТВОРЕНИЯХ и ЗАТЕМНЕНИЯХ между единицами: несовпадение костюма и позы допускается как сжатие времени (J099, J106, J107); (в) общий порог — не хуже оригинала: доля стыков с зафиксированным несовпадением ≤7% (измерено на оригинале: 7 из 109 = 6.4%).",
    "reference_fragment": "analysis/original-atomic/fragments/joins/*.mp4 — соответствующий стык оригинала"
   },
   "on_fail": "Перегенерировать входящий дубль с явным описанием позы, костюма и предметов из предыдущего. Провал называет ЕДИНИЦУ для перегенерации, а не блокирует приёмку целиком.",
   "not_overfit_note": "Проверка непрерывности не зависит от сюжета. Прежний порог «ноль несовпадений» был выше самого оригинала и виден как ложный уже в собственном поле evidence («none seen» в подавляющем большинстве — то есть не во всех). Требовать от покадрово перегенерируемых дублей 360p того, чего не достиг снятый вживую референс, — определение переобучения на идеализированном образе источника. Заметьте: «ноль расхождений на жёстких склейках внутри сцены» тоже невыполнимо — оригинал даёт там 2 случая (J069, J084), поэтому запрет сужен до костюма, тождества предмета и света.",
   "evidence_class": "model",
   "implementation_status": "not runnable",
   "implementation_gap": "model-проверки не имеют вызывающего кода: atomic/validate.py:236 возвращает 'model_checks': 'run per criterion with run_model_check(...)' — строку вместо результатов. Кроме того: (1) run_model_check передаёт оба клипа БЕЗ временного увеличения, хотя magnified_clip (setpts 2–4×, fragments.py:32) применялся при чтении стыков и событий оригинала (passes.py:92,104), а эффективная частота дискретизации эндпоинта ~1 кадр/с (memory/kie-gemini-video-endpoint-limits.md) — паузы 0.62 s, фазы жеста и опережение 0.15–0.40 s судье физически не видны; (2) кэш analyze() сравнивает только ('prompt_sha256','media','generation_config','model') и НЕ учитывает extra_media (video_model.py:75-80), а сгенерированный клип передаётся именно как extra_media — после перегенерации дубля повторный прогон под тем же именем вернёт СТАРЫЙ вердикт. Требуется: шаг `run.py validate --model-checks`, обязательное magnified_clip(factor=2..4) для обоих клипов и sha256 сгенерированного клипа в имени записи доказательства; extra_media — в набор полей сравнения кэша."
  },
  {
   "id": "C-VIDEO-04",
   "phase": "video",
   "statement": "Каждая генерация получает соответствующий фрагмент оригинала — по РОЛИ ЕДИНИЦЫ в механизме, а не по номеру сцены.",
   "why": "Проектное правило: реплицируем DNA референса, а не изобретаем.",
   "evidence_in_original": [
    "REFERENCE-GENERATION-CONTRACT.md, таблица соответствия стадий и фрагментов"
   ],
   "check": {
    "method": "measured",
    "procedure": "`scripts/reference_generation.py` проверяет вложение фрагмента до отправки задания. Соответствие задаётся ролью единицы: оглашение / приём / объяснение / решение / датированный отрезок / проверка / возврат заслуги / карточка.",
    "pass_if": "У каждой генерации в receipt зафиксирован путь и хеш приложенного оригинального фрагмента. Если у единицы адаптации нет аналога в оригинале (ночное срабатывание прибора без людей, сцена в инстанции, печать документа), прикладывается фрагмент ближайшей по РОЛИ единицы, а причина выбора записывается в receipt. Произвольный фрагмент «лишь бы был» — нарушение.",
    "reference_fragment": "соответствующий стадии фрагмент оригинала",
    "implemented_by": "scripts/reference_generation.py::validate_generation_packet"
   },
   "on_fail": "Не отправлять задание без фрагмента; при отсутствии транспорта — пометить стадию как заблокированную.",
   "not_overfit_note": "Проектное правило для всех стадий и продуктов. Соответствие по роли, а не по номеру сцены, добавлено по возражению: пофрагментное соответствие сцен предполагает, что у каждой единицы адаптации есть двойник в оригинале, а это неверно для любого продукта с другой цепью событий.",
   "evidence_class": "external",
   "implementation_status": "external"
  },
  {
   "id": "C-EDIT-01",
   "phase": "edit",
   "statement": "Нет ЖЁСТКОЙ склейки между двумя похожими позами одного носителя в одной крупности. Проверяется ПОСТФАКТУМ по стыкам смонтированного фильма.",
   "why": "Владелец отклонил шестисекундный монтаж именно за это; оригинал в такой ситуации держит один план.",
   "evidence_in_original": [
    "S05/SH030 3.67 s одним планом (кандидаты 61.9 / 63.8 отклонены)",
    "S06/SH039 6.43 s без врезки",
    "S14 — вся сцена одним планом 8.2 s",
    "Исключение, найденное самопроверкой: J106 (300.1 s) соединяет два плана «мужчина и девочка, средний» — но это РАСТВОРЕНИЕ между разными местами внутри финального монтажа, то есть сжатие времени, а не рваная склейка. Проверка применяется только к жёстким склейкам."
   ],
   "check": {
    "method": "measured",
    "procedure": "`run.py validate` → measured-проверка C-EDIT-01 (atomic/validate.py:44-70): сравнивает who_is_framed и scale из прочтения стыка видеомоделью. Заявленные крупность и ось из раскадровки проверяются отдельно (C-BOARD-02); при расхождении раскадровка — первичный источник, прочтение модели — второй голос.",
    "pass_if": "Ноль ЖЁСТКИХ склеек, у которых уходящий и входящий планы показывают один и тот же носитель в одной крупности (растворения между разными местами не считаются). При joins_checked == 0 или при отсутствии полей — unknown, а не pass.",
    "reference_fragment": "analysis/original-atomic/fragments/scene-windows/W05-threshold-kitchen.mp4"
   },
   "on_fail": "Объединить в один удержанный план либо вставить план слушателя между ними.",
   "not_overfit_note": "Дефект «рваного движения» не зависит от сюжета и языка. Формулировка «носитель» вместо «говорящий» — чтобы правило корректно применялось и к бессловесным предметным планам (капля → лужа). Отличие от C-BOARD-02: там — проверка по раскадровке ДО генерации, здесь — постфактум по стыкам.",
   "evidence_class": "measured-on-model-reading",
   "implementation_status": "partially implemented",
   "implementation_gap": "Проверка читает не измерение, а ОЦЕНКУ видеомодели: строковые поля who_is_framed и scale из join_out.model_estimate, нормализованные регуляркой и сравненные на равенство (validate.py:44-70). check.method оставлен 'measured' ТОЛЬКО потому, что id зарегистрирован в atomic/validate.py; вердикт зависит от прочтения стыка и должен читаться как оценка. Требуется: (1) замкнутый словарь крупностей (ECU/CU/MCU/MS/MW/WS/EWS) в промпте прочтения стыка вместо свободного текста — в оригинале 24 написания на ~6 значений («medium shot» ×45 / «medium» ×36 / «ms» ×4; «medium close-up» ×38 / «mcu» ×18; «close-up» ×28 / «cu» ×8), поэтому склейка двух одинаковых поз, описанная как «MCU» и «medium close-up», не будет поймана; (2) идентификатор персонажа из паспорта (P1/P2/…) вместо описания внешности — в оригинале 102 варианта who_is_framed («man and girl» ×14 против «girl and man» ×6 и «man and young girl» ×10; «man» ×11, «middle-aged man» ×6), и однородный каст даст обоим собеседникам одну строку, завалив здоровый восьмёрочный монтаж; (3) при joins_checked == 0 возвращать unknown, а не pass (validate.py:62,67).",
   "calibration_note": "След подгонки, зафиксированный в self-test-on-original.json/found_and_fixed: проверку правили дважды, пока оригинал не стал зелёным — сначала убрали сравнение говорящих, затем сузили до жёстких склеек ради единственного стыка J106 (300.1 s). Порог выведен на одном фильме; совпадение носителя на жёстких склейках оригинала встречается всего 3 раза (J022, J024, J090 — все «young girl») и каждый раз разведено разными строками крупности."
  },
  {
   "id": "C-EDIT-02",
   "phase": "edit",
   "statement": "Звук ведёт картинку на части стыков (J-cut).",
   "why": "Оригинал не даёт речи прерываться на склейке.",
   "evidence_in_original": [
    "«We» 9.38 → cut 9.733",
    "«I» 285.98 в чёрном → крыльцо ~286.1",
    "«My» 294.59 до наплыва"
   ],
   "check": {
    "method": "measured",
    "procedure": "`run.py validate` → C-EDIT-02: считает планы, чьё первое слово начинается до входящего стыка. Требует объявленного языка ASR-прогона.",
    "pass_if": "Минимум 5% СТЫКОВ имеют слово, проходящее через стык (доля от join_count адаптации). Измерено на оригинале: 38 планов из 110 (34.5%).",
    "reference_fragment": "analysis/original-atomic/fragments/joins/J004.mp4"
   },
   "on_fail": "Сдвинуть точку склейки на 0.1–0.4 s позже начала реплики.",
   "not_overfit_note": "Приём монтажный, не сюжетный. Порог выражен долей, а не абсолютным числом: константа, откалиброванная на 110 планах, в 20-плановой адаптации значит совсем другое, а исходный хронометраж нормативом быть не может (meta-function.json/do_not_transfer).",
   "evidence_class": "measured",
   "implementation_status": "partially implemented",
   "implementation_gap": "atomic/validate.py:74: `need = max(1, round(0.05 * ledger['shot_count']))` — доля берётся от числа ПЛАНОВ, а не стыков, как сказано в pass_if. Требуется считать от join_count. Кроме того, критерий зависит от языка ASR-прогона (slots.применимость.язык): на неанглийской дорожке помечается unknown, а не pass. check.method менять нельзя — id зарегистрирован в atomic/validate.py."
  },
  {
   "id": "C-EDIT-03",
   "phase": "edit",
   "statement": "Картинка приходит к слушателю раньше его реплики (опережение 0.15–0.40 s).",
   "why": "Так зритель видит, как информация «доходит», прежде чем услышит реакцию.",
   "evidence_in_original": [
    "J001 2.733 → «That high?» 2.98 (0.25 s)",
    "S10/J073 → голос 227.05 (≈0.25 s)"
   ],
   "check": {
    "method": "measured",
    "procedure": "`run.py validate` → C-EDIT-05 (реализована): доля стыков, где первое слово входящего плана начинается через 0.15–0.40 s после стыка. Требует объявленного языка ASR-прогона.",
    "pass_if": "Опережение 0.15–0.40 s есть минимум у 5% планов со речью, но не менее чем у двух планов. Измерено на оригинале: 12 планов из 110 (10.9%).",
    "reference_fragment": "analysis/original-atomic/fragments/joins/J001.mp4"
   },
   "on_fail": "Сдвинуть склейку раньше начала реплики слушателя.",
   "not_overfit_note": "Опережение — универсальный приём подачи реакции, но его порог — доля, а не константа.",
   "evidence_class": "measured",
   "implementation_status": "partially implemented",
   "implementation_gap": "atomic/validate.py:86: порог зашит абсолютным числом `len(leads) >= 3`, откалиброванным на 110-плановом фильме. Требуется доля от числа планов со речью с полом в два плана. Зависит от языка ASR-прогона: на неанглийской дорожке — unknown. check.method менять нельзя — id зарегистрирован в atomic/validate.py."
  },
  {
   "id": "C-EDIT-04",
   "phase": "edit",
   "statement": "Затемнения закрывают единицы, растворения сжимают время; типы не путаются.",
   "why": "В оригинале 8 затемнений стоят после исчерпанных последствий, 11 растворений — внутри сжатого времени.",
   "evidence_in_original": [
    "Затемнения 15.4 / 43.8 / 142.8 / 159.4 / 231.4 / 244.6 / 265.8 / 285.7",
    "Растворения — монтаж недель и финальный VO"
   ],
   "check": {
    "method": "measured",
    "procedure": "`run.py measure` + адьюдикация на сгенерированном фильме: сопоставить тип каждого мягкого перехода с границей единицы по карточкам сцен и вернуть список нарушений.",
    "pass_if": "Каждое затемнение стоит на границе единиц с завершённым последствием; каждое растворение — внутри отрезка со сжатым временем. Наличие двух типов мягких переходов — необходимое, но НЕ достаточное условие.",
    "reference_fragment": "analysis/original-atomic/measurements/transitions-adjudicated.json"
   },
   "on_fail": "Заменить тип перехода в монтаже.",
   "not_overfit_note": "Грамматика переходов не зависит от истории.",
   "evidence_class": "measured (только наличие типов) + human (адьюдикация)",
   "implementation_status": "partially implemented",
   "implementation_gap": "atomic/validate.py: `@measured('C-EDIT-04') def join_kinds_used(...)` возвращает `{'pass': soft >= 2 and len(kinds) >= 2, …, 'note': 'join kinds present; adjudicate each one against its scene boundary by hand'}` — то есть критерий с method='measured' выдаёт pass, не проверив НИЧЕГО из заявленного в pass_if. В self-test-on-original.json он засчитан по одному лишь наличию типов: {'hard cut': 90, 'fade-through-black': 8, 'dissolve': 11}. Любой монтаж с двумя затемнениями и одним растворением, поставленными наугад, получит зелёный. Требуется: сопоставление каждого мягкого перехода с границей единицы из карточек сцен и возврат списка нарушений. До реализации адьюдикация обязательна вручную, а автоматический pass читается как «типы присутствуют», а не «типы на месте». check.method менять нельзя — id зарегистрирован в atomic/validate.py."
  },
  {
   "id": "C-EDIT-05",
   "phase": "edit",
   "statement": "В фильме есть безмолвные удержания ≥1 s. Проверяется постфактум по всему фильму; привязка к решающим репликам — C-SCENE-02.",
   "why": "Реакции в оригинале дочитываются в тишине.",
   "evidence_in_original": [
    "S01/SH007, S10/SH078, S13/SH103, S12/SH095"
   ],
   "check": {
    "method": "measured",
    "procedure": "`run.py validate` → C-EDIT-03 (реализована): считает планы без слов длиннее 1 s. Требует объявленного языка ASR-прогона.",
    "pass_if": "Безмолвные планы ≥1 s составляют не менее 10% планов адаптации, но не менее двух планов. Измерено на оригинале: 27 из 110 (24.5%).",
    "reference_fragment": "analysis/original-atomic/fragments/strips/SH103.jpg"
   },
   "on_fail": "Добавить безмолвные дубли реакции.",
   "not_overfit_note": "Не зависит от языка как ПРИЁМ: молчание переносится без перевода. Но измерение зависит: «безмолвный» здесь означает «без распознанных слов».",
   "evidence_class": "measured",
   "implementation_status": "partially implemented",
   "implementation_gap": "atomic/validate.py:92: порог зашит абсолютным числом `len(silent) >= 3`. В 20-плановой адаптации «три» — вчетверо большая доля, чем в оригинале; требуется доля с полом в два плана. Зависит от языка ASR-прогона: слово, не распознанное чужим ASR, превращает говорящий план в «безмолвный». check.method менять нельзя — id зарегистрирован в atomic/validate.py."
  },
  {
   "id": "C-EDIT-06",
   "phase": "edit",
   "statement": "План с говорящим держат до завершения фразы и возврата рук в покой — если следующий план остаётся на том же носителе. Обрыв жеста допустим, когда картинка обязана уйти на слушателя.",
   "why": "Оригинал режет говорящего посреди жеста постоянно, но каждый раз — на слушателя; на том же человеке он такой склейки не делает.",
   "evidence_in_original": [
    "S06/SH039: руки в покое к 101.6, склейка J035 102.1 после «diet.» — и всё равно gesture_state_at_join = «mid», а входящий план уходит на слушающую дочь",
    "S09/SH067 7.534 s и SH073 7.07 s — фразы с жестом не разрезаны",
    "meta-function.json/transition_rules[3]: «Резать внутрь слова допустимо, когда картинка обязана показать слушателя» (S06: склейки 92.333 и 110.1)",
    "Пересчёт по ledger.json: из 109 стыков у 77 outgoing_shot.gesture_state_at_join = «mid», из них 60 — с говорящим, названным в speech_at_join, прямо в кадре. Разбивка этих 60: 51 жёсткая склейка уходит на ДРУГОЙ носитель и ноль жёстких склеек остаётся на том же; 8 мягких переходов уходят на другой носитель и 1 остаётся на том же (J106, 300.1 s, растворение). Переформулированный pass_if даёт на оригинале ноль нарушений"
   ],
   "check": {
    "method": "model",
    "procedure": "Прогнать `run.py joins` на сгенерированном фильме; взять поля gesture_state_at_join уходящего плана и who_is_framed обоих планов. Оба клипа подавать судье через magnified_clip(factor=2..4).",
    "pass_if": "Ноль стыков, где уходящий план обрывает жест говорящего (gesture_state_at_join = «mid») И входящий план остаётся на том же носителе в кадре. Обрыв жеста при переходе на слушателя, адресата или другой носитель разрешён (transition_rules[3]).",
    "reference_fragment": "analysis/original-atomic/fragments/joins/J035.mp4 (SH039→SH040, 102.1 s: фраза договорена, склейка на слушающую) и J037.mp4 (110.1 s: склейка внутрь слова «inside» на слушателя — РАЗРЕШЁННЫЙ случай, а не образец нарушения)"
   },
   "on_fail": "Удлинить уходящий дубль до конца жеста ИЛИ увести входящий план на слушателя.",
   "not_overfit_note": "Правило про завершённость движения, а не про конкретный жест. Прежняя редакция («ноль стыков с gesture_state_at_join = mid при говорящем в кадре») проваливалась на самом оригинале — 60 случаев из 109 — и противоречила transition_rules[3]; самопроверка её не поймала, потому что self-test-on-original.json прогоняет только measured-ветку. Прежний reference_fragment J037 сам был нарушением по собственному pass_if. Для бэкенда, который режется по границам дублей, почти каждый уходящий дубль с говорящим будет «mid», и абсолютный запрет гарантировал бы красный на корректном монтаже.",
   "evidence_class": "model",
   "implementation_status": "not runnable",
   "implementation_gap": "model-проверки не имеют вызывающего кода: atomic/validate.py:236 возвращает 'model_checks': 'run per criterion with run_model_check(...)' — строку вместо результатов. Кроме того: (1) run_model_check передаёт оба клипа БЕЗ временного увеличения, хотя magnified_clip (setpts 2–4×, fragments.py:32) применялся при чтении стыков и событий оригинала (passes.py:92,104), а эффективная частота дискретизации эндпоинта ~1 кадр/с (memory/kie-gemini-video-endpoint-limits.md) — паузы 0.62 s, фазы жеста и опережение 0.15–0.40 s судье физически не видны; (2) кэш analyze() сравнивает только ('prompt_sha256','media','generation_config','model') и НЕ учитывает extra_media (video_model.py:75-80), а сгенерированный клип передаётся именно как extra_media — после перегенерации дубля повторный прогон под тем же именем вернёт СТАРЫЙ вердикт. Требуется: шаг `run.py validate --model-checks`, обязательное magnified_clip(factor=2..4) для обоих клипов и sha256 сгенерированного клипа в имени записи доказательства; extra_media — в набор полей сравнения кэша."
  },
  {
   "id": "C-EDIT-07",
   "phase": "edit",
   "statement": "Длины ПЛАНОВ В МОНТАЖЕ разнообразны: есть и удержания ≥4 s, и короткие вставки ≤1.5 s.",
   "why": "Однородный ритм — признак механического монтажа; оригинал даёт разброс 1.00–8.20 s при медиане 2.3 s.",
   "evidence_in_original": [
    "ledger.json: медиана 2.3 s, min 1.00 s (SH049 123.133–124.133, SH066), max 8.20 s (SH104 286.2–294.4)",
    "ledger-shots.md:95 «SH093 | 04:18.000 | 04:19.700 | 1.70», :106 «SH104 | 04:46.200 | 04:54.400 | 8.20»",
    "self-test-on-original.json → C-EDIT-07: {min: 1.0, max: 8.2, median: 2.333}",
    "планов ≤1.5 s в оригинале 21 из 110 (19.1%)"
   ],
   "check": {
    "method": "measured",
    "procedure": "`run.py validate` → C-EDIT-04 (реализована).",
    "pass_if": "В фильме есть минимум один ПЛАН В МОНТАЖЕ ≥4 s и минимум один ≤1.5 s. Короткий план получается подрезкой хвоста дубля: длина ДУБЛЯ берётся из 4/6/8/10 s (scripts/production_policy.py:8) и укладывается в ±25% к длине плана в монтаже (C-VOICE-04).",
    "reference_fragment": "analysis/original-atomic/ledger-shots.md"
   },
   "on_fail": "Перемонтировать: удлинить единицы объяснения, подрезать хвосты дублей под короткие вставки.",
   "not_overfit_note": "Разброс длин — свойство живого монтажа, не сюжета. Прежняя редакция называла min 0.20 s и max 7.53 s — это опровергнуто собственным ledger.json и приглашало нарезать вставки в 5 кадров, которых Omni Flash не выдаст. Порог ≤1.5 s достижим только с явным разрешением подрезать хвост дубля: конвейер квантует длительность задания вверх (scripts/compile_narrative.py:279), а C-VOICE-04 запрещает терять слова, действия и реакции — но не хвост.",
   "evidence_class": "measured",
   "implementation_status": "implemented",
   "implementation_gap": "atomic/validate.py::shot_length_variety считает длины планов из ledger сгенерированного фильма — это план в монтаже, что и требуется. Отдельной проверки длины дубля против длины плана нет; она относится к C-VOICE-04."
  }
 ],
 "slots": {
  "носитель_изменения": "То, на чём изменение видно: человек | место | предмет | прибор | документ | доступ. У носителя постоянная идентичность и отдельно описанное изменяемое состояние. Носителем может быть квартира (пятно на потолке → свежая краска), пол под мойкой (мокрый → сухой), акт проверки (с замечаниями → без). Требовать телесного «до/после» запрещено: в категориях, где продукт продаёт телесный признак, сгенерированное «до/после» тела — это заявление об эффективности (см. C-SCRIPT-09).",
  "инициатор": "Человек, понёсший цену за своё действие и запустивший цепь событий. Продукт, прибор, уведомление или алгоритм инициатором не считаются: иначе развязка вырождается в «спасибо прибору». Прибор может БЫТЬ носителем события (C-BOARD-03), но заслугу возвращают человеку (C-SCRIPT-05).",
  "измеритель": "Шкала, на которой проблема поставлена и на которой же проверяется результат: человек | место | документ | прибор | счёт | повторяемый ритуал. Может быть субъективным (то же зеркало, тот же собеседник, тот же ежедневный обход). Внешний числовой измеритель — только один из вариантов и не обязателен.",
  "носитель_продукта": "То, чем продукт присутствует в кадре: предмет | экран приложения | документ | подпись | акт | доступ. Для услуги без предмета носитель называется явно в раскадровке; если носителя нет, критерии о продукте помечаются N/A с письменной причиной, а не pass и не unknown.",
  "получатель": "Тот, кому событие чего-то стоит и чей приём события показан. Получателей может быть 0 (C-SCENE-04) или несколько (C-BOARD-05).",
  "единица": "Сцена/отрезок, закрывающий один вопрос и открывающий другой (C-SCRIPT-02).",
  "дубль": "Одна генерация видеомодели. Бэкенд владельца: Omni Flash 360p, длительность только 4/6/8/10 s (scripts/production_policy.py:8).",
  "план_в_монтаже": "Отрезок дубля в финальном монтаже. Его длина НЕ равна длине дубля: конвейер квантует задание вверх до 4/6/8/10 s (scripts/compile_narrative.py:279), поэтому короткие планы получаются подрезкой хвоста дубля. Все пороги длины планов относятся к плану в монтаже, а допуск ±25% (C-VOICE-04) — к нему же, а не к квантованной длине задания.",
  "применимость": {
   "масштаб": "Пороги выражены долями от числа планов/стыков АДАПТАЦИИ. Абсолютные числа оригинала (325.68 s, 16 единиц, 110 планов, 109 стыков) нормативом не являются — meta-function.json/do_not_transfer. Измеренные доли оригинала как ориентир: безмолвные планы ≥1 s — 27/110 = 24.5%; планы со звуковым мостом — 38/110 = 34.5%; планы с опережением 0.15–0.40 s — 12/110 = 10.9%; планы ≤1.5 s — 21/110 = 19.1%; стыки с зафиксированным несовпадением — 7/109 = 6.4%.",
   "минимум_единиц": "Структурные критерии C-STRUCT-01, C-STRUCT-02 и C-SCRIPT-08 проверяются, если в фильме ≥6 единиц и ≥2 разнесённых во времени отрезка. Ниже этого порога критерий помечается n/a с письменным обоснованием — не pass.",
   "язык": "Перед любой measured-проверкой в отчёте фиксируется язык ASR-прогона. atomic/measure.py:79 берёт language='en' по умолчанию, а run.py:41 вызывает words() БЕЗ языка и не имеет CLI-флага. На неанглийской дорожке пословный клок и метки говорящих перестают быть свидетельством. Пока флаг не проброшен, все критерии, зависящие от пословного клока (C-SCRIPT-01, C-STRUCT-04, C-VOICE-01, C-VOICE-04, C-EDIT-02, C-EDIT-03, C-EDIT-05), помечаются unknown, а не pass."
  }
 },
 "refutation_log": {
  "ran_at": "2026-09-10",
  "refuters": "два опровергателя на переобучение: (1) по адаптации goPure к украинской локализации на бэкенде Omni Flash 360p; (2) по переносимости на продукты вне тела и вне семьи (датчик протечки, бухгалтерская услуга)",
  "method": "каждое возражение перепроверено самостоятельно по analysis/original-atomic/ledger.json, ledger-shots.md, кадровым полосам fragments/strips/*.jpg, карточкам сцен, meta-function.json и коду харнесса (atomic/validate.py, measure.py, ledger.py, video_model.py, fragments.py, passes.py, run.py; scripts/production_policy.py, compile_narrative.py). Числа в поле verified_independently — результат собственного пересчёта, а не пересказ возражения; расхождения с возражением названы явно (R-01, R-02, R-04).",
  "counts": {
   "objections": 35,
   "accepted_edits": 109,
   "rejected_edits": 16,
   "verdicts": {
    "принято": 21,
    "принято частично": 14,
    "отклонено": 0
   }
  },
  "frozen_ids": "Правки, требовавшие смены check.method у C-EDIT-01, C-EDIT-04, C-SCRIPT-01, C-SCRIPT-06, C-BOARD-02, C-VOICE-01, отклонены: эти id зарегистрированы в atomic/validate.py, и смена метода сломала бы харнесс. Существо каждого такого возражения перенесено в поля evidence_class и implementation_gap.",
  "criteria_count": {
   "before": 39,
   "after": 47,
   "added": [
    "C-SCRIPT-09",
    "C-SCRIPT-10",
    "C-SCRIPT-11",
    "C-SCRIPT-12",
    "C-SCRIPT-13",
    "C-SCRIPT-14",
    "C-PASS-04",
    "C-BOARD-05"
   ]
  },
  "entries": [
   {
    "id": "R-01",
    "target": "C-EDIT-06",
    "severity": "blocker",
    "verdict": "принято частично",
    "verified_independently": "Пересчёт по ledger.json: из 109 стыков у 77 outgoing_shot.gesture_state_at_join = «mid»; из них 60 (не 23, как утверждал опровергатель) — с говорящим, названным в speech_at_join. Собственный reference_fragment критерия J037 (110.1 s, «older man», «man: 'inside'», mid) действительно нарушал его же pass_if. Больше того: J035 (102.1 s) — стык из ТЕКСТОВОГО evidence самого критерия («руки в покое к 101.6, склейка 102.1 после “diet.”») — тоже помечен «mid». Проверка предложенной переформулировки на оригинале: из 60 mid-стыков с говорящим 51 жёсткая склейка уходит на ДРУГОЙ носитель и ноль жёстких склеек остаётся на том же; из мягких переходов 8 уходят на другой носитель и 1 остаётся на том же (J106, 300.1 s, растворение). Переформулировка даёт ноль нарушений.",
    "accepted": [
     "pass_if переписан: обрыв жеста запрещён только там, где входящий план остаётся на том же носителе; переход на слушателя разрешён (transition_rules[3])",
     "statement переписан под то же условие",
     "reference_fragment заменён: J035.mp4 как образец правила, J037.mp4 оставлен и ПЕРЕКЛАССИФИЦИРОВАН как разрешённый случай (честнее, чем удалить)",
     "evidence_in_original дополнено измеренной разбивкой: 77/109 mid, 60 из них с говорящим в кадре, 51 жёсткая склейка на другой носитель против нуля на том же",
     "not_overfit_note называет причину прежней ошибки: самопроверка прогоняет только measured-ветку, а критерий помечен method=model"
    ],
    "rejected": [
     "Полное удаление J037 из reference_fragment — отклонено: стык полезнее как названный пример РАЗРЕШЁННОГО обрыва жеста"
    ]
   },
   {
    "id": "R-02",
    "target": "C-VIDEO-03",
    "severity": "blocker",
    "verdict": "принято частично",
    "verified_independently": "Пересчёт continuity_check по ledger.json: 7 стыков из 109 (6.4%) несут зафиксированное несовпадение, а не 9 — J025, J069, J080, J084 (жёсткие склейки) и J099, J106, J107 (мягкие переходы). J026 («Location jump; clothing/props match») к несовпадениям не отнесён: смена места на жёсткой склейке — граница сцены, а не разрыв непрерывности. Дополнительное наблюдение, опровергающее часть самого предложения: расхождения костюма встречаются ТОЛЬКО на растворениях (J106, J107); на жёстких склейках оригинал даёт лишь дрейф позы/положения (J069, J084).",
    "accepted": [
     "pass_if разделён на три части: (а) жёсткие склейки — ноль несовпадений костюма, тождества предмета и света; (б) мягкие переходы между единицами — костюм и поза допускаются как сжатие времени; (в) общий порог ≤7% стыков (измерено на оригинале 6.4%)",
     "evidence_in_original заменено измеренными списками стыков с поимённым разделением по типу перехода",
     "on_fail уточнён: провал называет единицу для перегенерации, а не блокирует приёмку целиком"
    ],
    "rejected": [
     "Подпункт предложения «ноль расхождений на жёстких склейках внутри сцены» — ОТКЛОНЁН: оригинал даёт там 2 случая (J069 218.9, J084 274.6), и подпункт воспроизвёл бы ту же ошибку переобучения в другую сторону. Вместо него запрет сужен до костюма, тождества предмета и света."
    ]
   },
   {
    "id": "R-03",
    "target": "Языковая независимость measured-слоя (C-VOICE-04, C-SCRIPT-01, C-STRUCT-04, C-VOICE-01, C-EDIT-02, C-EDIT-03, C-EDIT-05)",
    "severity": "blocker",
    "verdict": "принято частично",
    "verified_independently": "Проверено по коду: atomic/measure.py:79 `def words(source, out_dir, model_name=..., language: str = 'en')`; run.py:41 `w = words(a.source, out / 'measurements')` — вызов БЕЗ языка, CLI-флага языка в run.py нет. atomic/ledger.py:26-55 label_speakers присваивает говорящих difflib.SequenceMatcher по токенам ASR против текста видеомодели. scripts/production_policy.py:30-43 проверяет только ±25% длительности и булев subtitles_observed — проверки присутствия слов авторского текста там нет.",
    "accepted": [
     "В slots.применимость.язык записано предусловие: язык ASR-прогона фиксируется в отчёте; до проброса флага все зависящие от пословного клока критерии помечаются unknown, а не pass",
     "В procedure C-VOICE-04 и C-VOICE-01 явно записано `run.py measure --language <язык дорожки>`",
     "pass_if C-VOICE-04 разделён на (а) длительность и (б) присутствие каждого слова авторского текста в ASR-клоке при нормализованном совпадении ≥0.95; пункт (б) помечен как НЕ реализованный",
     "В C-VOICE-01 записано: метки говорящих брать в первую очередь из плана дубля, текстовое выравнивание — второй голос; при одной метке на две роли возвращать unknown",
     "not_overfit_note C-VOICE-01 и C-VIDEO-02 переписаны: языковая независимость касается ПРИЁМА, но не харнесса"
    ],
    "rejected": [
     "Утверждение «в Omni один дубль = один говорящий» принято как основной, но не как единственный источник меток: в раскадровке говорящий дубля объявляется явно, а не выводится из бэкенда",
     "Правка самого run.py (проброс --language) в этом файле не сделана — это изменение харнесса; записано в provenance.NOT_done и в implementation_gap"
    ]
   },
   {
    "id": "R-04",
    "target": "11 критериев с check.method=model",
    "severity": "blocker",
    "verdict": "принято частично",
    "verified_independently": "Проверено по коду: atomic/validate.py:236 возвращает 'model_checks': 'run per criterion with run_model_check(...)' — строку вместо результатов; web_clip там импортируется (validate.py:16) и не используется; magnified_clip (fragments.py:32, setpts 2–4×) применяется только в passes.py:92 (стыки) и :104 (события). video_model.py:75-80 сравнивает кэш по ('prompt_sha256','media','generation_config','model'), extra_media и meta исключены. Ограничение эндпоинта подтверждено в memory/kie-gemini-video-endpoint-limits.md (~1 кадр/с). ПОПРАВКА к формулировке возражения: «весь оригинал читался в замедлении 2–4×» неверно — оконные проходы по сценам (passes.py:78) и целофильмовый проход шли через web_clip и proxy, то есть 1×; замедлялись только стыки и микрособытия.",
    "accepted": [
     "Все 11 model-критериев (C-STRUCT-01, C-STRUCT-03, C-PASS-01, C-PASS-03, C-BOARD-03, C-SCENE-01, C-SCENE-03, C-VOICE-02, C-VIDEO-01, C-VIDEO-03, C-EDIT-06) получили implementation_status='not runnable' и общий implementation_gap с точным списком требуемых правок",
     "В procedure каждого из них добавлено обязательное magnified_clip(factor=2..4) для ОБОИХ клипов",
     "В преамбулу добавлено: прогон без выполненных пунктов implementation_gap не является полным; названо, сколько проверок реально различны",
     "provenance.NOT_done переписан и называет отсутствие прогона model-ветки первым пунктом"
    ],
    "rejected": [
     "Внесение шага `run.py validate --model-checks` и учёт extra_media в кэше analyze() — не сделано здесь: это правка харнесса, а не критериев; записано как требование"
    ]
   },
   {
    "id": "R-05",
    "target": "Отсутствующие ворота do_not_transfer",
    "severity": "blocker",
    "verdict": "принято",
    "verified_independently": "Перебор criteria[].check.pass_if прежней редакции подтверждает: ни один из 39 критериев не упоминал ни одного из девяти запретов. Совпадение с meta-function.json/do_not_transfer проверено пословно.",
    "accepted": [
     "Добавлен C-SCRIPT-09 (human, блокирующий): список всех оценочных и числовых утверждений сценария с источником; ноль без источника; ноль совпадений с do_not_transfer",
     "Расширение против предложения: под ворота подведены также ВИЗУАЛЬНЫЕ утверждения (сгенерированный телесный признак действия продукта), потому что в косметике заявление делается картинкой, а не словом",
     "На ворота сослались C-SCRIPT-03, C-SCRIPT-08, C-SCRIPT-13, C-STRUCT-04 и C-PASS-04 — именно те критерии, которые примерами подталкивали к переносу"
    ],
    "rejected": []
   },
   {
    "id": "R-06",
    "target": "C-VOICE-01 (окно подсчёта пауз)",
    "severity": "major",
    "verdict": "принято частично",
    "verified_independently": "Пересчёт по ledger.json: 40 «пауз» при смене метки говорящего по всему фильму; максимум 19.84 s — «number.» 239.14 (S11) → «Let's» 258.98 (монтаж недель), внутри лежат затемнение 244.6–245.1 и два растворения; 5 пауз длиннее 3 s и все межсценовые; внутрисценовый максимум 2.69 s; в диапазоне 0.8–3.0 s всего 6; медиана 0.44 (в self-test 0.46 — верхняя медиана). Реализация подтверждена: validate.py:174-186 не имеет ни ограничения на смежность, ни верхней границы.",
    "accepted": [
     "pass_if переписан: медиана ВНУТРИСЦЕНОВЫХ пауз 0.15–1.2 s; минимум одна пауза 0.8–2.5 s перед дорогим ответом; открытый порог max ≥0.8 s убран",
     "procedure: счёт обрывается на границе единицы, на затемнении/растворении и на разрыве >3 s; дорогой ответ берётся из карточки единицы",
     "evidence_class изменён на 'measured-on-model-reading' (клок измерен, метка говорящего — оценка)",
     "implementation_gap называет требуемое поле unit/scene на плане ledger и деградацию в unknown при одной метке на две роли"
    ],
    "rejected": [
     "Смена check.method на 'measured+model' — ОТКЛОНЕНА: id C-VOICE-01 зарегистрирован в atomic/validate.py, смена метода сломала бы validate.py. Существо возражения записано в evidence_class и implementation_gap."
    ]
   },
   {
    "id": "R-07",
    "target": "C-BOARD-02 ≡ C-EDIT-01, C-SCENE-02 ≡ C-EDIT-05, C-STRUCT-05 ≡ C-EDIT-07",
    "severity": "major",
    "verdict": "принято частично",
    "verified_independently": "Подтверждено по коду: три функции — `duration_follows_action`, `silent_hold_after_decisive_info`, `adjacent_shots_differ` — возвращают результат чужой функции без изменений. Прежний pass_if C-SCENE-02 требовал удержания ИМЕННО после плохой новости и после решения, а реализация считает ≥3 безмолвных плана где угодно.",
    "accepted": [
     "Пары не схлопнуты, а РАЗВЕДЕНЫ по разным моментам конвейера: C-BOARD-02 — проверка по раскадровке ДО генерации, C-EDIT-01 — постфактум по стыкам; C-SCENE-02 — привязка удержания к решающим репликам (окно 5 s), C-EDIT-05 — наличие удержаний в фильме вообще; C-STRUCT-05 — чем задана длина плана и связь длины дубля с длиной плана, C-EDIT-07 — разброс длин в монтаже",
     "У всех трёх псевдонимов проставлен implementation_status='partially implemented (alias of …)' с точным указанием, какое условие молча теряется",
     "В преамбуле названо, сколько из measured-проверок — псевдонимы"
    ],
    "rejected": [
     "Схлопывание каждой пары в один критерий — ОТКЛОНЕНО: все шесть id зарегистрированы в atomic/validate.py, удаление любого из них разошлось бы с реестром харнесса"
    ]
   },
   {
    "id": "R-08",
    "target": "C-STRUCT-05 и C-EDIT-07 (пороги и квантование бэкенда)",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Пересчёт по ledger.json: min 1.00 s (SH049 123.133–124.133 и SH066), max 8.20 s (SH104 286.2–294.4), медиана 2.3; SH093 = 1.70 s (258.0–259.7), SH067 = 7.534 s. Заявленные «min SH093 0.20 s, max SH067 7.53 s» ложны относительно собственного ledger. Ограничение бэкенда подтверждено: scripts/production_policy.py:8 VIDEO_DURATIONS = (4, 6, 8, 10); scripts/compile_narrative.py:279 квантует вверх. Планов ≤1.5 s в оригинале 21 из 110.",
    "accepted": [
     "evidence_in_original обоих критериев исправлено на измеренные значения со ссылками на ledger-shots.md:95 и :106",
     "Введён слот «план_в_монтаже» и разведены длина ДУБЛЯ (4/6/8/10 s) и длина ПЛАНА В МОНТАЖЕ; все пороги отнесены к плану в монтаже",
     "В C-VOICE-04 on_fail уточнено: запрет обрезки касается потери слов, действий и реакций, а удаление ХВОСТА дубля разрешено; ±25% сверяется с длиной плана в монтаже, а не с квантованной длиной задания"
    ],
    "rejected": []
   },
   {
    "id": "R-09",
    "target": "C-VIDEO-01 («ноль событий недопустимо»)",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Подтверждено по ledger.json: SH018 (1.966 s, 0 слов, «The tablet screen showing a Google search bar»), SH020 (1.467 s, 0 слов), SH110 (3.649 s, 0 слов, 0 людей). meta-function.json/counterexamples, S16: «0 людей, 3.9 s тишины». Конфликт с C-EDIT-05/C-SCENE-02, требующими безмолвных удержаний, реален.",
    "accepted": [
     "pass_if переписан: «ноль недопустимо» действует только для дубля, заявленного в раскадровке как action; дубли hold/insert допускают ноль действий",
     "Введён обязательный тип дубля в раскадровке (action | hold | insert)",
     "Слово «телесное» убрано из statement (см. R-26)"
    ],
    "rejected": []
   },
   {
    "id": "R-10",
    "target": "C-EDIT-04 (заявленное не реализовано)",
    "severity": "major",
    "verdict": "принято частично",
    "verified_independently": "Подтверждено: join_kinds_used возвращает {'pass': soft >= 2 and len(kinds) >= 2, 'note': 'join kinds present; adjudicate each one against its scene boundary by hand'}; в self-test-on-original.json критерий засчитан по одному лишь наличию типов {'hard cut': 90, 'fade-through-black': 8, 'dissolve': 11}.",
    "accepted": [
     "implementation_status='partially implemented'; implementation_gap дословно называет, что проверка не проверяет ничего из pass_if",
     "pass_if дополнен: наличие двух типов — необходимое, но НЕ достаточное условие",
     "evidence_class='measured (только наличие типов) + human (адьюдикация)'"
    ],
    "rejected": [
     "Смена check.method на 'human' — ОТКЛОНЕНА: id C-EDIT-04 зарегистрирован в atomic/validate.py. Принят альтернативный маршрут, предложенный самим опровергателем (status='partially implemented')."
    ]
   },
   {
    "id": "R-11",
    "target": "C-EDIT-01 и C-BOARD-02 (method=measured при чтении оценки модели)",
    "severity": "major",
    "verdict": "принято частично",
    "verified_independently": "Подтверждено: validate.py:44-70 читает строки who_is_framed и scale из join_out.model_estimate. Подтверждён и след подгонки: self-test-on-original.json/found_and_fixed фиксирует две последовательные правки, пока оригинал не стал зелёным. Пересчёт по ledger.json: совпадение носителя на жёстких склейках встречается 3 раза (J022, J024, J090 — все «young girl») и каждый раз разведено разными строками крупности.",
    "accepted": [
     "Введён класс свидетельства 'measured-on-model-reading' и описан в преамбуле; обоим критериям он проставлен",
     "В procedure C-EDIT-01 записано: раскадровка — первичный источник крупности и оси, прочтение модели — второй голос при расхождении",
     "Добавлено поле calibration_note с прямой записью следа подгонки на одном фильме"
    ],
    "rejected": [
     "Смена check.method на 'model' — ОТКЛОНЕНА для обоих: id зарегистрированы в atomic/validate.py"
    ]
   },
   {
    "id": "R-12",
    "target": "C-PASS-01 (два требования в одном pass_if)",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Подтверждено чтением критерия: pass_if сшивал опознание того же человека и называние наблюдаемого изменения. Ограничения подтверждены: VIDEO_RESOLUTION = '360p' (production_policy.py:7), ~1 кадр/с (memory/kie-gemini-video-endpoint-limits.md).",
    "accepted": [
     "C-PASS-01 оставлен за идентичностью носителя: опора — паспорт и кадровые полосы, прочтение модели как второй голос",
     "Добавлен C-PASS-04 (наблюдаемое изменение ПОВЕДЕНИЯ носителя-человека) с прямым запретом засчитывать признак, который продаёт продукт"
    ],
    "rejected": []
   },
   {
    "id": "R-13",
    "target": "C-STRUCT-02 (единственный показанный способ датировки — запрещённый титр)",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Проверено кадрами оригинала: fragments/strips/SH088.jpg — на кадрах 245.1–247.4 s вжжённый белый титр «WEEK 2». Запрет подтверждён в meta-function.json/do_not_transfer и в REFERENCE-GENERATION-CONTRACT.md.",
    "accepted": [
     "pass_if дополнен списком разрешённых носителей датировки без экранного текста: реплика с датой, предметный маркер, композитная карточка, собранная в МОНТАЖЕ",
     "Прямо запрещено генерировать титр внутри дубля",
     "Добавлен отдельный пункт «в датированном отрезке не звучит измерение результата», проверяемый по ASR-клоку отрезка",
     "evidence_in_original дополнено ссылкой на кадровую полосу и на пункт do_not_transfer"
    ],
    "rejected": []
   },
   {
    "id": "R-14",
    "target": "Отсутствующие: порядок получателей по возрастанию цены и тест слушателя",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Перебор criteria[].statement и pass_if по подстрокам «цен|порядк|основани|получател» даёт только C-SCRIPT-02, C-SCRIPT-07, C-PASS-02, C-BOARD-04, C-SCENE-02, C-SCENE-04, C-VOICE-03, C-EDIT-04 — ни один не покрывает ни порядок, ни тест слушателя. Источник механизма подтверждён в pseudocode (`sorted(who, key=lambda p: cost[p])`), invariants[2] и earnedness.",
    "accepted": [
     "Добавлен C-BOARD-05: ≥2 показанных получателя, порядок по возрастанию цены, у каждого следующего назван прирост",
     "Добавлен C-SCRIPT-10 (тест слушателя) с исключением, зафиксированным в оригинале (S09: приём дан скоростью ответа)",
     "C-BOARD-04 сужен ссылкой: там — только наличие собственного кадра"
    ],
    "rejected": []
   },
   {
    "id": "R-15",
    "target": "C-SCRIPT-08 (скрытое требование внешнего числового измерителя)",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Подтверждено: not_overfit_note перечислял «отчёт, счёт, показание датчика, срок» — все внешние и числовые; replaceable_slots meta-function содержит тот же перекос. Пересечение с C-STRUCT-01 и C-PASS-03 реально: оба говорят о геометрии.",
    "accepted": [
     "pass_if переписан вокруг тождества ШКАЛЫ и свидетеля; свидетель может быть субъективным (то же зеркало, тот же собеседник, тот же ритуал)",
     "Явно запрещено вводить новый измеритель ради проверки и давать числовой результат без собственного источника (ссылка на C-SCRIPT-09)",
     "Пересечения сняты ссылками: геометрия зеркала — C-STRUCT-01, геометрия пары «до/после» — C-PASS-03, здесь — только тождество измерителя"
    ],
    "rejected": []
   },
   {
    "id": "R-16",
    "target": "C-SCRIPT-06 (тег has_product и несуществующий фрагмент)",
    "severity": "major",
    "verdict": "принято частично",
    "verified_independently": "Подтверждено: ключи плана в ledger.json — duration_s, end_s, first_word_offset_s, id, join_in, join_out, model_observations, speakers, speech, start_s, words; has_product отсутствует, self-test даёт status 'unknown'. Путь фрагмента проверен: в каталоге fragments/events есть E05-garlic-gasp-x4.mp4, файла E05b-…-mp4 нет.",
    "accepted": [
     "reference_fragment исправлен на E05-garlic-gasp-x4.mp4",
     "implementation_status='requires ledger tag — сейчас всегда unknown'; implementation_gap называет требуемый шаг тегирования и жёсткий порог frac >= 0.25 в коде",
     "pass_if перестроен: жёсткое условие — только порядок «вопрос → носитель»; доля хронометража стала мягким предупреждением",
     "Введён слот «носитель_продукта» — тег определён шире физического предмета"
    ],
    "rejected": [
     "Смена check.method на 'human' — ОТКЛОНЕНА: id зарегистрирован в atomic/validate.py"
    ]
   },
   {
    "id": "R-17",
    "target": "C-VIDEO-02 (method=measured при человеческой проверке)",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Подтверждено: production_policy.py:34-38 превращает готовый булев subtitles_observed в статус (None → 'pending'); check_subtitle_options:22-27 видит только поля задания. Критерий НЕ входит в список id, зарегистрированных в atomic/validate.py, поэтому смена метода безопасна.",
    "accepted": [
     "check.method изменён с 'measured' на 'human'",
     "procedure записана конкретно: fragments.frame_strip по каждому дублю + просмотр полосы, результат передаётся в review_output_policy как subtitles_observed",
     "implementation_gap: вернуть 'measured' можно только после OCR-детектора текста по кадрам",
     "Зафиксировано именованное исключение для финальной карточки, собираемой в монтаже (C-STRUCT-04)"
    ],
    "rejected": []
   },
   {
    "id": "R-18",
    "target": "Отсутствующие: удержание последствия, закрытие вопроса действием, самопроверяемый тест, тест удаления",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Перебор criteria[] по подстрокам «удержан|withhold|тест удалени|закрывается действием» даёт только C-SCRIPT-02 (и то в on_fail). Источники механизмов подтверждены: pseudocode шаг 2, invariants «Вопрос закрывается действием с предметом», карточка S09 (три вопроса → механизм 171.39–192.91, личное свидетельство 197.41–198.93, критерий подлинности 202.49–220.89), earnedness (тест удаления).",
    "accepted": [
     "Добавлены C-SCRIPT-11 (удержание последствия), C-SCRIPT-12 (вопрос закрывается действием с носителем, не более двух реплик между), C-SCRIPT-13 (самопроверяемый признак + названный срок, сопряжён с воротами C-SCRIPT-09), C-SCRIPT-14 (тест удаления как таблица)"
    ],
    "rejected": []
   },
   {
    "id": "R-19",
    "target": "Пороги-константы (C-EDIT-05/C-SCENE-02, C-EDIT-03, C-EDIT-02, C-STRUCT-04, C-SCRIPT-06)",
    "severity": "minor",
    "verdict": "принято частично",
    "verified_independently": "Подтверждено по коду: `need = max(1, round(0.05 * ledger['shot_count']))` при pass_if «минимум 5% СТЫКОВ»; `len(leads) >= 3`; `len(silent) >= 3`. Измеренные доли оригинала: безмолвные ≥1 s — 27/110 (24.5%), звуковой мост — 38/110 (34.5%), опережение 0.15–0.40 s — 12/110 (10.9%), планы ≤1.5 s — 21/110 (19.1%).",
    "accepted": [
     "Пороги в pass_if переведены в доли с абсолютным полом: безмолвные удержания ≥10% планов, но не менее двух; звуковой мост ≥5% СТЫКОВ (от join_count); опережение ≥5% планов со речью, но не менее двух",
     "В каждом implementation_gap записано, что код считает сейчас (доля от планов вместо стыков; жёсткие константы 3)",
     "В slots.применимость добавлены масштаб (доли, а не числа оригинала) и минимум единиц, ниже которого C-STRUCT-01/02 и C-SCRIPT-08 помечаются n/a, а не pass",
     "В slots.применимость.масштаб выписаны измеренные доли оригинала как ориентир"
    ],
    "rejected": [
     "Правка самих констант в atomic/validate.py не сделана — это изменение харнесса; записано в provenance.NOT_done"
    ]
   },
   {
    "id": "R-20",
    "target": "C-PASS-01 (изменение квантифицируется по людям)",
    "severity": "blocker",
    "verdict": "принято",
    "verified_independently": "Подтверждено перебором: слово «носитель» в прежнем файле не встречалось ни разу (единственное вхождение подстроки — внутри «относительно»). Все три опоры evidence_in_original телесно-поведенческие. В meta-function «носитель» занят другим слотом («носитель знания»).",
    "accepted": [
     "В файл введён слот «носитель_изменения» = человек | место | предмет | прибор | документ | доступ, с примерами вне тела (потолок, пол под мойкой, акт проверки, распорядок)",
     "C-PASS-01 переписан через носителя; procedure для модели спрашивает «тот же ли это носитель», а не «тот же ли это человек»",
     "Требование человеческого носителя вынесено в отдельный C-PASS-04 и ограничено ПОВЕДЕНИЕМ; телесное «до/после» прямо запрещено как визуальное заявление об эффективности",
     "Слот «носитель_изменения» отличён от meta-function «носитель знания» именем"
    ],
    "rejected": []
   },
   {
    "id": "R-21",
    "target": "C-BOARD-03 («продукт без человека»)",
    "severity": "blocker",
    "verdict": "принято",
    "verified_independently": "Подтверждено: прежний pass_if запрещал план, где продукт — сам носитель события (прибор мигает ночью), и был пуст для услуги без предмета. Контрпример оригинала подтверждён в meta-function.json/counterexamples (S04: «10.6 s, ноль слов, ноль получателей… Реакция вынесена за границу единицы»), легальный перенос реакции уже описан в C-SCENE-04.",
    "accepted": [
     "Запрет переформулирован: запрещён не «продукт без человека», а «носитель продукта без события» (пэкшот, упаковка, логотип)",
     "Явно разрешён план, где продукт САМ является носителем события, при условии показанного приёма в этой или следующей единице (ссылка на C-SCENE-04)",
     "Для продукта без физической формы носитель называется явно; при его отсутствии критерий помечается N/A с письменной причиной, а не pass"
    ],
    "rejected": []
   },
   {
    "id": "R-22",
    "target": "C-EDIT-01/C-BOARD-02 (сравнение свободного текста, pass при нуле проверенных стыков)",
    "severity": "major",
    "verdict": "принято частично",
    "verified_independently": "Пересчёт по ledger.json подтверждает: 24 написания крупности на ~6 значений («medium shot» ×45 / «medium» ×36 / «ms» ×4; «medium close-up» ×38 / «mcu» ×18; «close-up» ×28 / «cu» ×8) и 102 варианта who_is_framed. Подтверждено и `if not (...): continue` + `return {'pass': not fails …}` — при joins_checked == 0 статус pass.",
    "accepted": [
     "В implementation_gap обоих критериев записаны все три правки: замкнутый словарь крупностей ECU/CU/MCU/MS/MW/WS/EWS, идентификатор персонажа из паспорта (P1/P2/…) вместо описания внешности, unknown вместо pass при joins_checked == 0",
     "В statement обоих «говорящий» заменён на «носитель в кадре» — правило корректно применяется к бессловесным предметным планам",
     "В pass_if C-BOARD-02 добавлено «при отсутствии заявленных полей — unknown, а не pass»"
    ],
    "rejected": [
     "Правка самой функции no_similar_pose_join не сделана — изменение харнесса; записано в provenance.NOT_done"
    ]
   },
   {
    "id": "R-23",
    "target": "C-VOICE-01 (метка measured и однородный каст)",
    "severity": "major",
    "verdict": "принято частично",
    "verified_independently": "Подтверждено: множество меток оригинала ['doctor','girl','man','older man','older woman','woman'] — разметка держится на демографически разном касте; метки присваиваются выравниванием (ledger.py:26). Максимальная «пауза перед ответом» 19.84 s перекрывает затемнение 244.6–245.1 и два растворения; следующие 12.55 s и 12.16 s — тоже межсценовые.",
    "accepted": [
     "evidence_class='measured-on-model-reading' с пояснением в преамбуле",
     "В implementation_gap записана обязательная деградация в unknown, когда две роли получили одну метку",
     "Счёт пауз ограничен одной единицей и смежными репликами разных участников"
    ],
    "rejected": [
     "Смена check.method — ОТКЛОНЕНА (id зарегистрирован в atomic/validate.py); см. R-06"
    ]
   },
   {
    "id": "R-24",
    "target": "C-SCRIPT-01 (проверка знает только слова)",
    "severity": "major",
    "verdict": "принято частично",
    "verified_independently": "Подтверждено: validate.py:120-128 учитывает только w['start_s'] из words; в оригинале событие совпало с речью («Your» в 0.00), поэтому подмена не проявилась. not_overfit_note сам называл допустимым событием «показание датчика», которое молчит.",
    "accepted": [
     "statement и pass_if переписаны на «инициирующее событие (произнесённое ИЛИ показанное)»",
     "implementation_gap требует тег inciting_event на плане ledger и возврат unknown вместо fail при его отсутствии; отмечено, что поле events в ledger.json уже существует",
     "not_overfit_note дополнен примерами беззвучного открытия"
    ],
    "rejected": [
     "Смена check.method — ОТКЛОНЕНА (id зарегистрирован в atomic/validate.py)"
    ]
   },
   {
    "id": "R-25",
    "target": "C-SCRIPT-08 (тождество измерителя недостижимо для профилактического продукта)",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Подтверждено чтением критерия и meta-function: тождество измерителя в оригинале обеспечено тем, что угроза хроническая и измеряется прибором, существующим до и после, — свойство продукта, а не механизма.",
    "accepted": [
     "Тождество ПРИБОРА заменено тождеством ШКАЛЫ и свидетеля (или прямого аналога на той же шкале)",
     "Добавлен явный случай «успех = отсутствие события»: шкала предъявляется как измеримый ноль (счёт на 0, сухой пол, акт без замечаний), а не репликой",
     "Добавлено требование к текстовому измерителю: читаем в кадре ≥2 s и принят человеком в кадре"
    ],
    "rejected": []
   },
   {
    "id": "R-26",
    "target": "C-SCENE-01 и C-VIDEO-01 (единица задана через тело)",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Подтверждено: pass_if C-VIDEO-01 требовал «ровно одно законченное событие; ноль — недопустимо», procedure C-SCENE-01 спрашивала про «видимый жест»; все опоры обоих критериев человеческие.",
    "accepted": [
     "В обоих «телесное событие»/«жест» заменены на «завершённое наблюдаемое действие носителя» с началом, ходом и завершением внутри дубля",
     "Требование, что в фильме ЕСТЬ телесные события, сохранено, но перенесено в C-PASS-04 (минимум один носитель-человек с наблюдаемой сменой поведения), а не требуется в каждом дубле",
     "not_overfit_note обоих дополнены примерами нечеловеческих действий (вода до порога, лист из принтера, уведомление на экране)"
    ],
    "rejected": []
   },
   {
    "id": "R-27",
    "target": "C-PASS-03 («различие — только в состоянии персонажей»)",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Подтверждено: pass_if и обе опоры (SH001.jpg + SH096.jpg) построены на расстановке людей; на паре «до/после» без людей процедура вернёт fail или мусор.",
    "accepted": [
     "statement и pass_if переписаны через носителя изменения (человек | место | предмет | прибор | документ)",
     "В procedure для модели «персонажи» заменены на «носитель, названный в паспорте единицы»",
     "not_overfit_note дополнена парами без людей (потолок с пятном ↔ после ремонта; мокрый пол ↔ сухой; стол с коробкой первички ↔ стол с подписанным актом)"
    ],
    "rejected": []
   },
   {
    "id": "R-28",
    "target": "C-PASS-02 (цепочка передачи предполагает физический предмет)",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Подтверждено: statement, procedure и все три опоры построены на физическом объекте; для услуги таблица «предмет → кто держит» оказывается пустой, и критерий проходит вакуумно.",
    "accepted": [
     "statement расширен до «владение действием, доступом и предметом»",
     "pass_if: «Нет единицы, где персонаж распоряжается предметом ИЛИ доступом, который он не получил в кадре»",
     "В procedure перечислены нематериальные носители: доступ к системе, логин, ключ, папка первички, право подписи, доверенность, право говорить от лица компании"
    ],
    "rejected": []
   },
   {
    "id": "R-29",
    "target": "C-STRUCT-01 («тот же свидетель» как человек)",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Подтверждено: все три опоры (SH001↔SH096, SH006↔SH102, SH007↔SH103) держатся на расстановке людей в кабинете; в зеркальной единице другого продукта людей может не быть вовсе.",
    "accepted": [
     "statement: «тот же носитель свидетельства (человек, место, прибор или документ)»",
     "pass_if допускает совпадение по месту и типам планов при отсутствии человека-свидетеля",
     "not_overfit_note прямо запрещает выдумывать персонажа ради формального совпадения свидетеля"
    ],
    "rejected": []
   },
   {
    "id": "R-30",
    "target": "C-VIDEO-02 в связке с C-SCRIPT-08 и C-PASS-01 (запрет текста при текстовом измерителе)",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Подтверждено: C-VIDEO-02 запрещал любые текстовые наложения, C-PASS-01 требовал «кадром, а не титром», C-STRUCT-02 при этом требовал датировки, единственный показанный носитель которой — вжжённый титр (strips/SH088.jpg). Угол действительно неразрешим.",
    "accepted": [
     "В C-VIDEO-02 введено различение: диегетический текст в мире кадра (документ, экран прибора, счёт, дата на письме, вывеска) субтитром не является; запрет касается наложений речи и служебной графики поверх кадра",
     "В C-SCRIPT-08 добавлено условие для текстового измерителя: читаем в кадре ≥2 s И принят человеком в кадре (взгляд, реакция, реплика-подтверждение)",
     "Финальная карточка, собираемая в монтаже, названа именованным исключением в обоих критериях (C-VIDEO-02 и C-STRUCT-04)"
    ],
    "rejected": []
   },
   {
    "id": "R-31",
    "target": "C-SCRIPT-06 (для услуги тег принципиально неопределим; порог 25% против профилактики)",
    "severity": "major",
    "verdict": "принято",
    "verified_independently": "Подтверждено: self-test даёт unknown уже на оригинале; порог frac >= 0.25 в коде жёсткий. Для профилактического продукта носитель обязан появиться до события, а после установки нужно уместить ещё датированный отрезок (C-STRUCT-02) и проверку (C-SCRIPT-08).",
    "accepted": [
     "Тег определён как «носитель продукта в кадре» (предмет | экран приложения | документ | подпись | акт | доступ)",
     "Для продуктов без носителя введён отдельный статус N/A с письменной причиной, чтобы «выключено» не путалось с «не проверено»",
     "Порог сформулирован относительно ВОПРОСА; доля хронометража оставлена мягким предупреждением"
    ],
    "rejected": []
   },
   {
    "id": "R-32",
    "target": "C-STRUCT-03 (pass_if добавляет запреты, не следующие из механизма)",
    "severity": "minor",
    "verdict": "принято частично",
    "verified_independently": "Подтверждено: statement описывает механизм, а pass_if добавлял «нет говорящей головы» и «нет продукта отдельно от человека» — оба взяты из стиля S15. Для услуги без предмета второй запрет пуст.",
    "accepted": [
     "В pass_if оставлен только механизм: носители изменения в изменившейся обычной жизни, предложение не открывает новую тему",
     "Оба запрета вынесены в новое поле style_observations с пометкой «наблюдение источника, не условие приёмки»"
    ],
    "rejected": [
     "Полное удаление запретов — ОТКЛОНЕНО: отсутствие говорящей головы и товарной вставки в S15 — измеренное наблюдение источника и остаётся в файле как таковое, но перестаёт блокировать приёмку"
    ]
   },
   {
    "id": "R-33",
    "target": "C-SCRIPT-05 (инициатором может стать прибор)",
    "severity": "minor",
    "verdict": "принято",
    "verified_independently": "Подтверждено: pass_if не запрещал продукту занять слот инициатора, а replaceable_slots meta-function («роль инициатора — ребёнок только один из вариантов») ограничения «только человек» не содержит.",
    "accepted": [
     "pass_if дополнен: «Инициатор — человек, понёсший цену за своё действие; продукт, прибор, уведомление или алгоритм инициатором не считаются»",
     "То же ограничение записано в slots.инициатор с указанием, что прибор может БЫТЬ носителем события (C-BOARD-03), но заслугу возвращают человеку"
    ],
    "rejected": []
   },
   {
    "id": "R-34",
    "target": "C-VIDEO-04 (пофрагментное соответствие сцен)",
    "severity": "minor",
    "verdict": "принято",
    "verified_independently": "Подтверждено по REFERENCE-GENERATION-CONTRACT.md: таблица задаёт соответствие по сцене («Matching scene/excerpt with original dialogue, action, cause and consequence»); у единиц, которых в оригинале нет, соответствующего фрагмента не существует.",
    "accepted": [
     "Соответствие переопределено по РОЛИ ЕДИНИЦЫ в механизме (оглашение / приём / объяснение / решение / датированный отрезок / проверка / возврат заслуги / карточка)",
     "Предусмотрен путь «нет аналога»: прикладывается фрагмент ближайшей по роли единицы, причина записывается в receipt; произвольный фрагмент «лишь бы был» объявлен нарушением"
    ],
    "rejected": []
   },
   {
    "id": "R-35",
    "target": "C-STRUCT-05 и C-EDIT-07 (ложные числа evidence_in_original)",
    "severity": "minor",
    "verdict": "принято",
    "verified_independently": "Пересчёт по ledger.json и ledger-shots.md:95,:106 подтверждает: 1.00 s (SH049, SH066) — 8.20 s (SH104), медиана 2.3; SH093 = 1.70 s. То же в self-test-on-original.json {min: 1.0, max: 8.2, median: 2.333}. Занижённый минимум приглашал нарезать вставки в 5 кадров.",
    "accepted": [
     "evidence_in_original обоих критериев исправлено на измеренные значения со ссылками",
     "В not_overfit_note обоих записано, что именно было опровергнуто и чем это грозило"
    ],
    "rejected": [
     "Исправление того же числа в meta-function.json (invariants, последний пункт: «0.20 s (SH093)… 7.53 s (SH067)») здесь НЕ сделано — этот файл вне задачи; ошибка записана в provenance.NOT_done как остающаяся"
    ]
   }
  ]
 }
}