Эксперимент: проверить Streaming Sortformer v2 Q8_0 против свежего W0 на Ryzen CPU #46

Closed
opened 2026-09-01 15:05:14 +03:00 by ddmitry · 3 comments
Owner

Результат и причина

Нужно реализовать изолированный стенд и получить воспроизводимый исход go
или stop для Streaming Sortformer v2 Q8_0 на целевом Ryzen CPU. Кандидат
должен сократить время построения разметки говорящих минимум на 30% относительно
свежего последовательного W0 и пройти обязательные gates качества, текста и
памяти.

Задача #45 показала, что на embeddings приходится 74,167% суммарного wall
time текущего Ryzen W0, а локальные изменения старого каскада не дали принятого
30%-го результата.
Streaming Sortformer заменяет весь путь segmentation -> embeddings -> clustering и имеет закрепляемый локальный CPU runtime. Переносимого CPU RTF для
кандидата нет, поэтому результат определяется только свежим парным A/B.

needs-user означает ожидание обязательного решения владельца. Его нельзя
публиковать как результат кандидата.

Сначала прочитать

  1. Задача #45 -
    граница исторических доказательств и причина нового опыта.
  2. docs/research/2026-09-01-end-to-end-cpu-diarization-map.md - разделы
    "Граница выводов", A1 и формула полной замены.
  3. docs/specs/2026-09-01-streaming-sortformer-cpu-experiment.md - единственный
    источник точных рецептов, пинов, gates, расписания и правил остановки.
  4. Текущие отчеты docs/benchmarks/2026-08-31-cpu-diarization-ryzen.md и
    docs/benchmarks/2026-08-31-cpu-diarization-intel.md - исторические агрегаты
    и причины остановки прежней матрицы.
  5. docs/adr/007-word-level-speaker-diarization.md - каноническое сведение слов
    с временной привязкой и разметки говорящих.

Критерий завершения чтения: исполнитель может объяснить, почему старые
3 / 2 / 2, unmatched words и purity остаются историческими значениями и не
задают gates свежего опыта.

Закрепленная гипотеза

Стенд поддерживает ровно две recipe: W0-FRESH и SORTFORMER-V2-Q8.

  • W0 - действующий непатченный sherpa-onnx/core 1.13.6, Pyannote
    Segmentation 3.0 FP32, WeSpeaker ResNet34 LM FP32,
    window_shift_ratio=0.1, FastClustering(auto, 0.89), один worker/session,
    provider=cpu для segmentation и embeddings, debug=True для обеих model
    configs, min_duration_on=0.3, min_duration_off=0.5,
    intra_op_threads=8, inter_op_threads=1, batch 1.
  • Кандидат - NVIDIA/NeMo-Speech.cpp commit
    4f9676226f667d14608487df744f375db87127f8, CPU preset cpu-diar, gpu=-1,
    один процесс и stream, standalone C ABI.
  • Модель - repo nvidia/diar_streaming_sortformer_4spk-v2, revision
    5240a64075176943f677d30fa2171c780229f341, файл
    diar_streaming_sortformer_4spk-v2.q8_0.gguf, размер 147075776 байт,
    SHA-256 0679cfeb1ce356d0dea9470b31274f4bfc7eb927497d82005483770666da998a.
  • Точная geometry, post-processing, model hashes и W0 hashes берутся из
    спецификации без изменений. Любое изменение pin, quantization, geometry,
    post-processing или hardcoded CPU thread count образует другую гипотезу.

Свежая основа

Опыт начинается с трех сохраненных исходных записей, но не продолжает старые
ячейки побайтно. Закрытые хранилища задач #41/#42, их manifests, sidecars,
опорная разметка, prepared matrices, patch и wheel не используются и не
восстанавливаются.

До завершения и приемки задачи #46 старые хранилища остаются архивом только для
чтения. Стенд не получает их пути, не читает их содержимое и отклоняет legacy ID
при валидации. Архив нужен лишь для ретроспективного аудита и не является входом,
базой сравнения или условием нового результата. После приемки отчета #46 его
можно удалить.

Новое закрытое хранилище должно содержать собственные source hashes, три новые
300-секундные области, единый mono/16 kHz float32 recipe, ASR-sidecars,
опорную разметку, подтвержденный expected_cluster_count каждого фрагмента и
каждой полной записи, runtime/model/build hashes, расписание и raw results.
Публично выходят только безопасные агрегаты, хеши и вердикты gates.

Порядок работы и точки остановки

1. Реализовать изолированный стенд

Прочитать src/local_transcriber/benchmark_experiment.py и
tests/test_benchmark_experiment.py. Реализовать новый стенд отдельным модулем
src/local_transcriber/streaming_sortformer_experiment.py с собственной schema
и recipes W0-FRESH/SORTFORMER-V2-Q8. Manifest validation должна происходить
до загрузки моделей. Реализовать redacted
--validate-only, точное расписание A/B, сбор wall/CPU/RSS, quality и
Sortformer diagnostics, остановку при первом отказе и безопасную публичную
сериализацию.

Критерий завершения: детерминированные тесты из спецификации проходят без
модели и аудио, а schema отклоняет legacy manifests, корни старых хранилищ и
ID ячеек.

2. Подготовить закрепленный runtime

Собрать закрепленный NeMo-Speech.cpp командами из спецификации и сохранить
компилятор, коммиты submodules, параметры CMake, SHA-256 исполняемого файла и
динамической библиотеки, эффективную конфигурацию. Выполнить только
синтетический C ABI-тест без аудио.

stop: несовпадение коммита, пина сборки, структуры или конфигурации,
num_speakers=4 либо seconds_per_frame=0.08 закрывает подготовку до
исправления. Smoke-проверка аудио или модели запрещена до завершения
детерминированных проверок.

Критерий завершения: синтетический ABI-тест прошел, все пины runtime и модели
проверяются локально, дальнейшая работа не требует сети.

3. Пройти пользовательский gate и создать свежую опору

Владелец выбирает три исходные записи и по одной 300-секундной области в каждой,
подтверждает право локального использования, пригодность материала,
expected_cluster_count в диапазоне 2..4 для каждого фрагмента и каждой
полной записи, доступность полных записей и готовность к безусловной финальной
слуховой приемке при медиане не ниже 30%. Diagnostics только добавляют
обязательные места прослушивания.
Материал должен совместно включать русскую рабочую речь, смену говорящего,
короткий ответ и перекрытие. В каждом контрольном объекте должно быть от двух до
четырех слышимых голосов.

