textmachine/docs/archive/prompts/BACKEND_PACK17_CHANNEL_B_SESSION_PROMPT.md

28 KiB
Raw Blame History

Промт бэкенд-сессии: ПАК-17 «канал B (18+) вживую» (ДВУХФАЗНЫЙ: дизайн → ратификация → стройка)

Статус: ПАК ОТРАБОТАН ЦЕЛИКОМ И ЗАКРЫТ (дизайн D39.26 · стройка D39.27 · дельта D39.28, 25.07). ПРОМТ АРХИВНЫЙ — исполнять из него нечего. Отчёты с ревью-шапками: docs/archive/reports/PACK17_{DESIGN,CHANNEL_B_REPORT,DELTA}_2026-07-25.md (дизайн принят В РЕДАКЦИИ §14). Остаток пака — не код: ФАКТЫ ToS под accepts_labels (зона полигона, experiments/00-provider-quirks.md) · Q2 редактор и D22.7 перед первой explicit-книгой. Всё ниже — история задания.

Статус фазы 1: ВЫДАН 25.07.2026, оркестратор №7. Цель: 18+ контент (уровни 12) идёт через волновой стек по adult-каналу — permissive-провайдеры, refusal-обработка, механические гарантии маршрутизации. Ратифицированная база: D14 (состав канала B) · D19 (Mistral = переводчик канала B; register-оговорка эха D19.1; судьи 18+ п.6: Gemini fail-closed на эротике, Grok первичный) · D22 (развязки 18+/эха; L3-спека D22.7) · D4 (adult-цепочка = permissive-провайдеры; уже в конфигах: escalation.chains.adult: [grok-4.3]). Эмпирика полигона: experiments/10-explicit-benchmark (violence) · 11-erotica-benchmark.

