textmachine/docs/product-requirements.md

34 KiB
Raw Blame History

Реестр продуктовых требований — «что продукт обязан уметь»

Единый список требований владельца к продукту. Источники: ../START_PROMT.MD (ЖИВОЙ бриф, идеи V0V6) + владельческие находки H6H18 (architecture/09-target-architecture.md §3). Статусы сверены КОДОМ и D-логом, не прозой; последний сплошной свип — D39.139/146. При конфликте с D-логом побеждает D-лог. Правила: новую V-секцию владельца разбирает сюда оркестратор при первом касании; статус правится при лендинге пака, который его меняет; требование без носителя не оставлять.

Статусы: построено · 🔶 частично · не построено · снято (отменено владельцем ИЛИ закрыто отрицательным замером — с D-ссылкой) · 🔒 открытый вопрос владельца.

Ядро перевода

ID Требование (источник) Статус Носитель / доказательство
ПТ-1 Издательское художественное качество, победить translationese (V0 гл. цель; канон §1) 🔶 пайплайн draft→терминолог→editor→гейты→судья построен, адресная эскалация дорогой моделью есть (pipeline/escalation.go); качество добирается курсом «добор идеала» (D39.62/67, бэклог 24·65·16). Выводы-п.2 брифа (редкий узкий вызов за смыслами вне книги) — поглощён этим курсом, отдельный механизм не строится без замера
ПТ-2 ЛЮБЫЕ пары языков, в любую сторону — движок общий, пара = ДАННЫЕ (канон §2); «бэкенд только под русский» = объявленная антицель. Названные в брифе zh/en/ru/ja (V0-п.11; V4-п.5: в zh→en русский не участвует) — первые, а не полный список: продукт обязан поддержать и языки, которых в репозитории ещё нет (слово владельца 23.08) 🔶 построено только →ru: zh→ru боевая; ja→ru безопасна без правки Go, en→ru — нет (карта D39.60); не-ru target = антицель §0.1 в 09; носители: строки 81 (ja-преп) · 35 (не-CJK майнер) · 34
ПТ-3 Книга ЦЕЛИКОМ (эталон 7,78 млн симв., ~2284 раздела) 🔶 гоняли ≤10 глав; волны/потолки/ETA на сотнях глав = строка 54 (МАСШТАБ)
ПТ-4 Референсы: предыдущие части серии / чужой перевод как контекст (V0-п.1314) 🔶 серийный шаринг банка = строка 48а; импорт «оригинал+чужой перевод» = 48б (юр-сторона — 67)
ПТ-5 Неологизмы/выдуманные автором слова переводятся консистентно (V1-п.6) 🔶 банк+майнер держат термины книги; замер на вне-претрейн тексте = строка 55
ПТ-6 Структурные традиции целевого языка (короткие zh-абзацы → читаемые ru-структуры) (V1-п.4) 🔶 редакторские мандаты в пар-промптах; спец-замера структуры нет — добор идеала
ПТ-7 Слабый оригинал: подправлять ли художественно — вопрос владельца не решён (V1-п.5) 🔒 канал вопросов; сейчас пайплайн верен оригиналу

Память и консистентность

ID Требование (источник) Статус Носитель / доказательство
ПТ-8 Банк памяти на всю книгу, «крайне точный» (V0-п.78; Выводы-п.1) D39.69/75/77/78; recall банка 0.918/0.980 на холодном прогоне (D39.58). Смежный остаток H6 (running-summary): carryover закрыт замером (D39.7/8), проза-суммарайзер закрыт (D39.69), нарратив-состояние = строка 80 (гейт пилота Ф2.5)
ПТ-9 Глоссарий автосборкой: модель переводит термины с контекстом/жанром (V4-п.4, H15) терминолог пака-20 (D39.4153), KWIC-контексты, подписной цикл. Вход владельца 02.08 (D39.89): банк = центральная ценность, арбитраж перевода термов должен быть консилиумом со скорами уверенности, но не ломать связность системы термов ⇒ качество МЕХАНИЗМА проверено полигоном (research/24, принято D39.102): консилиум закрыт КЛАССОМ (равноправный совет · кросс-модельные веса · self-consistency · селекция не окупаются), остаток строки 5 (рецензент спорных кластеров) гейчен ре-пробой 74
ПТ-10 Веб-фетч для терминов без культурного контекста (V0-п.16, V4-п.4) гейт action-security = строка 70 (Ф3); до него — сид/бриф
ПТ-11 Голоса персонажей консистентны на книгу (V1-п.2; канон §1) 🔶 схема голосов построена (пак-19, D39.55/56); оси не подписаны — замер добора (строки 24 · 13б)