stop: без решения владельца approved с отметкой времени состояние равно
needs-user, модели не загружаются. Запись с пятью и более слышимыми голосами
закрывает кандидат до измерений.

Критерий завершения: три уникальных source hash, три WAV ровно по 300 секунд,
sidecars и опорная разметка имеют SHA-256; --validate-only подтверждает свежую
опору и не печатает приватные данные.

4. Принять свежий W0

Один W0-FRESH последовательно обрабатывает три фрагмента на восьми физических
ядрах. Для каждого сохраняются сырые значения wall/CPU/RSS и времена стадий;
публично выводится сумма.

stop: любое несовпадение expected_cluster_count, sidecar-текста, порядка
слов, правил интервалов или хешей либо gate памяти дает stop; база сравнения
непригодна.

Критерий завершения: W0 прошел все обязательные gates, а закрытый result имеет
SHA-256.

5. Выполнить первичный A/B

На тех же подготовленных buffers выполнить пару W0 -> candidate. Таймеры и границы
измерения взять дословно из спецификации. Обе ветви работают на одной машине с
одинаковой affinity к восьми физическим ядрам; каждая ячейка запускается новым
дочерним процессом.

Правила остановки:

  • abs(speedup) <= 5% - результат фиксируется как равенство по скорости;
  • speedup < 10% - stop: причина equal-speed для равенства по скорости,
    иначе below-continuation;
  • speedup >= 10% при всех gates - продолжить;
  • любой обязательный quality, memory или Sortformer gate - немедленный stop.

Критерий завершения: ячейки имеют одинаковые input hashes и pair ID; сохранены
ускорение, разность CPU и RSS, первая причина остановки и хеш результата.

6. Выполнить ровно пять финальных циклов

Первичная пара не входит в финал. Порядок заранее закреплен:

  1. candidate -> W0;
  2. W0 -> candidate;
  3. candidate -> W0;
  4. W0 -> candidate;
  5. candidate -> W0.

stop: первый провал обязательного gate немедленно завершает опыт. После пяти
принятых пар медиана ниже 30% дает stop; дополнительные повторы и варианты не
назначаются. Медиана не ниже 30% открывает проверку полных записей.

Критерий завершения: сохранены ровно пять парных ускорений, медиана, MAD и
вердикты всех десяти ячеек.

7. Проверить полные записи и пройти слуховой gate владельца

W0 и кандидат однократно обрабатывают три полные записи. Их скорость остается
диагностикой и не заменяет финальную медиану. Подготовить слепой материал A/B по
коротким ответам, сменам говорящего, overlap, устойчивости соответствия голоса
кластеру, словам без говорящего и малым остаточным кластерам. Включить все места,
отмеченные diagnostics, и закрепленную случайную выборку совпадающих мест.

stop: провал автоматического gate любой пары на полной записи дает stop.
Пока владелец не записал pass/fail по всем пяти категориям, состояние равно
needs-user. Любой подтвержденный fail дает stop; полный pass при
медиане не ниже 30% дает go.

Критерий завершения: три пары прошли автоматические gates, пять решений
владельца сохранены в закрытом хранилище, публично сохранен только общий
вердикт.

8. Опубликовать безопасный результат

Сформировать отчет из рецептов, пинов, агрегатов, вердиктов gates, первой
причины остановки и SHA-256. Сохранить ограничения четырех выходных голосовых кластеров,
пяти и более слышимых голосов, non-English/out-of-domain и длинных записей.

stop: при нарушении приватности удалить публичный артефакт из рабочей ветки и
собрать его заново только из безопасных агрегатов.

Критерий завершения: итог равен go или stop; закрытое хранилище
самодостаточно, а публичный отчет проходит проверку приватности.

Обязательные gates

  • Голосовые кластеры каждого обработанного фрагмента и полной записи точно
    совпадают со свежим expected_cluster_count.
  • Нормализованный текст и порядок слов побайтно совпадают с одним sidecar; нет
    потерянных, продублированных или переставленных слов.
  • Интервалы и метки проходят правила корректности и детерминированной
    канонической нумерации из спецификации.
  • Матрица Sortformer имеет форму T x 4, вероятности конечны и лежат в
    [0, 1], итоговые метки принадлежат 1..4, эффективная конфигурация
    совпадает с пинами.
  • OOM, активный swap, RSS без плато или линейный рост RSS дают stop. Peak RSS
    выше 2 ГиБ на машине с 16 ГиБ переводит опыт в needs-user для решения
    владельца.
  • Изменения channel stability, short turns, overlap, unmatched words, малых
    кластеров или mapped purity не получают нового числового порога; они
    добавляют места в слуховой gate владельца. Открытый диагностикой gate не
    прерывает primary и финальные циклы: места накапливаются до безусловной
    приемки шага 7. needs-user из-за прослушивания возможен только после
    достижения 30%-го порога и подготовки полного blinded-материала.

Проверки

До первого запуска модели выполнить:

uv run pytest -q \
  tests/test_streaming_sortformer_experiment.py \
  tests/test_benchmark_experiment.py \
  tests/test_speaker_diarizer.py \
  tests/test_diarization.py

Новый модуль тестов должен покрывать отклонение schema, несовпадение пинов и
хешей, требование свежей опоры, обезличенный вывод --validate-only, правило
expected_cluster_count, точное расписание A/B, границы 5%/10%/30%, gates
качества, памяти и Sortformer, переход к прослушиванию, безопасную сериализацию
и остановку при первом отказе. Отдельный синтетический тест стенда C ABI
проверяет размеры структур, выбор CPU и эффективную конфигурацию без загрузки
модели.

--validate-only обязан проверить fresh-basis marker, owner approval,
expected_cluster_count каждого фрагмента и каждой полной записи, hashes обеих
recipe, effective values W0 (provider=cpu, debug=True,
min_duration_on=0.3, min_duration_off=0.5, threads, clustering), runtime
pins, clean local-transcriber worktree и source commit из manifest, одинаковые
input/sidecar hashes, geometry/post-processing, расписание, отсутствие корней
старых хранилищ и legacy ID ячеек.