Инварианты — «РОВНО ТАК» (ратифицировано; конфликт с кодом/доками → пинг оркестратору через владельца, НЕ интерпретация)

  • В ДВИЖКЕ НЕТ ПОНЯТИЯ «18+» (директива владельца 25.07 — архитектурная). Движок несёт только GENERIC-механизм: content-label книги/глав (данные книги) × capability провайдера (данные models.yaml) × выбор цепочки (конфиг). «adult» — ЗНАЧЕНИЕ данных; ни один Go-идентификатор/ветка не именуется adult/18+/каналом B. Тот же механизм обязан нести будущие лейблы без правки Go — мысленный тест: archaic-register (D19.1-эхо grok на архаичном zh — та же фигура «свойство контента × способность модели»). Проактивный роутинг по лейблу — не оптимизация, а ToS-гигиена: провайдер без способности не должен ПОЛУЧИТЬ такой контент, независимо от того, откажет ли.
  • Refusal-обработка — GENERIC и причино-агностичная: D12-таксономия детектит ФАКТ отказа (hard/soft), не причину; отказ по эротике/политике/чему угодно идёт ОДНИМ путём (регенерация → эскалация по цепочке лейбла → flag+skip, D2 — мусор не течёт в TM/экспорт). Причина отказа — только операторская диагностика. Параметризуется ПОЛИТИКА ЦЕПОЧКИ (конфиг), не код. Существующая таксономия не переписывается.
  • 18+ уровень 3 — жёсткая линия: НЕ обрабатывать, НЕ анализировать, классификатор L3 в этом паке НЕ строить (спека D22.7 ждёт решений владельца по валидации). eval/data/refusal_corpus/* НЕ открывать. L3 — политика ВХОДА (человеческий уровень), не механизм движка.
  • Live-вызовы с 18+ контентом — ТОЛЬКО по явной санкции владельца с его корпусом. Пак строится и тестируется на mock-провайдере + СИНТЕТИЧЕСКИХ безобидных фикстурах (маркер-прокси, не реальная эротика); книга и производные вне git.
  • Capability-исключения — ДАННЫМИ: DeepSeek без adult-capability (ToS, стратревью 09.07), Anthropic без 18+ — строки в models.yaml, не Go-литералы имён; гарантия «label ⊄ capabilities → провайдер не получает контент» — компилируемая/тестируемая, fail-loud.
  • Байт-точность no-adult пути: канал A (обычные книги) байт-идентичен — golden без пере-капчера; парити EXACT; adult-механика активируется только явной маркировкой.
  • Ключи: xAI единый data-sharing, off перед продом (D27) — операционная петля владельца, в пак не тащить.

Отправные точки в код (сверь САМ — код первичен, это entry-points)

escalation.chains.adult в шиппинг-конфигах и его валидация · channel-aware фильтр цепочек заявлен зоной раннера в комменте pipeline-c1.yaml (НЕ построен) · refusal-классы internal/pipeline/disposition.go + internal/lang/data/refusal.txt · провайдер-модель internal/config/models.yaml+models.go (есть ли слот под permissive-флаг — инвентаризуй) · волновой драйвер waverun/stagerun (где стадия выбирает модель/цепочку).

ФАЗА 1 — ДИЗАЙН ИСПОЛНЕНА И ЗАКРЫТА (D39.26; ниже — история задания, пере-делывать НЕЧЕГО; работа идёт по §«ФАЗА 2»)

Каждый пункт был «реши сам и аргументируй»; советы = приоры, опровергаются аргументом/замером.

  • B1. Схема content-labels и гранулярность. Формат лейблов (данные книги: book.yaml/brief) и capabilities (models.yaml); книга / глава / чанк; кто маркирует в v1. Приор: v1 = ручная маркировка владельцем на уровне книги или глав; значение v1 — одно («adult»), но СХЕМА generic (множество лейблов); ПОЛИТИКА лейбла — тоже generic: route-to-chain (adult → permissive-цепочка) ИЛИ terminal (не обрабатывать вовсе; будущее значение «prohibited» = данные, движок значения не знает); авто-детекция = НЕ этот пак (упирается в L3-спеку). Дизайн проверь мысленным тестом archaic-register: второй лейбл добавляется данными?
  • B2. Маршрутизация ролей под лейблом. Переводчик adult-контента = Mistral (D19 — ровно так). Редактор — открытый вопрос: dspro НЕЛЬЗЯ (без capability), кандидаты — mistral-large/glm/grok; предложи с аргументами (глоссарий/проза/цена; эмпирики нет — честно скажи, что выбор интерим до замера). Эскалация — цепочка лейбла (chains.adult уже в конфиге). Судья — eval-сторона, НЕ в паке (D22.6 проба-гейт у полигона).
  • B3. Refusal-политика цепочки (GENERIC). Сегодня refusal → flag+skip; спроектируй per-chain политику: отказ ЛЮБОЙ причины → следующий хоп цепочки лейбла до потолка → flag+skip; потолки/бюджет; как ложится в существующую лестницу regenerate→escalate (семантику не менять молча). Никаких «18+ отказов» как отдельного класса.
  • B4. Механическая гарантия маршрутизации. Enforcement «label ⊄ capability → не отправлять»: загрузка конфига (fail-loud на модели без способности в цепочке лейбла) + рантайм-ассерт перед вызовом. Тест обязателен обоим.
  • B5. Wire/снапшот/резюм. Channel-маркировка фолдится в снапшот (какую волну двигает)? Чекпойнты/RequestHash adult-вызовов — штатно; no-adult путь байт-идентичен; фикстуры синтетические.
  • B6. Отчётность. Канал в паспорте главы/quality-report/леджере (CostSource-атрибуция adult-вызовов) — что дёшево сейчас, что в очередь.

Приёмка фазы 1: отчёт docs/archive/reports/PACK17_DESIGN_<дата>.md — НАЧИНАЕТСЯ эхо-блоком (≤10 строк: скоуп/инварианты/не-делать); по каждому B: варианты, рекомендация, риски; адверсариальный селф-ревью (линзы: L3-линия/гардрейлы · маршрутизация-fail-loud · байт-точность канала A · деньги/резюм · общность §0). СТОП — ратификация.

ФАЗА 2 ИСПОЛНЕНА, ПРИНЯТА И ЗАЛЕНДЕНА (D39.27, 25.07) — ниже история задания; АКТИВНА ТОЛЬКО «ДЕЛЬТА» в конце файла

ДЕЛЬТА ИСПОЛНЕНА И ПРИНЯТА (D39.28, 25.07) — ПАК-17 ЗАКРЫТ ЦЕЛИКОМ; промт архивный, исполнять из него нечего

ДЕЛЬТА ПОСЛЕ ПРИЁМКИ (история задания)

Владелец выбрал ПАРУ лейблов violence / sexually-explicit (сохраняет ратифицированную развязку D14 п.1: DeepSeek запрещён только на sexually explicit, на violence допустим ⇒ violence-книга не теряет dspro-редактора). Из этого — одна обязательная правка механизма и одна операционная:

  1. «РОВНО ТАК»: третье значение action — assert-only (имя предложи сам, приор allow). Семантика: capability-инвариант применяется (каждая достижимая модель обязана принимать лейбл), маршрут НЕ меняется; chain, escalation.budget_usd > 0 и label_models для такого лейбла НЕ требуются и запрещены как бессмысленные. Причина по коду: route сегодня требует все три (иначе отказы «action=route requires chain» / «budget_usd» / «routes nothing»), terminal = не обрабатывать вовсе — чистого ассерта в enum нет, и пара без него невыразима данными, то есть механизм не проходит собственный тест «второй лейбл добавляется ДАННЫМИ». checkContentRouting уже action-агностичен (кроме terminal) — дельта мала: значение enum + ветка валидации + тесты (позитивный: книга с assert-only лейблом грузится и маршрут не двигается; негативный: модель без лейбла → громко) + строка примера в реестре шиппинг-конфига (значение синтетическое, вокабуляр в шиппинг НЕ прибивать).
  2. «РЕШИ САМ»: заполнение accepts_labels НЕ делай по памяти. Факты ToS/AUP — пер-провайдер И ПЕР-ЛЕЙБЛ (violence и sexually-explicit — разные ответы), только по первоисточникам (правило двух направлений). Пока фактов нет — оставь fail-closed, это верное состояние. Фиксация фактов — зона полигона (docs/experiments/00-provider-quirks.md), не твоя.
  3. Фикс-лист: коммент поля Stage.ReasoningMaxTokens (internal/config/pipeline.go:189-194) говорит «ignored for subset providers / reasoning-off» — после ратифицированной формы 2 (гейт независимо от off) вторая половина неверна.

Инварианты те же: golden байт-идентичен · парити EXACT · -race · сэндбокс через настоящий драйвер · ценз ^func Test исполнением · сессия не коммитит.


ФАЗА 2 — СТРОЙКА (ратифицировано D39.26; читай вместе с §14 отчёта — там file:line на каждый пункт)

Читать перед работой: §14 отчёта фазы 1 (несущее) + D39.26 в 05-decisions-log.md (что я изменил против §14 и три добора приёмки). Промт даёт РЕШЕНИЯ; код-факты вытаскивай сам, отчёт — карта.

«РОВНО ТАК» (ратифицировано; отступление = пинг оркестратору через владельца, не тихая девиация)

  1. Лейблы НЕ входят ни в один хеш. Назначенный слой снапшота (разрядка D20.2-Q3) = резолвнутая модель стадии + её wire-фолд, пер-стадийно и пер-волново (stageSnap): лейбл на редакторе двигает ТОЛЬКО edit-волну, оплаченный драфт резюмится за $0. Канон brief ЗАМОРОЖЕН — "adult":false остаётся 7-м полем, omitempty-хвост НЕ нужен; stageSnap.Escalate* сохраняют имя/тег/позицию/правило заполнения, любой фолд хопов — строго аддитивный указатель+omitempty. Провенанс лейблов — шапка отчёта, не хеш.
  2. Порядок: РЕЗОЛВ → ВАЛИДАЦИЯ → все читатели видят резолвнутое. Лейблы приходят в LoadPipeline тем же швом, что pair (доктрина «все проблемы конфига одним списком»); резолвнутые поля — yaml:"-"; «достижимое» ЛЕЙБЛ-ЗАВИСИМО (st.EscalateTo/chains.default под лейблом недостижимы); дедуп — только по цепочкам активных лейблов ИСПОЛНЯЕМОГО конфига (C2-заглушка не блокирует загрузку); резолв работает и на read-путях (export/status пере-считывают снапшот).
  3. Эскалация под лейблом = ОДИН хоп chain[0] (Q4 = B3-A): len(chain) > 1 — громкая ошибка загрузки «мульти-хоп не построен» (тихого усечения нет); escalation.budget_usd > 0 ОБЯЗАТЕЛЕН для route-лейбла (иначе гейт не может выстрелить); escMu — как сегодня (лок-на-итерацию ОТМЕНЁН: он ломает пин «перерасход ≤ 1 хоп»).
  4. Гранулярность v1 = КНИГА (аргумент гарантии: авто-скрина нет, пер-главность сводит ToS-гарантию к точности ручного чтения). labelsFor() — БЕЗ аргумента, с ассертом книго-константы; диапазоны глав НЕ обещать формой.
  5. Вокабуляр данных: книга — content_labels:, провайдер/модель — accepts_labels: (разные ключи: свойство контента ≠ разрешение получателя); пер-модельный оверрайд — *[]string, только СУЖАЕТ (nil = наследовать, указатель на пустой = «ни одного», модельный ⊆ провайдерского, load-тест на вычитание); реестр политик — УПОРЯДОЧЕННЫЙ СПИСОК (action: route|terminal), «первая политика, претендующая на стадию, выигрывает», равное притязание = громко; лейбл книги без записи в реестре = громко; эффективный список хопов — упорядоченное объединение с дедупом ПОСЛЕ резолва.
  6. Отставки — ОДНИМ диффом: permissive (громко при наличии) · adult: книги (громко ТОЛЬКО на true; false/отсутствие терпимо — ключ несут 13 файлов вне git + example/book.yaml; обязателен LoadBook-тест на все три формы) · Stage.Channel + его enum + блок изоляции D4.1 (иначе providerPermissive вечно false и выживший channel: adult = операторский тупик) · CheckAdultChannel. Go-идентификаторы — БЕЗ слова adult (тег = замороженный ключ данных). Два существующих adult-теста перепиши/удали тем же диффом.
  7. Механическая гарантия: инвариант «для книги с набором лейблов L каждая модель, которую прогон может вызвать, несёт все лейблы L». Рубеж 1 — загрузка (сообщение называет модель, провайдера и НЕДОСТАЮЩИЙ лейбл). Рубеж 2 — рантайм-ассерт в runAttempt ДО Reserve через clientFor(model, labels) (компиль-энфорс: путь на провод не может не объявить контент). Ассерт НЕ переносить до GetCheckpoint (реплей ничего не отправляет; перенос отнял бы $0-реплей). Негативный тест — на СВЕЖЕМ вызове, ассертит идентичность ОШИБКИ, не дельту spend.
  8. Отказы загрузки — за forWrite; резолв — ВСЕГДА. Книга, помеченная после оплаты, обязана остаться читаемой ($0 read-only, D20.4) — иначе единственный выход «снять лейбл» = тихий обход; на read-пути те же условия дают громкое предупреждение + флаг в шапке отчёта.
  9. internal/llm/failover.go — УДАЛИТЬ (вызывающих нет; пересылает тот же запрос другому провайдеру — ровно то, что лейбл запрещает; nil-panic-дыра D4 п.1). Тесты файла уходят с ним — объявить в цензе ^func Test ИСПОЛНЕНИЕМ. Гард-тест шва оставить: \.Complete( вне internal/llm и вне stagerun.go — пусто, с ИМЕНОВАННЫМ аллоулистом live_conformance_test.go.
  10. Реестр-пример — только route на синтетическом значении. prohibited из примеров убрать (не воспроизводить выходы будущего L3); механизм terminal построить, значение НЕ заводить; будущий L3-скрин подключается НАЗВАННЫМ пер-лейбловым хуком политики, а не через terminal. D22.7 этим паком НЕ снимается — пер-чанковый L3-скрин остаётся предусловием первой erotica-книги в проде.
  11. Отказ РЕДАКТОРА под лейблом терминален (D12 pinned: flag+skip без хопа). Refusal остаётся причино-агностичным: новых классов нет, refusal.txt не переписывается.
  12. Закрыть тихий выход reasoning:"off" на аддитивном провайдере (добор приёмки B). Сегодня гейт pipeline.go:541 гейтится внешним st.Reasoning != "off", а шиппинг-стадия edit объявляет ровно off (no-op для dspro, НО не для grok: control: effort, off_effort: none шлёт явный none) ⇒ деньги честны, а эхо-зона D19.1 п.2 («reasoning-off + плотный CJK — свойство класса, DeepSeek и ОБА grok-слага») открыта, и echoMineViolation выстрелить не может (echoes_when_thinking_off только у deepseek). Форму выбираешь сам и аргументируешь (данные: флаг у xai ⇒ off становится громким | код: аддитивный гейт над резолвнутой моделью независимо от off), закрытие — обязательно, с тестом.
  13. Рейт-гарды утверждать ПОЗИТИВНО (добор C): rateGuard() возвращает nil (= без лимита) молча, в отличие от громкого r.client; лейблованный переводчик — mistral-large-2512 с max_concurrency: 2. Тест: резолвнутая лейблованная модель получила свой гард.
  14. Тесты (все обязательны, правило 11 — гоняем, не читаем): негативный load (книга с лейблом + модель без способности) · рантайм-ассерт до резервации · сквозняк refusal→хоп→OK→ре-гейт · сквозняк «хоп тоже отказал» → flag+skip · генеральность на СИНТЕТИЧЕСКОМ значении лейбла (если движок знает слово «adult» — тест красный) · второй лейбл только данными · шиппинг-конфиги в лейблованном сценарии.
  15. Док-правки §10 отчёта (5 расхождений док↔код) — тем же паком, включая устаревшие против D30.1 комменты про «вход редактора — русский черновик».

«РЕШИ САМ И АРГУМЕНТИРУЙ»

  • Форма закрытия п.12 · где физически живут резолвнутые поля и как именно labelsFor доезжает до runAttempt · формы валидационных сообщений · отчётность B6 (шапка report/status с резолвнутыми лейблами и таблицей маршрутизации · Hops из durable-чекпойнтов · read-only агрегат SpendByModel) — состав и объём на твоё усмотрение, миграций схемы НЕ вводить, Role синтетическую под лейбл НЕ заводить (ось RequestHash = новый платный вызов).
  • Данные редактора/переводчика под лейблом НЕ прибивай сам: переводчик = mistral-large-2512 (D19, ровно так); редактор и вокабуляр лейблов ждут владельца (единый adult против violence/sexually-explicit — D14 п.1 оставляет DeepSeek допустимым на violence; кандидаты редактора только из способных, dspro запрещён на sexually-explicit по ToS, mistral отвергнут как несущий D39.20, glm-5 — одна строка данных ТОЛЬКО после сверки ToS/AUP Z.AI по первоисточнику). Строй механизм так, чтобы ответ был строкой данных; получишь его релеем.

ВЫНЕСЕНО ИЗ ПАКА (не делать)

escalation_model = ОТВЕТИВШАЯ модель (вердикт-изменение: golden пинит esc_model на отказавшем хопе ⇒ отдельная ратификация с санкционированным пере-капчером) · --accept-rebill (D20.2-Q2, открытая петля) · полный обход цепочки · авто-детекция лейблов · L3-классификатор · судья 18+ (eval-сторона).

Хвосты общности из петель — УСЛОВНО: Detail-строки чекеров из данных · множитель ×2 lintTimeUnits (checkers.go:174) → ключ данных. Берутся ТОЛЬКО в байт-нейтральной форме (данные в пар-конфиге, фолд лишь при отличии от дефолта) с доказательством ИСПОЛНЕНИЕМ (выход чекеров байт-идентичен до/после над корпусом); иначе CheapGateVersion/pack.Version() двигают снапшот стендовых книг и убивают $0-резюм драфта под замер остатка пака-16 — тогда отложи и скажи явно. Молча bump-нуть версию нельзя, молча не bump-нуть — тоже.

Инварианты фазы: golden байт-идентичен без пере-капчера · парити EXACT · -race · сэндбокс-репродукции через настоящий драйвер (правило 11: mock-провайдер, сквозные сценарии — refusal-каскад, реджект неспособной модели, маршрутизация) · дифф ^func Test ИСПОЛНЕНИЕМ, не памятью · заявление = команда (приёмка ре-ранит манифест) · самопроверка ревью исполнением своего кода и результатов · сессия НЕ коммитит, git mv декларировать.

НЕ делать

L3-классификатор · live 18+ вызовы без санкции · реальный 18+ текст в репо/фикстурах · копирование GPL/AGPL · пар/книго-литералы и провайдер-литералы в Go · расширение скоупа без пинга.

Приёмка (мандат 12.07 + нормы 711)

Фаза 1 — СТОП после отчёта. Фаза 2 — отчёт docs/archive/reports/PACK17_CHANNEL_B_REPORT_<дата>.md; сессия НЕ коммитит; git mv декларировать.