Деньги и телеметрия

ID Требование (источник) Статус Носитель / доказательство
ПТ-12 Низкий COGS: дешёвые модели + адресные дорогие вызовы (V0-п.3/12; канон §5) ~$0.85/ранобэ (D30.4); ре-проба исполнена и строка 74 закрыта (замер D39.86/91, закрытие D39.95); статус пере-калибровки цены — STACK.md §Примечания·Цена
ПТ-13 Телеметрия токенов/стоимости с первого вызова, БД (V0-п.25/31) SQLite request_log/леджер/смета; ⚠ леджер = нижняя граница (строка 78)
ПТ-14 Потолки бюджета и явное согласие на пере-оплату (канон §5) 🔶 reserve/settle и потолки (траты защищены). ⚠ Статус понижен с приёмкой №18 (D39.149): само ЧИСЛО согласия неполно и приблизительно — пере-прайс по текущей таблице цен исполнен (строка 181 закрыта), но: деньги банк-ролей ВХОДЯТ в число с 31.08 (строка 194 закрыта D39.185: rebill.go bankRoleCommittedUSD, пин bankrolemoney_test.go) · ось модели ПОСТРОЕНА 03.09 (D39.187): цена берётся по модели, которую стадия резолвит СЕЙЧАС, с округлением вверх — прежде считалась цена отставленной модели (решено 17.08: прайсить по текущей + округлять вверх и называть оговорку — D39.150) · принадлежность вызова поколению ВЫВОДИТСЯ, а не хранится (195). Щель терминолога = строка 38

Чувствительный контент

ID Требование (источник) Статус Носитель / доказательство
ПТ-15 18+/агрессивный контент при цензуре провайдеров, мультипровайдерность (V0-п.910) 🔶 канал B построен (пак-17), лейблы/ToS-мониторинг (строка 4); per-chunk L3-скрин = строка 8; explicit-редактор = строка 7

Управление прогоном (продукт)

ID Требование (источник) Статус Носитель / доказательство
ПТ-16 Абьюз/misuse-прескрин: дёшево, точно, до трат токенов, минимум false positive (V2-п.1, H8) строка 94; UI-контракт отказа — проект-решение D39.80 к Ф3-брифу (вывод оркестратора, не цитата брифа); форма отказа в API РЕШЕНА владельцем 16.08 (К-9 закрыт, D39.138 п.2б: rejected + ОДИН грубый код на модельный класс, без вариации между попытками — оракула подбора не давать; в каноне 0.3.0 — content_refused)
ПТ-17 Лимит размера входа настройкой (V2-п.3, H7) строка 94
ПТ-18 Стоп и продолжение пайплайна; абьюзивный прогон НЕ продолжать (V2-п.2, H10) 🔶 graceful stop по сигналу (cmd/tmctl/main.go NotifyContext) + чекпойнты/redrive; продукт-кнопки и связка с прескрином = строка 94; API-форма в контракте 14 (D39.99: stop/resume; отказ прескрина — К-9 закрыт D39.138 п.2б)
ПТ-19 Скорость: «очень быстрый перевод книги — киллерфича» (V4-п.1, H9); видимый прогресс/ETA — из Ф3-видения ридер-IDE (цветная полоса статуса), не из V4 🔶 волны параллельны по чанкам; замер скорости и ETA на целой книге = строка 54 (МАСШТАБ); пофазные счётчики draft/edit НА ГЛАВУ построены движком (D39.122 — строка 99 ЗАКРЫТА); ETA ПОКАЗЫВАТЬ — решение владельца 04.08 (D39.100/К-5), eta_seconds в спеке (0.2.0+, D39.115); оценка $/глава движком = строка 166
ПТ-44 Готовый перевод отдаётся ПОЛЬЗОВАТЕЛЮ файлом — читаемая книга (EPUB 3 + чистый txt), а не JSON-выхлоп; неполная книга выдаётся ВСЕГДА, с пометкой на титуле и маркером на месте каждой дыры (слово владельца 30.08: «дверь ВСЕГДА строит файл — отказ юзеру не отдаётся»; отказ по умолчанию остаётся операторской ручкой CLI) 🔶 Движковая половина ПОСТРОЕНА (D39.175, 8adcb86) — глагол tmctl build, пакет backend/internal/bookfile, шесть состояний честности и полоса отказов расшифрованы в glossary.md, флаги и оба конверта (tm-build-v1 у глагола build, аддитивно расширенный tm-export-v1) — в теле ноты. ⚠ испр. 05.09: дверь платформы ПОСТРОЕНАcreateExport · getExport · downloadExport (adf5e53, D39.194, контрактный минор 0.10.0 §2.23), цикл замкнут живьём: EPUB настоящего платного перевода выдан через API. Прежняя редакция после этой поправки продолжала хвостом слать «в очередь, гейт: живой прогон» — очереди больше нет. Открытое на владельце: лестница D25.1 (какая ступень даёт копию БЕЗ пометки, что печатать на титуле)