Приватность

Checkout и дерево сборки NeMo-Speech.cpp, скачанные веса и новое закрытое
хранилище размещаются вне рабочей копии local-transcriber. Обычная .scratch
внутри репозитория не подходит: .gitignore покрывает там только
.scratch/handoffs/. Ни один runtime/model/build artifact или закрытый вход не
попадает в Git.

В Git, комментариях задачи, заданиях на ревью и выводе --validate-only не
публиковать пути, source/recording IDs, текст, временные интервалы, сырые
строки, содержимое manifest, логи, имена участников или аудио. Публичный отчет
содержит только точные рецепты, хеши, агрегаты и вердикты. Все исходные данные,
sidecars, опорная разметка, сырые диагностические данные и слуховые решения
остаются в новом закрытом хранилище. Хранилище и публичный отчет сохраняют
clean local-transcriber source commit, который произвел таймеры, gates,
сериализацию и назначение слов. Реализация стенда должна быть зафиксирована этим
коммитом до первого запуска модели.

Acceptance

  • Создан отдельный стенд с recipes W0-FRESH и SORTFORMER-V2-Q8; legacy
    хранилища и manifests отклоняются.
  • Свежая опора создана из сохраненных исходных записей и подтверждена
    владельцем; старые контрольные значения не наследуются.
  • Runtime, модель, сборка и оба рецепта закреплены и проверены до моделей.
  • Clean local-transcriber source commit сохранен в закрытом хранилище и
    публичном отчете, а --validate-only проверяет его до запуска модели.
  • Детерминированные тесты, синтетический ABI-тест, --validate-only и
    проверка приватности проходят.
  • Свежий W0 принят либо stop содержит точную причину провала базы
    сравнения и хеш результата.
  • Первичный A/B завершен и правила 5%/10% применены без дополнительных
    ветвей.
  • При продолжении выполнены ровно пять финальных циклов; сохранены median и
    MAD.
  • Каждая выполненная ячейка имеет вердикты качества, текста, памяти и
    Sortformer.
  • Каждый остановленный шаг сохраняет первую точную причину и хеш результата.
  • При медиане не ниже 30% выполнены три пары на полных записях и пять
    слуховых решений владельца.
  • Закрытое хранилище самодостаточно; публичный отчет содержит только безопасные
    агрегаты и SHA-256.
  • Итог равен go или stop; needs-user остается открытым до решения
    владельца.
  • Результат не меняет production-зависимости, профиль, CLI, config, ADR или
    модель по умолчанию.

Границы

  • Production-интеграция, lock зависимостей, упаковка runtime и изменение ADR не
    входят в эту задачу.
  • Production-профиль, CLI, контракт конфигурации и модель по умолчанию
    сохраняются.
  • Параллельное планирование ASR/диаризации принадлежит
    задаче #22.
  • Автоматическое включение принадлежит
    задаче #23.
  • Joint ASR+diarization и shared-ASR-encoder исключены; ASR-sidecar используется
    только как quality input.
  • Повтор старой матрицы W/M/Q/E/C, восстановление C1 и запуски на Intel или
    других CPU исключены.
  • Результат go разрешает только отдельное последующее production-решение и не
    меняет dependencies, профиль, CLI, config или модель по умолчанию.
