# ПАК-17, ФАЗА 1 — ДИЗАЙН: generic content-labels × provider-capabilities (канал B «вживую») > **Ревью-шапка оркестратора №8 (25.07, приёмка пропорциональная — инлайн-пасс исполнением, без воркфлоу; РАТИФИЦИРОВАНО `D39.26`).** **Принято В РЕДАКЦИИ §14: тело §0–13 читать ТОЛЬКО через неё** (при расхождении побеждает §14). > Пере-выведено мной, не с чужих слов: **M1 ре-деривирован независимо** — все пять дайджестов посимвольно (`c2021b1b…cab0df` = `capture.golden:6`; omitempty-хвост при пустых лейблах байт-в-байт тот же); **фантом-гард D-ссылок чист** (D2/D3/D4.1/D6.2/D12/D13.6/D14.1/D15.2/D19/D19.1/D20.2-Q1,Q2/D20.4/D22.5-22.7/D25.4/D30.1/D39.20-25 существуют и говорят заявленное); спот-чеки подтвердили §14.1 (`BriefHash` book-global в общем билдере обеих волн при пер-стадийном `stageSnap`), §14.2 (сырое `reachableModels`; `chains.default[0]` = `escalate_to` драфта), §14.3 (`escMu`-пин «перерасход ≤ 1 хоп»; `Waves.Workers` дефолт 1), §14.5.6 (`GetCheckpoint:337` → `Reserve:379` → `client:410` → `Complete:442`), §14.6.1 (golden пинит `esc_model` на ОТКАЗАВШЕМ хопе), §14.6.2 (`style_check_version` фолдится безусловно), 13 файлов вне git с `adult:`. > **Ноль опровержений §14; три добора оркестратора (в D39.26):** (A) единый лейбл «adult» схлопывает ратифицированную violence-развязку D14 п.1 (DeepSeek допустим на violence) ⇒ вокабуляр лейблов — решение владельца; (B) `reasoning:"off"` — тихий выход из аддитивного гейта (`pipeline.go:541` внешним условием) И из эхо-гейта (`echoes_when_thinking_off` только у deepseek, обобщение D19.1 п.2 в данные не доехало) ⇒ закрытие обязательно; (C) рейт-гард молча деградирует в «неограниченно» (`ratelimit.go:92-97`) при лейблованном переводчике mistral `max_concurrency:2`. > **Неточности, выводов не меняющие:** манифестное «`accept-rebill` грепом пусто» — 9 попаданий, все в `backend/docs/D15.2-*.md` (в коде/CLI действительно нет); «23 сайта `LoadPipeline`» включает строку определения. > **Скоуп-выносы приняты:** `escalation_model`=ответившая (вердикт-изменение, отдельная ратификация) · два нита общности — условно (байт-нейтральная форма + доказательство исполнением) · D22.7 паком НЕ снимается · `--accept-rebill` (D20.2-Q2) — открытая петля. **Разметка фазы 2 — в промте пака-17.** > **Статус: ДИЗАЙН-ОТЧЁТ, СТОП ПЕРЕД РАТИФИКАЦИЕЙ.** Сессия: бэкенд, 2026-07-25. Промт: `docs/BACKEND_PACK17_CHANNEL_B_SESSION_PROMPT.md` (фаза 1). Кода НЕ трогал — дерево чистое (`git status --porcelain` пусто на старте и на сдаче, кроме этого файла). Ратифицированная база: D39.25 (директива владельца: в движке нет понятия 18+) · D22.7 (L3 = политика входа) · D19 (переводчик канала B = Mistral) · D12/D2 (лестница отказов) · D4.1 (изоляция типом) · D15.2 §13-Q3 (первый рантайм-потребитель обязан назначить слой снапшота). ## §0. Эхо-блок (что я понял — ДО работы) 1. **Скоуп фазы 1:** только дизайн B1–B6 + адверсариальный селф-ревью; ни строчки кода; отчёт → СТОП → ратификация. 2. **Инвариант №1 (архитектурный):** в движке НЕТ понятия «18+/adult/канал B». Механизм generic: content-label книги (данные книги) × capability провайдера (данные models.yaml) × политика цепочки (конфиг). «adult» — ЗНАЧЕНИЕ данных. 3. **Инвариант №2:** refusal-обработка причино-агностична — детектим ФАКТ отказа (D12), причина = операторская диагностика; путь один: регенерация → эскалация по цепочке лейбла → flag+skip (D2). 4. **Инвариант №3 (жёсткая линия):** L3 не строим, не анализируем; `eval/data/refusal_corpus/*` не открывал (проверяемо: ни одного чтения оттуда). 5. **Инвариант №4:** live-вызовы с 18+ контентом — только по санкции владельца; дизайн и будущие тесты — на mock-провайдере и СИНТЕТИЧЕСКИХ безобидных фикстурах. 6. **Инвариант №5:** канал A байт-идентичен — golden без пере-капчера, парити EXACT; adult-механика включается ТОЛЬКО явной маркировкой. 7. **Инвариант №6:** capability-исключения (DeepSeek/Anthropic без adult) — СТРОКИ ДАННЫХ, не Go-литералы; гарантия «label ⊄ capabilities → провайдер не получает контент» компилируемая/тестируемая, fail-loud. 8. **Мысленный тест генеральности:** второй лейбл (archaic-register) добавляется ДАННЫМИ, без правки Go. 9. **Не делать:** L3-классификатор · live 18+ без санкции · реальный 18+ текст в репо · пар/книго/провайдер-литералы в Go · расширение скоупа без пинга. 10. **Канал вопросов:** конфликт промта с кодом → пинг оркестратору через владельца (в §5/§6 ниже — 4 таких пинга и 3 вопроса владельцу). ## §1. Метод и что верифицировано исполнением Метод — образец пака-16 (D39.24): эхо → инвентаризации → дизайн → адверсариальные линзы → ревизия отдельным слоем. 1. Онбординг: CLAUDE.md → `docs/README.md` → D-лог целиком по несущим блокам (D2/D3/D4/D12/D14/D19/D22/D39.20–D39.25) → `architecture/12-go-style-notes.md` §0 → нормы промтов §7–11. 2. Личное чтение кода (не по памяти): `internal/config/{pipeline,models,book}.go`, `internal/pipeline/{disposition,escalation,stagerun,snapshot,waverun,runner,repair,clients}.go`, `configs/models.yaml`, `configs/pipeline-c1.yaml`, `prompts/zh-ru/editor.md`. 3. Семь параллельных read-only инвентаризаций (снапшот/деньги/отчётность/транспорт/тесты/конфиги/refusal-поток), каждая с требованием `file:line` + цитата; их выводы ниже перепроверены точечно мной. 4. **Ключевой численный факт проверен МОИМ исполнением** (не агентским): brief-канон golden-книги даёт ровно записанный в фикстуре `brief_hash` — см. §7 манифест, строка M1. Это фундамент §B5. ## §2. Инвентаризация: 8 фактов, на которых стоит дизайн **Ф1. Сегодняшняя adult-поверхность в Go — ровно 6 точек, все load-time.** `config.Book.Adult` (`backend/internal/config/book.go:32`) · `config.Stage.Channel` `""|sfw|adult` (`pipeline.go:166`) · `config.Provider.Permissive` (`models.go:60`) + `Models.providerPermissive` (`models.go:271-276`) · `Pipeline.CheckAdultChannel` (`pipeline.go:336-346`) · enum-валидация канала (`pipeline.go:549-553`) · D4.1-изоляция типом (`pipeline.go:569-576`). Единственный вызов из движка — `runner.go:147`, тоже load-time. **Ф2. Рантайм-влияния на выбор модели у книги НЕТ вообще.** Выбор модели 100% статичен из конфига: `r.client(...)` вызывается только с `model ∈ {st.Model, st.EscalateTo, Gates.Repair.Model}` (`runner.go:299-323`, `stagerun.go:410`). Единственное книжное свойство, меняющее поведение рантайма, — `TargetLang`, и оно гейтит ГЕЙТЫ (`isRuTarget`/`isCJKTarget`) и выбирает ДАННЫЕ (`lang.*For`), но никогда модель. `Stage.Channel` имеет НОЛЬ рантайм-читателей. **Ф3. Единственная точка-удавка на провода — одна, и она уже есть.** `(*Runner).runAttempt` (`stagerun.go:326`) — единственный вызов `r.client(model)` (`stagerun.go:410`) и единственный `client.Complete(...)` во всём продовом коде (`stagerun.go:442`). Через неё проходят ВСЕ три класса вызовов: праймари (`stagerun.go:131`), эскалационный хоп (`escalation.go:132`), ремонт (`repair.go:389`). Failover-декоратор (`internal/llm/failover.go`) — мёртвый код: `NewFailoverClient` не имеет ни одного вызывающего вне своих тестов. Следствие: один клиент = один провайдер = одна модель, второго пути на провод нет. **Ф4. Ремонтный путь ТЕРЯЕТ стадийный канал.** `repair.go:386`: `rst := config.Stage{Name: st.Name, Role: roleRepair, Model: model}` — синтетическая стадия копирует только Name/Role/Model, `Channel` отбрасывается. Любой ассерт, ключёванный на `st.Channel`, слеп на ремонтных вызовах; ассерт на `(лейблы книги/чанка, model)` — не слеп. Это решает форму B4. **Ф5. `escalation.chains` — мёртвые данные рантайма.** Единственные потребители: валидация существования моделей (`pipeline.go:578-584`) и префлайт ключей под бюджетом (`models.go:507-518`). Исполняется ТОЛЬКО single-hop через `stage.escalate_to` (`escalation.go:90,132`). При этом `chains.adult` во всех 4 шиппинг-конфигах = **[grok-4.3], ОДИН элемент** (`configs/pipeline-c1.yaml:101`, `pipeline-arm-{glm,mistral,deepseek-pro}.yaml`). То есть «мульти-хоп по цепочке лейбла» сегодня по данным = один хоп. **Ф6. `Book.Adult` фолдится в снапшот транзитивно — и документация это ОТРИЦАЕТ (док↔код).** `Adult bool json:"adult"` внутри канона `BriefHash()` (`book.go:221,228`) → `snap.BriefHash` (`snapshot.go:338,413`) → оба волновых snapshotID → `Request.SnapshotID` в каждом `RequestHash` (`render.go:247,271-274`). А комментарий `pipeline.go:331-332` утверждает: «Adult stays wire/verdict-NEUTRAL (no snapshot layer … never a hash input)» — **неверно**. Проверено численно (§7/M1): убрать `"adult":false` из канона = `c2021b1b…` → `58883ff5…`, то есть обязательный `--resnapshot` и пере-оплата КАЖДОЙ книги. **Ф7. Байт-стабильность brief-канона — это защита денег следующего платного прогона, а не косметика.** На стенде 5 book.yaml, все с `adult: false`; `rerun2/book-dspro.yaml` и `book-mistral.yaml` по шапке «IDENTICAL to book.yaml (same book_id + all BriefHash fields, so the shared paid draft resumes at $0)». D39.20 зафиксировал $0-резюм драфта на трёх армах, а пак-16 оставил ОТКРЫТУЮ петлю (замер остатка ремонта на пост-профилактическом прогоне, D39.24 §15.1) — она поедет на следующем платном прогоне тех же книг. Сдвиг `BriefHash` = потеря $0-резюма драфта. **Ф8. Тестовая поверхность adult = 2 теста, оба load-only, исполняемого adult-пути нет.** `config_test.go:37-64` (`CheckAdultChannel`, чистые in-memory структуры) и `runner_test.go:1552-1572` (`NewRunner`+`Close`, `TranslateBook` НЕ вызывается). НЕ покрыто: ветка «escalate_to должен быть permissive» (`pipeline.go:573-575`), enum-валидация канала, `providerPermissive` напрямую, любой хоп на adult-стадии, refusal→хоп→УСПЕХ→ре-гейт (все «хоп вылечил» тесты гоняют `cjk_artifact`), `soft_refusal`→хоп, `content_filter`→хоп. Ни одна фикстура не ставит `adult: true`. Мока на Go-шве не существует вообще: подделка живёт на HTTP (`httptest`, `runner_test.go:60-76`), ответы ключуются ПО ТЕЛУ запроса (имя модели / `max_tokens` / маркер в источнике). ## §3. B1 — Схема content-labels и гранулярность ### Вариант 1 (рекомендуемый): лейблы книги + capability провайдера + реестр политик в ран-конфиге **Данные книги** (`book.yaml`): `content_labels: [