Фронт (Ф3)

ID Требование (источник) Статус Носитель / доказательство
ПТ-20 Ридер-IDE: VS Code-подобный фронт агентного перевода (V0-п.20/23) research/16 принят (D29); строки 6971; F3-brief — D29 п.3. Ф3 ОТКРЫТА 02.08 (D39.81): фронт-сессия живёт на моках; контракт API ратифицирован (D39.99; ⚠ версию канона брать ФАЙЛОМ, не этой ячейкой — норма и команда в карте README.md. Открытыми по контракту остаются хвост строки 203 и строка 241 — самопротиворечие канона на дочитанной книге.); платформа построена до читающей поверхности и денежной двери (паки P0…P13 — реестр нот; ⚠ КВОТ нет ни строки кода, и по D39.176 п.1 не будет — продуктовых квот нет, фри-тир-лимиты не проектируются; ретеншен/свип остаются инженерной гигиеной); фронт — S0S4 приняты, зона ЗАМОРОЖЕНА (D39.136 п.2 + D39.147: сначала движок и платформа до «работает и отдаёт результат», фронт накручивается на готовую функциональность)
ПТ-21 Параллельное чтение двух текстов с выравниванием по смыслам (V0-п.21); выравнивание грубое, по единицам экспорта — принято владельцем 02.08, спаны внутри текста не строятся 🔶 механизм готов: tmctl export --pairs выравнивает пары побайтно по единицам редактуры (internal/pipeline/export.go:147=aligned byte-for-byte); якорь = edit-unit, НЕ чанк (переформулировано D39.84 — финальный текст существует только на уровне юнита, ~1.9 юнита/главу, местами глава = один блок; читалка обязана это выдерживать); UI-читалка = Ф3 (этап S6)
ПТ-22 Настройки от человека: 18+, жанр и т.п. (V0-п.22) 🔶 book.yaml (labels) данными; UI = Ф3. ⚠ ЖАНР из продукта ВЫКИНУТ словом владельца 16.08 (D39.138 п.2в, строка 184: ни на чём не ветвится, влияние не измерено; снимается из промптов/брифа/контракта/формы)
ПТ-23 Веб-ПЕРВЫЙ фронт; SEO/ранжирование Google — куки, страницы-сироты, актуальные алгоритмы (V5-п.2); продукт = SaaS, не локальное приложение (решение владельца 02.08, D39.81 — натив-прицел V0-п.26 СНЯТ этим решением, вернуть только новым словом владельца); SEO только под Google, Яндекс снят; рынок глобальный; десктоп = PWA первым шагом, Tauri по явным триггерам (решения владельца 02.08, D39.84) строка 71 (Ф3-бриф); SEO вошёл в стек-дизайн ДО выбора (D39.84, требование исполнено): двухконтурный деплой — SPA app.<домен> целиком под noindex + статический публичный контур ≤3 кликов от главной (лечение страниц-сирот), frontend/docs/STACK_DECISIONS.md §4; SSR-вопрос закрыт этим решением
ПТ-24 Цикл согласования глоссария с профпереводчиком/редактором (V0-п.23) 🔶 подписной цикл терминолога в бэкенде есть; UI = Ф3. Модель цикла записана словом владельца 16.08 (D39.144 + строка 192): черновой перевод и черновой банк появляются вместе → ОДИН ОК всему банку (не пер-термная масс-подпись) → доработка → пост-ридинговые точечные правки с пере-генерацией по вхождениям (механика — после полигона)
ПТ-33 Интерфейс НЕ раскрывает конвейер: ни моделей, ни стадий, ни внутренней терминологии (решение владельца 02.08; граница пере-читана 15.08 — охранять АЛГОРИТМЫ, не минорную механику, D39.136 п.4а). ⚠ «Лестница» фаз «загрузка → … → финал → готово» — устная фраза владельца, НЕ норма продукта (его слово 16.08, D39.138: finalizing сворачивается) 🔶 инвариант D39.81; словарь статусов принят (D39.100/К-1); карта «вердикт → фраза» — приложение А компаньона (В-3), после D39.138 пишется по словарю машинных кодов Б-1. Машинный ГЕЙТ на утечку волн draft/edit — фронту при разморозке (пинг 16.08; сама утечка снята батчем 0.3.0, D39.142/143). Полоса прогресса — ОДНА монотонная доля на всю работу прогона через обе волны, считает СЕРВЕР, плюс подпись «что делается сейчас» (Progress.stage, ВТОРОЕ и последнее исключение границы — D39.163, словарь ОТКРЫТ, клиент рисует незнакомое нейтрально). ⚠ Остаток, который НЕ закрылся и назван честно: платформа продаёт ГЛАВЫ, а движку передаёт только денежный потолок — единица продажи не равна единице остановки (PD-410, архитектурный стоп; направление лечения — D39.165 §1). И полоса ПЕРЕ-ПРОХОДА гранулярности не имеет вовсе: движок анонсирует работу один раз за жизнь книги, поэтому она объявлена «одной неделимой единицей работы» (D39.166), а не выведена
ПТ-34 Пользовательский перевод НИКОГДА не попадает на публично индексируемый URL — ни витрин примеров, ни «поделиться главой», ни публичных ссылок чтения (жёсткий продуктовый запрет, решение владельца 02.08; авторское право на исходники + политика Google по масштабируемому машин-контенту действуют на весь домен) инвариант D39.84; носители: двухконтурный деплой frontend/docs/STACK_DECISIONS.md §4 (SPA под X-Robots-Tag: noindex на каждом HTML-ответе; публичный контур без контента переводов) + контракт 14 (architecture/14-api-contract/, D39.99) + платформенный бэклог П-1; правило доступа к экспорт-ссылке (срок/подпись) — батч 183 (research/28 Б-4)
ПТ-35 Лимиты «как в Claude Code» (решение владельца 04.08, D39.100): страница лимитов/использования в настройках (статус, НЕ суммы) ⚠ испр. 05.09: «запрет денег на экране» ОТОЗВАН владельцем — D39.196, эррата 05.09-а; баланс аккаунта, потолок заказа и холд выходят наружу ДЕНЬГАМИ, поля приезжают паком формы заказа. Запрещённым осталось другое и оно не отменялось: цены моделей, стоимость стадий и вызовов; стоп по потолку = статус paused + оповещение «перевод остановлен: лимиты исчерпаны» 🔶 контракт К-8 закрыт, спека несёт paused/paused_reason (0.2.0+, D39.115); ручки /v0 — платформа-раннер P4 (D39.123); статус paused по потолку ЧЕСТЕН с P6 (D39.132: exit 4/событие → paused, не failed; дневной потолок оператора различим и из платформенного шаблона убран — решение владельца 15.08); остаток: страница лимитов и оповещение на фронте (после РАЗМОРОЗКИ зоны: лендинг P7 её НЕ размораживает — D39.147) · ⚠ фразы (В-3 · К-6 · Приложение А) ДЕЛЕГИРОВАНЫ проекту словом владельца 30.08 (D39.176 п.4): подписи владельца НЕ ждём, требование ИНЖЕНЕРНОЕ — фраза не литерал ни в Go, ни в TSX, а ДАННЫЕ по машинному коду причины и локали; вместе со словарём закрывается PD-246, гейт — строка бэклога 204 · К-13 ЗАКРЫТ (D39.132 п.2а: null на проводе)
ПТ-36 Интерфейс МУЛЬТИЯЗЫЧНЫЙ, русский не хардкодится в разметке (слово владельца 10.08; язык интерфейса — отдельная ось от языков перевода) 🔶 ПОСТРОЕНО S3.7 (принят D39.129): каталог frontend/src/i18n/ru.ts (⚠ число ключей здесь НЕ держим — оно растёт каждым касанием зоны; счёт снимается командой grep -cE "^\s+'[a-z][a-zA-Z0-9.]*':" frontend/src/i18n/ru.ts) · механизм @internationalized/string · ESLint-гейт «текст местом» · стор языка с персистом · <html lang> следует выбору; содержимое — только ru; продуктовый список языков — 🔒 владелец (В-9 зоны фронта)