## Результат и причина Нужно реализовать изолированный стенд и получить воспроизводимый исход `go` или `stop` для Streaming Sortformer v2 Q8_0 на целевом Ryzen CPU. Кандидат должен сократить время построения разметки говорящих минимум на 30% относительно свежего последовательного W0 и пройти обязательные gates качества, текста и памяти. Задача #45 показала, что на embeddings приходится `74,167%` суммарного wall time текущего Ryzen W0, а локальные изменения старого каскада не дали принятого 30%-го результата. Streaming Sortformer заменяет весь путь `segmentation -> embeddings -> clustering` и имеет закрепляемый локальный CPU runtime. Переносимого CPU RTF для кандидата нет, поэтому результат определяется только свежим парным A/B. `needs-user` означает ожидание обязательного решения владельца. Его нельзя публиковать как результат кандидата. ## Сначала прочитать 1. [Задача #45](https://git.dementev.space/ddmitry/local-transcriber/issues/45) - граница исторических доказательств и причина нового опыта. 2. `docs/research/2026-09-01-end-to-end-cpu-diarization-map.md` - разделы "Граница выводов", A1 и формула полной замены. 3. `docs/specs/2026-09-01-streaming-sortformer-cpu-experiment.md` - единственный источник точных рецептов, пинов, gates, расписания и правил остановки. 4. Текущие отчеты `docs/benchmarks/2026-08-31-cpu-diarization-ryzen.md` и `docs/benchmarks/2026-08-31-cpu-diarization-intel.md` - исторические агрегаты и причины остановки прежней матрицы. 5. `docs/adr/007-word-level-speaker-diarization.md` - каноническое сведение слов с временной привязкой и разметки говорящих. Критерий завершения чтения: исполнитель может объяснить, почему старые `3 / 2 / 2`, unmatched words и purity остаются историческими значениями и не задают gates свежего опыта. ## Закрепленная гипотеза Стенд поддерживает ровно две recipe: `W0-FRESH` и `SORTFORMER-V2-Q8`. - W0 - действующий непатченный `sherpa-onnx/core 1.13.6`, Pyannote Segmentation 3.0 FP32, WeSpeaker ResNet34 LM FP32, `window_shift_ratio=0.1`, `FastClustering(auto, 0.89)`, один worker/session, `provider=cpu` для segmentation и embeddings, `debug=True` для обеих model configs, `min_duration_on=0.3`, `min_duration_off=0.5`, `intra_op_threads=8`, `inter_op_threads=1`, batch 1. - Кандидат - `NVIDIA/NeMo-Speech.cpp` commit `4f9676226f667d14608487df744f375db87127f8`, CPU preset `cpu-diar`, `gpu=-1`, один процесс и stream, standalone C ABI. - Модель - repo `nvidia/diar_streaming_sortformer_4spk-v2`, revision `5240a64075176943f677d30fa2171c780229f341`, файл `diar_streaming_sortformer_4spk-v2.q8_0.gguf`, размер `147075776` байт, SHA-256 `0679cfeb1ce356d0dea9470b31274f4bfc7eb927497d82005483770666da998a`. - Точная geometry, post-processing, model hashes и W0 hashes берутся из спецификации без изменений. Любое изменение pin, quantization, geometry, post-processing или hardcoded CPU thread count образует другую гипотезу. ## Свежая основа Опыт начинается с трех сохраненных исходных записей, но не продолжает старые ячейки побайтно. Закрытые хранилища задач #41/#42, их manifests, sidecars, опорная разметка, prepared matrices, patch и wheel не используются и не восстанавливаются. До завершения и приемки задачи #46 старые хранилища остаются архивом только для чтения. Стенд не получает их пути, не читает их содержимое и отклоняет legacy ID при валидации. Архив нужен лишь для ретроспективного аудита и не является входом, базой сравнения или условием нового результата. После приемки отчета #46 его можно удалить. Новое закрытое хранилище должно содержать собственные source hashes, три новые 300-секундные области, единый mono/16 kHz float32 recipe, ASR-sidecars, опорную разметку, подтвержденный `expected_cluster_count` каждого фрагмента и каждой полной записи, runtime/model/build hashes, расписание и raw results. Публично выходят только безопасные агрегаты, хеши и вердикты gates. ## Порядок работы и точки остановки ### 1. Реализовать изолированный стенд Прочитать `src/local_transcriber/benchmark_experiment.py` и `tests/test_benchmark_experiment.py`. Реализовать новый стенд отдельным модулем `src/local_transcriber/streaming_sortformer_experiment.py` с собственной schema и recipes `W0-FRESH`/`SORTFORMER-V2-Q8`. Manifest validation должна происходить до загрузки моделей. Реализовать redacted `--validate-only`, точное расписание A/B, сбор wall/CPU/RSS, quality и Sortformer diagnostics, остановку при первом отказе и безопасную публичную сериализацию. Критерий завершения: детерминированные тесты из спецификации проходят без модели и аудио, а schema отклоняет legacy manifests, корни старых хранилищ и ID ячеек. ### 2. Подготовить закрепленный runtime Собрать закрепленный NeMo-Speech.cpp командами из спецификации и сохранить компилятор, коммиты submodules, параметры CMake, SHA-256 исполняемого файла и динамической библиотеки, эффективную конфигурацию. Выполнить только синтетический C ABI-тест без аудио. `stop`: несовпадение коммита, пина сборки, структуры или конфигурации, `num_speakers=4` либо `seconds_per_frame=0.08` закрывает подготовку до исправления. Smoke-проверка аудио или модели запрещена до завершения детерминированных проверок. Критерий завершения: синтетический ABI-тест прошел, все пины runtime и модели проверяются локально, дальнейшая работа не требует сети. ### 3. Пройти пользовательский gate и создать свежую опору Владелец выбирает три исходные записи и по одной 300-секундной области в каждой, подтверждает право локального использования, пригодность материала, `expected_cluster_count` в диапазоне `2..4` для каждого фрагмента и каждой полной записи, доступность полных записей и готовность к безусловной финальной слуховой приемке при медиане не ниже 30%. Diagnostics только добавляют обязательные места прослушивания. Материал должен совместно включать русскую рабочую речь, смену говорящего, короткий ответ и перекрытие. В каждом контрольном объекте должно быть от двух до четырех слышимых голосов. `stop`: без решения владельца `approved` с отметкой времени состояние равно `needs-user`, модели не загружаются. Запись с пятью и более слышимыми голосами закрывает кандидат до измерений. Критерий завершения: три уникальных source hash, три WAV ровно по 300 секунд, sidecars и опорная разметка имеют SHA-256; `--validate-only` подтверждает свежую опору и не печатает приватные данные. ### 4. Принять свежий W0 Один `W0-FRESH` последовательно обрабатывает три фрагмента на восьми физических ядрах. Для каждого сохраняются сырые значения wall/CPU/RSS и времена стадий; публично выводится сумма. `stop`: любое несовпадение `expected_cluster_count`, sidecar-текста, порядка слов, правил интервалов или хешей либо gate памяти дает `stop`; база сравнения непригодна. Критерий завершения: W0 прошел все обязательные gates, а закрытый result имеет SHA-256. ### 5. Выполнить первичный A/B На тех же подготовленных buffers выполнить пару `W0 -> candidate`. Таймеры и границы измерения взять дословно из спецификации. Обе ветви работают на одной машине с одинаковой affinity к восьми физическим ядрам; каждая ячейка запускается новым дочерним процессом. Правила остановки: - `abs(speedup) <= 5%` - результат фиксируется как равенство по скорости; - `speedup < 10%` - `stop`: причина `equal-speed` для равенства по скорости, иначе `below-continuation`; - `speedup >= 10%` при всех gates - продолжить; - любой обязательный quality, memory или Sortformer gate - немедленный `stop`. Критерий завершения: ячейки имеют одинаковые input hashes и pair ID; сохранены ускорение, разность CPU и RSS, первая причина остановки и хеш результата. ### 6. Выполнить ровно пять финальных циклов Первичная пара не входит в финал. Порядок заранее закреплен: 1. `candidate -> W0`; 2. `W0 -> candidate`; 3. `candidate -> W0`; 4. `W0 -> candidate`; 5. `candidate -> W0`. `stop`: первый провал обязательного gate немедленно завершает опыт. После пяти принятых пар медиана ниже 30% дает `stop`; дополнительные повторы и варианты не назначаются. Медиана не ниже 30% открывает проверку полных записей. Критерий завершения: сохранены ровно пять парных ускорений, медиана, MAD и вердикты всех десяти ячеек. ### 7. Проверить полные записи и пройти слуховой gate владельца W0 и кандидат однократно обрабатывают три полные записи. Их скорость остается диагностикой и не заменяет финальную медиану. Подготовить слепой материал A/B по коротким ответам, сменам говорящего, overlap, устойчивости соответствия голоса кластеру, словам без говорящего и малым остаточным кластерам. Включить все места, отмеченные diagnostics, и закрепленную случайную выборку совпадающих мест. `stop`: провал автоматического gate любой пары на полной записи дает `stop`. Пока владелец не записал `pass`/`fail` по всем пяти категориям, состояние равно `needs-user`. Любой подтвержденный `fail` дает `stop`; полный `pass` при медиане не ниже 30% дает `go`. Критерий завершения: три пары прошли автоматические gates, пять решений владельца сохранены в закрытом хранилище, публично сохранен только общий вердикт. ### 8. Опубликовать безопасный результат Сформировать отчет из рецептов, пинов, агрегатов, вердиктов gates, первой причины остановки и SHA-256. Сохранить ограничения четырех выходных голосовых кластеров, пяти и более слышимых голосов, non-English/out-of-domain и длинных записей. `stop`: при нарушении приватности удалить публичный артефакт из рабочей ветки и собрать его заново только из безопасных агрегатов. Критерий завершения: итог равен `go` или `stop`; закрытое хранилище самодостаточно, а публичный отчет проходит проверку приватности. ## Обязательные gates - Голосовые кластеры каждого обработанного фрагмента и полной записи точно совпадают со свежим `expected_cluster_count`. - Нормализованный текст и порядок слов побайтно совпадают с одним sidecar; нет потерянных, продублированных или переставленных слов. - Интервалы и метки проходят правила корректности и детерминированной канонической нумерации из спецификации. - Матрица Sortformer имеет форму `T x 4`, вероятности конечны и лежат в `[0, 1]`, итоговые метки принадлежат `1..4`, эффективная конфигурация совпадает с пинами. - OOM, активный swap, RSS без плато или линейный рост RSS дают `stop`. Peak RSS выше 2 ГиБ на машине с 16 ГиБ переводит опыт в `needs-user` для решения владельца. - Изменения channel stability, short turns, overlap, unmatched words, малых кластеров или mapped purity не получают нового числового порога; они добавляют места в слуховой gate владельца. Открытый диагностикой gate не прерывает primary и финальные циклы: места накапливаются до безусловной приемки шага 7. `needs-user` из-за прослушивания возможен только после достижения 30%-го порога и подготовки полного blinded-материала. ## Проверки До первого запуска модели выполнить: ```bash uv run pytest -q \ tests/test_streaming_sortformer_experiment.py \ tests/test_benchmark_experiment.py \ tests/test_speaker_diarizer.py \ tests/test_diarization.py ``` Новый модуль тестов должен покрывать отклонение `schema`, несовпадение пинов и хешей, требование свежей опоры, обезличенный вывод `--validate-only`, правило `expected_cluster_count`, точное расписание A/B, границы 5%/10%/30%, gates качества, памяти и Sortformer, переход к прослушиванию, безопасную сериализацию и остановку при первом отказе. Отдельный синтетический тест стенда C ABI проверяет размеры структур, выбор CPU и эффективную конфигурацию без загрузки модели. `--validate-only` обязан проверить fresh-basis marker, owner approval, `expected_cluster_count` каждого фрагмента и каждой полной записи, hashes обеих recipe, effective values W0 (`provider=cpu`, `debug=True`, `min_duration_on=0.3`, `min_duration_off=0.5`, threads, clustering), runtime pins, clean local-transcriber worktree и source commit из manifest, одинаковые input/sidecar hashes, geometry/post-processing, расписание, отсутствие корней старых хранилищ и legacy ID ячеек. ## Приватность Checkout и дерево сборки NeMo-Speech.cpp, скачанные веса и новое закрытое хранилище размещаются вне рабочей копии local-transcriber. Обычная `.scratch` внутри репозитория не подходит: `.gitignore` покрывает там только `.scratch/handoffs/`. Ни один runtime/model/build artifact или закрытый вход не попадает в Git. В Git, комментариях задачи, заданиях на ревью и выводе `--validate-only` не публиковать пути, `source/recording IDs`, текст, временные интервалы, сырые строки, содержимое manifest, логи, имена участников или аудио. Публичный отчет содержит только точные рецепты, хеши, агрегаты и вердикты. Все исходные данные, sidecars, опорная разметка, сырые диагностические данные и слуховые решения остаются в новом закрытом хранилище. Хранилище и публичный отчет сохраняют `clean local-transcriber source commit`, который произвел таймеры, gates, сериализацию и назначение слов. Реализация стенда должна быть зафиксирована этим коммитом до первого запуска модели. ## Acceptance - [ ] Создан отдельный стенд с recipes `W0-FRESH` и `SORTFORMER-V2-Q8`; legacy хранилища и manifests отклоняются. - [ ] Свежая опора создана из сохраненных исходных записей и подтверждена владельцем; старые контрольные значения не наследуются. - [ ] Runtime, модель, сборка и оба рецепта закреплены и проверены до моделей. - [ ] Clean local-transcriber source commit сохранен в закрытом хранилище и публичном отчете, а `--validate-only` проверяет его до запуска модели. - [ ] Детерминированные тесты, синтетический ABI-тест, `--validate-only` и проверка приватности проходят. - [ ] Свежий W0 принят либо `stop` содержит точную причину провала базы сравнения и хеш результата. - [ ] Первичный A/B завершен и правила 5%/10% применены без дополнительных ветвей. - [ ] При продолжении выполнены ровно пять финальных циклов; сохранены median и MAD. - [ ] Каждая выполненная ячейка имеет вердикты качества, текста, памяти и Sortformer. - [ ] Каждый остановленный шаг сохраняет первую точную причину и хеш результата. - [ ] При медиане не ниже 30% выполнены три пары на полных записях и пять слуховых решений владельца. - [ ] Закрытое хранилище самодостаточно; публичный отчет содержит только безопасные агрегаты и SHA-256. - [ ] Итог равен `go` или `stop`; `needs-user` остается открытым до решения владельца. - [ ] Результат не меняет production-зависимости, профиль, CLI, config, ADR или модель по умолчанию. ## Границы - Production-интеграция, lock зависимостей, упаковка runtime и изменение ADR не входят в эту задачу. - Production-профиль, CLI, контракт конфигурации и модель по умолчанию сохраняются. - Параллельное планирование ASR/диаризации принадлежит [задаче #22](https://git.dementev.space/ddmitry/local-transcriber/issues/22). - Автоматическое включение принадлежит [задаче #23](https://git.dementev.space/ddmitry/local-transcriber/issues/23). - Joint ASR+diarization и shared-ASR-encoder исключены; ASR-sidecar используется только как quality input. - Повтор старой матрицы W/M/Q/E/C, восстановление C1 и запуски на Intel или других CPU исключены. - Результат `go` разрешает только отдельное последующее production-решение и не меняет dependencies, профиль, CLI, config или модель по умолчанию.
ddmitry added the ready-for-agent label 2026-09-01 15:05:14 +03:00
Author
Owner

Предлагаю в каталоге .scratch/slug-issue/ сделать журнал работ, который потом может пригодиться при восстановлении проделанных операций после сбоя. Подумай, как полезнее его вести

Предлагаю в каталоге .scratch/slug-issue/ сделать журнал работ, который потом может пригодиться при восстановлении проделанных операций после сбоя. Подумай, как полезнее его вести
Author
Owner

Handoff для канонического Ryzen-прогона

Этот комментарий заменяет только прежнее практическое решение не разворачивать Ryzen. Результаты и ограничения Intel-scout остаются в силе.

Точка входа

  • PR #48 со стендом и PR #49 с Intel-scout слиты в master; текущая точка входа - 28d0f37.
  • Перед запуском прочитать задачу #46 со всеми комментариями, docs/specs/2026-09-01-streaming-sortformer-cpu-experiment.md и docs/benchmarks/2026-09-01-streaming-sortformer-intel-scout.md.
  • Владелец уточнил, что Ryzen 7 8845H можно развернуть. Так как Intel-scout показал 12,69% и прошел порог продолжения 10%, рекомендация изменена: выполнить канонический Ryzen-прогон.
  • Intel-результат не подставлять вместо Ryzen primary или пяти финальных пар.

Основа и приватность

  • Сохраненные записи, ASR-sidecar, опорная разметка и числа говорящих 3/2/2 уже подготовлены и подтверждены владельцем. Повторно считать говорящих или полностью прослушивать фрагменты до измерений не нужно.
  • На Ryzen создать новое закрытое хранилище #46. Старые хранилища #41/#42 разрешено использовать только как источник байтов подготовленных записей и разметки: не читать их manifest, расписания и результаты и не принимать их за доказательства нового опыта.
  • Все входы скопировать в новое хранилище и заново проверить по SHA-256. Оно должно стать самодостаточным до удаления старых архивов.
  • Не публиковать пути, идентификаторы записей, текст, интервалы, сырые результаты, логи, имена участников или аудио. В комментарии и отчет выводить только безопасные агрегаты, gates, рецепты и SHA-256.