Качество процесса и самоулучшение

ID Требование (источник) Статус Носитель / доказательство
ПТ-25 Валидация влияния каждого решения на качество, вкл. пагубное (V1-п.3, V3-п.1; Выводы) методология полигона (exp0121 приняты, 22/23 живые; labels, судья, пре-рег); держится нормами D39.46/47
ПТ-25а Онлайн- и оффлайн-замер КАЧЕСТВА прогона (V0-п.31, H5 in-loop signal) 🔶 детерминированный $0-слой в петле построен (гейты/чекеры, телеметрия качества — слой 5 в 09); семантический in-loop сигнал = Ф2 (судья, строки 33 · 90-метрики; ⚠ испр. 05.09: 13а отсюда снята — веса рубрики сняты владельцем как неверная постановка, мерить по УЗЛАМ, D39.198 п.2)
ПТ-26 Самоулучшение пайплайна по данным больших прогонов (V3-п.2, H16) строка 90 (дизайн петли по данным судьи — при пилот-препе Ф2.5); AB-способность бэкенда — дальний хвост V1 (двойное хеджирование владельца), тем же дизайном
ПТ-27 Без-LLM анализ книги в помощь переводу/валидации (V1-п.1/п.9) майнер, $0-гейты/чекеры, экраны, KWIC — весь детерминированный слой
ПТ-28 Фронтир-модель внутри пайплайна / «судья над судьёй» (V3-п.3) отменено владельцем (V4-п.2)
ПТ-29 Полный проход книги наперёд перед переводом (V0-п.33) отклонено брифом V4-п.3 (вопросительная форма, отдельной ратификации в D-логе нет); контекст-вперёд несут сид/банк/бриф
ПТ-30 Язык промптов = язык цели/оригинала (V4-п.5) ru/en-срез закрыт отрицательно ЗАМЕРОМ (D39.61; там же оговорка «не закрыт окончательно», N=12); реопен только с новой парой по данным
ПТ-31 Локальная модель ради экономии (V0-п.6) 🔶 стенд есть (ollama/llama.cpp; ⚠ носителем доказательства прежде была названа авто-память оркестратора — её в проекте больше НЕТ, распущена по решению владельца 21.08; репо-носители — eval/local_bench.py, eval/ollama-up.sh, docs/experiments/03-local-stand.md, 06-local-extraction.md); в пайплайне не задействована = строка 90 (llama-server)
ПТ-32 Рынок/юридика: анализ рынка, право на перевод и распространение (V0-п.29, преамбула) 🔶 ToS-мониторинг (строка 4, D39.57); юр-пакет к проду = строка 67; рыночный анализ — ресёрчи 04.07