Выполнение

  1. Обновить чистый master, создать рабочую ветку и закрепить source commit в новом manifest.
  2. Пересобрать NeMo-Speech.cpp на целевой WSL: сохраненный Intel runtime не считать переносимым. Проверить C ABI, модель, runtime, зависимости, effective config и хеши до первого запуска.
  3. Создать и провести свежий W0 на восьми физических ядрах. Sortformer использует закрепленные четыре внутренних потока.
  4. Выполнить primary в порядке W0 -> candidate с полным runtime guard.
  5. При speedup < 10% или провале обязательного gate завершить эксперимент как stop.
  6. При speedup >= 10% и пройденных gates выполнить ровно пять финальных пар в порядке из спецификации. Медиана ниже 30% дает stop.
  7. Только при медиане не ниже 30% обработать три полные записи и подготовить blinded-материал для слуховой приемки владельцем. До этого участие владельца не требуется.
  8. Сохранить приватные доказательства в новом закрытом хранилище, опубликовать безопасный отчет, пройти независимые ревью, сделать commit и PR. Задачу #46 завершить только формальным go или stop.

Ограничения для агентов и ревью

  • Реализацию выполняют модели GPT. Claude CLI разрешен владельцем только как канал независимого ревью diff и фрагментов кода.
  • Для ревью вкуса использовать craftsman на Opus, не Fable. При недоступности Claude заменить его независимыми Codex-субагентами.
  • Раздел «Кому что» из AGENTS.md снят владельцем для этого продолжения; передать исключение ревьюерам и не считать его находкой.
  • Документы писать через writing-for-agents; перед публикацией пройти ai-text-lint и вычитать литературный русский.
## Handoff для канонического Ryzen-прогона Этот комментарий заменяет только прежнее практическое решение не разворачивать Ryzen. Результаты и ограничения Intel-scout остаются в силе. ### Точка входа - PR #48 со стендом и PR #49 с Intel-scout слиты в `master`; текущая точка входа - `28d0f37`. - Перед запуском прочитать задачу #46 со всеми комментариями, `docs/specs/2026-09-01-streaming-sortformer-cpu-experiment.md` и `docs/benchmarks/2026-09-01-streaming-sortformer-intel-scout.md`. - Владелец уточнил, что Ryzen 7 8845H можно развернуть. Так как Intel-scout показал 12,69% и прошел порог продолжения 10%, рекомендация изменена: выполнить канонический Ryzen-прогон. - Intel-результат не подставлять вместо Ryzen primary или пяти финальных пар. ### Основа и приватность - Сохраненные записи, ASR-sidecar, опорная разметка и числа говорящих `3/2/2` уже подготовлены и подтверждены владельцем. Повторно считать говорящих или полностью прослушивать фрагменты до измерений не нужно. - На Ryzen создать новое закрытое хранилище #46. Старые хранилища #41/#42 разрешено использовать только как источник байтов подготовленных записей и разметки: не читать их manifest, расписания и результаты и не принимать их за доказательства нового опыта. - Все входы скопировать в новое хранилище и заново проверить по SHA-256. Оно должно стать самодостаточным до удаления старых архивов. - Не публиковать пути, идентификаторы записей, текст, интервалы, сырые результаты, логи, имена участников или аудио. В комментарии и отчет выводить только безопасные агрегаты, gates, рецепты и SHA-256. ### Выполнение 1. Обновить чистый `master`, создать рабочую ветку и закрепить source commit в новом manifest. 2. Пересобрать NeMo-Speech.cpp на целевой WSL: сохраненный Intel runtime не считать переносимым. Проверить C ABI, модель, runtime, зависимости, effective config и хеши до первого запуска. 3. Создать и провести свежий W0 на восьми физических ядрах. Sortformer использует закрепленные четыре внутренних потока. 4. Выполнить primary в порядке `W0 -> candidate` с полным runtime guard. 5. При `speedup < 10%` или провале обязательного gate завершить эксперимент как `stop`. 6. При `speedup >= 10%` и пройденных gates выполнить ровно пять финальных пар в порядке из спецификации. Медиана ниже 30% дает `stop`. 7. Только при медиане не ниже 30% обработать три полные записи и подготовить blinded-материал для слуховой приемки владельцем. До этого участие владельца не требуется. 8. Сохранить приватные доказательства в новом закрытом хранилище, опубликовать безопасный отчет, пройти независимые ревью, сделать commit и PR. Задачу #46 завершить только формальным `go` или `stop`. ### Ограничения для агентов и ревью - Реализацию выполняют модели GPT. Claude CLI разрешен владельцем только как канал независимого ревью diff и фрагментов кода. - Для ревью вкуса использовать craftsman на Opus, не Fable. При недоступности Claude заменить его независимыми Codex-субагентами. - Раздел «Кому что» из `AGENTS.md` снят владельцем для этого продолжения; передать исключение ревьюерам и не считать его находкой. - Документы писать через `writing-for-agents`; перед публикацией пройти `ai-text-lint` и вычитать литературный русский.
Author
Owner

Проверил закрытое хранилище и достроил post-processing из готовых JSON. Нового
инференса не было.

1. Откуда взялись 2 / 2 / 3

Это те же три записи и те же 300-секундные области, что давали историческое
3 / 2 / 2. Число голосов не уточнялось. Изменился порядок записей.

Исторически первой шла трехголосая запись без reference, затем две двухголосые
с reference. В новой основе сначала лежат две записи с reference, затем запись
без reference, поэтому порядок manifest равен 2 / 2 / 3. Первая версия новой
основы ошибочно перенесла старый список по позиции. Basis v2 исправила привязку
по SHA-256 исходной записи.

Комментарий владельца от 2026-09-01 подтверждает подготовленные записи,
sidecar, доступную разметку и числа 3 / 2 / 2. Позже владелец отдельно
подтвердил три голоса и отличное качество записи для контроля без reference.
Это подтверждение сохранено в закрытом owner-confirmation-note.md.

2. Где W0 теряет третий голос

Точно назвать человека или участок пока нельзя: у трехголосого контроля нет
независимой reference и прослушивание не проводилось.

Без повторного запуска проверено следующее:

  • source SHA-256 и выбранная область совпадают с историческим трехголосым
    контролем;
  • обе модели получили один и тот же WAV; списки из 808 слов совпадают по
    text, start и end;
  • W0 построил два interval-кластера, но все 757 назначенных им слов попали в
    один кластер; еще 51 слово осталось без говорящего;
  • Sortformer построил три кластера. После сопоставления кластеров по максимуму
    временного перекрытия его дополнительный кластер содержит 263 слова, для
    которых у W0 нет отдельного соответствующего кластера.

Последнее локализует материал для прослушивания, но пока остается гипотезой о
третьем голосе. Speaker IDs моделей произвольны, а overlap-сопоставление не
устанавливает личность говорящего.

3. Что означают swap-счетчики

swap_sin_bytes, swap_sout_bytes и swap_used_bytes взяты из
psutil.swap_memory() и относятся ко всей системе. W0 за свою ячейку увидел
дельты sin +503808, sout +151552 байт; Sortformer - sin +229376,
sout +163840 байт. Объем занятого swap внутри каждой ячейки не изменился.

Ноутбук работал от сети, одновременно шла обычная браузерная активность.
Сохраненные данные не позволяют отделить подкачку worker от браузера или другого
фонового процесса. RSS и RUSAGE_SELF page faults относятся к worker, но major
faults сами по себе не доказывают, что swap создавал именно он.

4. Расхождения назначений

Сырые интервалы и назначения словам обеих моделей сохранены. Теперь из них без
инференса построены приватный индекс расхождений и очередь прослушивания.

По статусу слово без говорящего:

  • 53 слова не назначены обеими моделями;
  • 20 не назначены только W0;
  • 39 не назначены только Sortformer.

После overlap-сопоставления остается еще 272 слова с разными назначенными
кластерами и 263 слова дополнительного Sortformer-кластера на трехголосом
контроле. Эти числа задают очередь проверки. Оценкой качества они пока не
являются: для первых двух контролей есть reference, для третьего ее нет.

Приватные файлы:

  • private-runner-v1/work/posthoc/word-disagreements.json;
  • private-runner-v1/work/posthoc/listening-queue.json;
  • private-runner-v1/work/posthoc/summary.json.

5. Что можно переиспользовать

Корень закрытого хранилища:

/home/dmitry/.local/share/local-transcriber/streaming-sortformer-ryzen-canonical-20260901

В basis-v2-20260904-1751/ сохранены manifest, исходные записи,
подготовленные WAV, fragment/full ASR-sidecar, две reference и явный null для
трехголосого контроля. В runtime-sortformer-20260904-173744/ и
w0-runtime-20260904-173813/ лежат runtime/model, исходники, параметры сборки,
хеши и build logs.

Фактически использованные runner, guard и тесты находятся в
private-runner-v1/. Точные команды preflight и W0 сохранены в
operator-handoff.md; Python driver диагностической Sortformer cell скопирован
в candidate-diagnostic.py. Инструкция пересчета и подготовки материала для
прослушивания: private-runner-v1/reuse-after-merge.md. Проверочный список
хешей: reuse-checksums.sha256 в корне закрытого хранилища.

Для следующей пары не нужно заново извлекать аудио, запускать ASR, строить
sidecar, размечать первые две reference или пересобирать runtime, если хеши и
ABI совпали. Нужно выбрать source commit нового опыта, заново выполнить tests,
manifest validation, artifact/ABI checks и live host guard, затем провести
новые чередующиеся W0/Sortformer cells. Старую пару нельзя считать повтором
новой серии.

Хеши и проверки

  • W0 result:
    ad32b3fe8a204e2fe6fbb6a13142e22c7e00ce9f0d816c3b0b8889fcab898e89;
  • Sortformer result:
    9ae009b3650e82c35b04728a8c6467be0bf287be97ad9d649c5432d21abef58a;
  • manifest:
    1e4d19e8bdebf2a25415384cc0cf70fa5749fdb81b2a59608bbc109a3cf406d1;
  • sha256sum -c reuse-checksums.sha256 проходит для manifest, подтверждения
    владельца, runner, guard, тестов, обоих результатов и posthoc-файлов;
  • post-processing завершился с кодом 0, повторил опубликованные агрегаты и не
    загрузил ни одну модель;
  • сам post-processing script прошел Ruff.