Архитектура пайплайна — идеи V6 (бриф владельца 18.08.2026)

Разобрано 23.08 (№19). V6 предлагает переделку пайплайна; статусы ниже поставлены по КОДУ, а не по докам.

ID Требование (источник) Статус Носитель / доказательство
ПТ-37 Нарезка по границам СЦЕН, а не по объёму: «граница сцены — удобная порция, где не теряется смысл; сцены можно склеить, крупная должна вмещаться в контекст» (V6-1/V6-3) не построено. Книга режется бюджетом ОЦЕНЁННЫХ ВЫХОДНЫХ токенов: пакуются целые абзацы, при переполнении спуск до границ предложений, предложение не разрывается (backend/internal/chunk/chunker.go:324-330=prefer paragraph boundaries). Сцены как семантической единицы нет; ближайшее — «инерция сцены» A5, где границей сцены считается граница ГЛАВЫ (backend/internal/pipeline/wave.go:72=a new chapter is a scene change). Полигон отдельно фиксирует, что требование «не исполнено ни разу»
ПТ-38 Майнинг ВСЕХ терминов дешёвой моделью с явной JSON-схемой и КООРДИНАТАМИ вхождений (V6-1) 🔶 майнер и фокус-классификатор построены; KWIC-контексты вхождений персистятся и едут терминологу. Чего нет: ответ терминолога — не JSON, а три поля через табуляцию (backend/prompts/zh-ru/terminologist.md), офсетов/координат в нём нет вовсе. Служебная инфа о книге (нарезка по главам) построена; поиск идиом и прочего — не начат
ПТ-39 Решение по термину С ОБОСНОВАНИЕМ от дорогой модели, с контекстом первого появления (V6-2) терминолог возвращает РОВНО три поля — термин, перевод, уверенность 0100 — и уверенность явно НЕ арбитр, она только сортирует лист ревью. Обоснования нет ни в промпте, ни в парсере. ⚠ Формат его примет аддитивно: поле Note в схеме сида существует (backend/internal/seed/seed.go:81=Note string ), то есть строить надо ПРОИЗВОДИТЕЛЯ, а не формат — тот же паттерн, что у оси рода (строка 210)
ПТ-40 Раздельные правила перевода по классам сущностей — имена отдельно, магические предметы отдельно (V6-2, ПРЯМОЙ вопрос владельца «мы кстати так и делаем или нет?») 🔶 Наполовину да. Отдельный фокус-классификатор построен, со своей ролью, промптом и осью цены, и раскладывает термины по ЧЕТЫРЁМ закрытым классам name/place/title/term, где имена и топонимы транскрибируются, а титулы и реалии переводятся по смыслу (backend/prompts/zh-ru/classifier.md). Заведён 01.08, потому что черновой тип врал в 1222%. Чего нет: отдельных ВЫЗОВОВ и отдельных наборов правил на класс — терминолог получает один смешанный список; отдельного класса «магические предметы» не существует, они лежат в term вместе с материалами, веществами и классами существ. Окупается ли разделение — не мерено
ПТ-41 Литературный критик: фиксирует расхождение, НЕ предлагает решений, классифицирует проблему; МАЙНИНГ ЗАМЕЧАНИЙ как отдельный банк (V6-4) в движке роли нет. Полигон критика мерил и назвал два факта, которые дизайн обязан учесть: критик НЕ видит удалённого целого абзаца, при том что снятую частицу «не» ловит; реальный дефект в черновике удорожает критика в 14 раз. ⇒ полноту обязан ловить детерминированный гейт, а не критик
ПТ-42 Точечный edit-редактор: получает строку банка замечаний, чинит названное место, фиксы инжектятся в текст; НЕ переписывальщик (V6-5) в движке нет. Смежный механизм существует и его стоит переиспользовать: точечная пере-редактура юнитов с $0-репином незатронутых (backend/internal/pipeline/stagerun.go:88-107=POINTWISE RE-EDIT) — но она срабатывает на сдвиг БАНКА, а не на строку замечаний
ПТ-43 «Не подсовывать хорошей модели дешёвый черновой вариант» (V6-3) 🔒 вопрос владельца с ЗАМЕРЕННЫМ контр-доводом, решения нет. Замер полигона трейсом: у deepseek-v4-pro медиана 96% предложений финального текста встречается в трейсе размышления дословно ⇒ отказ от дешёвого черновика черновик НЕ убирает, а переносит его в канал размышления дорогой модели, где за него платят по цене ВЫХОДА и где он невидим и непереиспользуем. Действующая топология дешёвого черновика этим и оправдана. ⚠ Это данные полигона, НЕ ратифицированный канон; решение — за владельцем после фазы Д