Из отсутствующего: независимая reference для трехголосого контроля,
полные прогоны записей, повторные пары и слуховая проверка. Для диагностической
Sortformer cell не сохранилась отдельная stdout/stderr-пара и строка внешнего
shell-вызова; сохранены выполненный Python driver, raw result и guard
snapshots. По сохраненным данным также нельзя приписать системные swap-дельты
конкретному процессу.

Проверил закрытое хранилище и достроил post-processing из готовых JSON. Нового инференса не было. ## 1. Откуда взялись 2 / 2 / 3 Это те же три записи и те же 300-секундные области, что давали историческое `3 / 2 / 2`. Число голосов не уточнялось. Изменился порядок записей. Исторически первой шла трехголосая запись без reference, затем две двухголосые с reference. В новой основе сначала лежат две записи с reference, затем запись без reference, поэтому порядок manifest равен `2 / 2 / 3`. Первая версия новой основы ошибочно перенесла старый список по позиции. Basis v2 исправила привязку по SHA-256 исходной записи. Комментарий владельца от 2026-09-01 подтверждает подготовленные записи, sidecar, доступную разметку и числа `3 / 2 / 2`. Позже владелец отдельно подтвердил три голоса и отличное качество записи для контроля без reference. Это подтверждение сохранено в закрытом `owner-confirmation-note.md`. ## 2. Где W0 теряет третий голос Точно назвать человека или участок пока нельзя: у трехголосого контроля нет независимой reference и прослушивание не проводилось. Без повторного запуска проверено следующее: - source SHA-256 и выбранная область совпадают с историческим трехголосым контролем; - обе модели получили один и тот же WAV; списки из 808 слов совпадают по `text`, `start` и `end`; - W0 построил два interval-кластера, но все 757 назначенных им слов попали в один кластер; еще 51 слово осталось без говорящего; - Sortformer построил три кластера. После сопоставления кластеров по максимуму временного перекрытия его дополнительный кластер содержит 263 слова, для которых у W0 нет отдельного соответствующего кластера. Последнее локализует материал для прослушивания, но пока остается гипотезой о третьем голосе. Speaker IDs моделей произвольны, а overlap-сопоставление не устанавливает личность говорящего. ## 3. Что означают swap-счетчики `swap_sin_bytes`, `swap_sout_bytes` и `swap_used_bytes` взяты из `psutil.swap_memory()` и относятся ко всей системе. W0 за свою ячейку увидел дельты `sin +503808`, `sout +151552` байт; Sortformer - `sin +229376`, `sout +163840` байт. Объем занятого swap внутри каждой ячейки не изменился. Ноутбук работал от сети, одновременно шла обычная браузерная активность. Сохраненные данные не позволяют отделить подкачку worker от браузера или другого фонового процесса. RSS и `RUSAGE_SELF` page faults относятся к worker, но major faults сами по себе не доказывают, что swap создавал именно он. ## 4. Расхождения назначений Сырые интервалы и назначения словам обеих моделей сохранены. Теперь из них без инференса построены приватный индекс расхождений и очередь прослушивания. По статусу `слово без говорящего`: - 53 слова не назначены обеими моделями; - 20 не назначены только W0; - 39 не назначены только Sortformer. После overlap-сопоставления остается еще 272 слова с разными назначенными кластерами и 263 слова дополнительного Sortformer-кластера на трехголосом контроле. Эти числа задают очередь проверки. Оценкой качества они пока не являются: для первых двух контролей есть reference, для третьего ее нет. Приватные файлы: - `private-runner-v1/work/posthoc/word-disagreements.json`; - `private-runner-v1/work/posthoc/listening-queue.json`; - `private-runner-v1/work/posthoc/summary.json`. ## 5. Что можно переиспользовать Корень закрытого хранилища: ```text /home/dmitry/.local/share/local-transcriber/streaming-sortformer-ryzen-canonical-20260901 ``` В `basis-v2-20260904-1751/` сохранены manifest, исходные записи, подготовленные WAV, fragment/full ASR-sidecar, две reference и явный null для трехголосого контроля. В `runtime-sortformer-20260904-173744/` и `w0-runtime-20260904-173813/` лежат runtime/model, исходники, параметры сборки, хеши и build logs. Фактически использованные runner, guard и тесты находятся в `private-runner-v1/`. Точные команды preflight и W0 сохранены в `operator-handoff.md`; Python driver диагностической Sortformer cell скопирован в `candidate-diagnostic.py`. Инструкция пересчета и подготовки материала для прослушивания: `private-runner-v1/reuse-after-merge.md`. Проверочный список хешей: `reuse-checksums.sha256` в корне закрытого хранилища. Для следующей пары не нужно заново извлекать аудио, запускать ASR, строить sidecar, размечать первые две reference или пересобирать runtime, если хеши и ABI совпали. Нужно выбрать source commit нового опыта, заново выполнить tests, manifest validation, artifact/ABI checks и live host guard, затем провести новые чередующиеся W0/Sortformer cells. Старую пару нельзя считать повтором новой серии. ## Хеши и проверки - W0 result: `ad32b3fe8a204e2fe6fbb6a13142e22c7e00ce9f0d816c3b0b8889fcab898e89`; - Sortformer result: `9ae009b3650e82c35b04728a8c6467be0bf287be97ad9d649c5432d21abef58a`; - manifest: `1e4d19e8bdebf2a25415384cc0cf70fa5749fdb81b2a59608bbc109a3cf406d1`; - `sha256sum -c reuse-checksums.sha256` проходит для manifest, подтверждения владельца, runner, guard, тестов, обоих результатов и posthoc-файлов; - post-processing завершился с кодом 0, повторил опубликованные агрегаты и не загрузил ни одну модель; - сам post-processing script прошел Ruff. Из отсутствующего: независимая reference для трехголосого контроля, полные прогоны записей, повторные пары и слуховая проверка. Для диагностической Sortformer cell не сохранилась отдельная stdout/stderr-пара и строка внешнего shell-вызова; сохранены выполненный Python driver, raw result и guard snapshots. По сохраненным данным также нельзя приписать системные swap-дельты конкретному процессу.
Sign in to join this conversation.