textmachine/docs/architecture/13-tech-debt-anchors.md

207 lines
59 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Якоря техдолга — справочник к строкам бэклога (НЕ трекер)
> **Единственный трекер — таблица «Бэклог» в `../PROGRESS.md`.** Этот файл — справочные file:line-якоря и скоуп-заметки к её строкам (родился как пост-сверка свипа D39.66, 01.08.2026; вынесен из архива решением владельца — содержимое ЖИВОЕ). Актуализируется лендингами паков, которые трогают эти строки; исполненный пункт помечать ссылкой на D-номер, не удалять.
**Метод:** 4 адверсариальных верификатора (author≠reviewer к свипу) против backend-кода и D-лога; вердикты CONFIRMED_LOST / ALREADY_BUILT / ALREADY_CLOSED / RESCOPE, evidence обязателен. **Итог: 23 пункта — 20 CONFIRMED_LOST · 3 RESCOPE · 0 ALREADY_CLOSED (передумываний не найдено).** RESCOPE вправлены в бэклог тем же лендингом (строки 81/73/49). file:line-якоря ниже — вход для пакета-чекеров (строка 25) и дизайн-пака арки (73).
## Срез: строки 81/83/85 + инфра-дописки
### [RESCOPE] Строка 81 — ja-преп B6-ja: Поливанов-валидатор + kana-омограф POS/known-word гейтинг (D17.1) + чек-лист kana-алиасов сида (D16.4)
Два компонента реально отсутствуют: (1) Поливанов-валидатор — backend/internal/store/migrate.go:186 «translit_policy … field only in v1; validator = Phase 2» и :194 «ruby_reading … bridge to Polivanov dst validation, B6 Phase 2 — NOT a dst»; grep polivanov/Поливанов по backend/*.go даёт только значения конфига в тестах/примерах и комментарий backend/internal/config/book.go:50 — валидирующего кода нет. (2) kana-омограф гейтинг — backend/internal/membank/memory.go:10481051: «KANA and HAN are deliberately NOT boundary-checked … their ≥4 precision is deferred to the kana-precision measurement + the B6 tokenizer»; подтверждено D-логом (05-decisions-log.md:214: митигация kana-омографов → «скоуп B6»). НО третий компонент УЖЕ ПОСТРОЕН: чек-лист kana-алиасов сида существует — backend/README.md:38 «## Подготовка ja-книги (чек-лист сида)» с пунктом «Kana-написания имён = matchable … внеси в aliases: руками — иначе „тихо пусто"», а сам механизм D16.4 (ruby-чтение → авто-алиас ручного термина с громким скипом омофонной коллизии) реализован: backend/internal/pipeline/seeding.go:4350 (membank.AttachRubyAliasesToManual) — это ровно интерим-фикс из D16 п.4 (05-decisions-log.md:203).
**Фикс/скоуп:** Сузить строку 81 до двух реально отложенных работ: «Поливанов-валидатор (translit_policy Phase 2, store/migrate.go:186/194) + kana-омограф POS/known-word гейтинг / B6-токенизатор (memory.go:1048)»; компонент «чек-лист kana-алиасов сида (D16.4)» пометить built (backend/README.md:38 + seeding.go:47) — в чек-листе остаётся лишь Ф2-хвост «двойные чтения (強敵→とも) полная дизамбигуация», который и так под B6.
### [CONFIRMED_LOST] Строка 83 — F4: бэкап + integrity_check SQLite перед платным прогоном (VACUUM INTO)
grep -rni 'VACUUM|integrity_check|backup' по backend/cmd/tmctl/ и backend/internal/store/ — 0 вхождений; расширенный grep по всему backend/ — тоже 0. Подкоманды tmctl (backend/cmd/tmctl/main.go:7383) — только translate|report|status|export|redrive|seed-lint, команды бэкапа нет; в internal/store/ (chunkstatus.go, glossary.go, jobs.go, ledger.go, migrate.go, requestlog.go, ruby.go, store.go, voice.go) нет ни файла, ни функции бэкапа/integrity-проверки. SPOF из 06-реестра F4 реально ничем не закрыт.
**Фикс/скоуп:** Не требуется — занесено правильно (малый пак с 67/78, до МАСШТАБА).
### [CONFIRMED_LOST] Строка 85 — пилот-преп добор: Bertalign GOLD-пары (D29.2в) · R2 shadow (D25.2) · exp08 v3 (D21.8)
Bertalign: grep -rni bertalign по eval/ и backend/ — 0 вхождений (нет ни кода, ни данных). exp08 v3: в docs/experiments/ существует только 08-cost-model-v2.md; его шапка (строка 3) прямо говорит «Пере-съём заказан как exp08 v3 (D21.8 … D25.8 …)» — т.е. заказан, не исполнен; в eval/ есть только cost_model_v2.py (v3-скрипта нет). Подтверждается и D-логом: 05-decisions-log.md:261 «→ exp08 v3 … до фиксации budget_usd-дефолтов Ф2» — висящее поручение, и 02-mvp-plan.md:34 «пере-съём exp08 v3» как открытый.
**Фикс/скоуп:** Не требуется — занесено правильно (пилот-преп-промт, Ф2.5); дельта уже вписана в docs/POLYGON_PACKAGE4_SESSION_PROMPT.md:4.
### [CONFIRMED_LOST] Дописка к строке 59 — GLM context-overflow гард (finish=model_context_window_exceeded)
backend/internal/llm/provider_openai.go:166171: normalizeOpenAIFinish схлопывает только content_filter-композит и sensitive; «EVERY other value — network_error, model_context_window_exceeded … passes through RAW». Тест фиксирует это как осознанный дефер: backend/internal/llm/pack12_transport_test.go:190 «model_context_window_exceeded … raw (deferred GLM-overflow item)». Ниже по потоку гарда тоже нет: classify() (backend/internal/pipeline/disposition.go:201246) знает ветки decodeErrorFinish/content_filter/refusal/length — model_context_window_exceeded не матчится ни одной: пустой выход упадёт в FlagEmpty («retryable — thinking usually ate the entire budget», строки 230233) — платный ретрай, обречённый при overflow; непустой выход пройдёт как reasonOK (строка 245) — усечённый по контексту текст принят как годный.
**Фикс/скоуп:** Не требуется — занесено правильно (NOT-do пака-12 без решения, полигон-пакет до МАСШТАБА).
### [CONFIRMED_LOST] Дописка к строке 53 — внутрифайловый дубль ключа pair-файла → громкая ошибка (PACK15 §Внутрифайловый)
backend/internal/lang/langpack.go:824 (parseCategoryRows): `cats[f[0]][f[1]] = val` — повторный ключ ВНУТРИ одного файла молча перезаписывает предыдущий (last-wins), без проверки дубля. Громкая коллизия есть только на стыке уже слитого состояния и следующего источника: unionStringMap (langpack.go:466474, «key … is already defined … and the overlay redefines it») — но внутрифайловые дубли схлопываются в parseCategoryRows ДО того, как merge их увидит. Ровно так это и зафиксировано открытым в отчёте: docs/archive/reports/PACK15_STRUCTURE_REPORT_2026-07-25.md:274276 «Дубль ключа ВНУТРИ одного pair-файла всё ещё тихо разрешается „последний выигрывает" … фикс — кандидат следующего пака». Теста на внутрифайловый дубль в langpack_test.go нет (grep duplicate/дубл/already defined — 0).
**Фикс/скоуп:** Не требуется — занесено правильно (мелкие хвосты качества одним паком).
### [CONFIRMED_LOST] Дописка к строке 11 — судьба v1.1 quote-absorption при флипе coverage-гейта (D12-Q1)
Go-гейт стоит на v1 без поглощения кавычек: backend/internal/checks/coverage.go:39 `CoverageGateVersion = "coverage-v1-naive-split-lower-bound"`; grep quote/кавыч/absor/поглощ по coverage.go — 0 вхождений. Python-оракул тоже: eval/refusal_bench.py split_sentences (строка 81) без absorption-логики (grep absorb/quote — 0 содержательных попаданий). Дефер задокументирован в обе стороны: eval/coverage_precision.py:1416 «naive sentence segmentation can undercount RU sentences vs a CJK source (quote-absorbing §3.7 is deferred to v1.1)» и D-лог 05-decisions-log.md:20 (D12 Q1) «§3.7 „поглощение кавычек" → v1.1 (координированно)». Гейт при этом выключен (шапка coverage.go: «opt-in (gates.coverage.enabled)») — решение о судьбе v1.1 реально висит на флипе.
**Фикс/скоуп:** Не требуется — занесено правильно (решение владельца при флипе, Python-first лок-степ).
### [CONFIRMED_LOST] Дописка к строке 33 — включить sanitizer в pipeline-c2 при оживлении (D33.4б)
grep sanitiz по backend/configs/pipeline-c2.yaml — 0 вхождений (exit 1), при том что секцию `sanitizer:` несут pipeline-c1.yaml:87 и все три arm-конфига (pipeline-arm-mistral.yaml:47, pipeline-arm-glm.yaml:50, pipeline-arm-deepseek-pro.yaml:51). C2 — спящий скелет (pipeline-c2.yaml:14: «Фаза 0 фиксирует СХЕМУ … исполнение fan-out/селекции — механика раннера Фазы 2»), поэтому отсутствие сейчас безвредно, но при оживлении C2 без правки конфига финал пойдёт без санитайзера — строка корректно держит это как условие оживления. Нюанс цитаты: «D33.4б» как секции в 05-decisions-log.md нет (есть D33/D33.1, строки 409/422; нотация D33.4a встречается в research/18-quality-levers.md:213) — на вердикт не влияет.
**Фикс/скоуп:** Не требуется по существу; опционально при док-пассе поправить ссылку «D33.4б» на фактический носитель решения (серия D33.x в теле D33, 05-decisions-log.md:409+).
**Сводка среза:** Срез 81/83/85 + дописки 11/33/53/59 D39.66: 6 из 7 пунктов CONFIRMED_LOST — занесены правильно и живы. F4-бэкап (83): 0 вхождений VACUUM/integrity_check/backup во всём backend/, tmctl без такой подкоманды (main.go:73-83). Bertalign+exp08 v3 (85): bertalign 0 вхождений в eval/ и backend/, v3 «заказан» шапкой 08-cost-model-v2.md:3 и не исполнен. GLM-overflow (59): finish проходит RAW (provider_openai.go:166-171, тест «deferred GLM-overflow item»), classify() без ветки — пустой выход = ложно-retryable FlagEmpty, непустой = ложный OK. Внутрифайловый дубль (53): langpack.go:824 молчаливый last-wins, громкость только base↔overlay (langpack.go:466-474), открытость подтверждена PACK15-отчётом:274. Quote-absorption (11): coverage.go:39 = v1-naive, оба слоя (Go+refusal_bench.py) без поглощения, дефер в v1.1 задокументирован. Sanitizer в c2 (33): 0 вхождений в pipeline-c2.yaml при наличии в c1:87 и трёх arm-конфигах. ЕДИНСТВЕННЫЙ RESCOPE — строка 81: Поливанов-валидатор (migrate.go:186/194 «Phase 2») и kana-омограф гейтинг (memory.go:1048-1051 deferred) реально отсутствуют, но третий компонент «чек-лист kana-алиасов сида (D16.4)» уже построен — чек-лист написан (backend/README.md:38) и механизм авто-алиасов реализован (seeding.go:43-50, AttachRubyAliasesToManual); строку сузить до валидатора+гейтинга.
## Срез: строки 80/82/84 + кандидаты 73
### [CONFIRMED_LOST] Строка 80: резюме-слой памяти (глава→арка→книга) + fact-gate
В backend/internal/ резюме-механизма НЕТ: grep summary/резюме даёт только несвязанное — RedriveSummary (pipeline/status.go:592-593, план redrive), SanitizerResult.Summary() (checks/sanitizer.go:165-167, текст флага), детектор ХВОСТОВОГО edit-summary модели (sanitizer.go:90), коммент-плейсхолдер «approved-glossary+summary+series-bible» в pipeline/snapshot.go:391 при том, что memoryVersion() материализует ТОЛЬКО frozen APPROVED glossary rows (snapshot.go:179-189); в схеме store/migrate.go нет таблицы/колонки резюме (строка 18 — лишь коммент о payload снапшота). Не закрыт решением: 05-decisions-log.md:373 (D30.8 п.8) — «слой авто-памяти/состояния (Annotator, межглавные резюме…) — Ф2, связка с пилотом Ф2.5 зафиксирована» — отложено, не отменено; в списке «ЗАКРЫТО ЯВНО» D39.66 его нет.
**Фикс/скоуп:** Строка верна как есть: дизайн-пак 73 обязан дать диспозицию «строить в Ф2.5 или закрыть с обоснованием».
### [CONFIRMED_LOST] Строка 82: морфо-гейт РОДА (C3, глагол прош. вр. при gender=hidden)
В checks/*.go НОЛЬ упоминаний gender (grep gender по backend/internal/checks/ пуст); checks/sanitizer.go:83 и :429 прямо документируют «NOT offline-detectable without a morphology/dictionary pass (Ф2) — left silent»; pymorphy в бэкенде существует только в комментах ОТБРОШЕННОГО pymorphy3-подканала лемматизатора майнера (miner/miner.go:18-23, дефолт B). Gender в банке хранится как TEXT «male|female|hidden|''» (store/migrate.go:183; membank/memory.go:140); hidden даёт лишь ИНЪЕКЦИЮ-мандат избегать род-маркирующих конструкций (memory.go:810-823, GenderHidden-текст), а ДЕТЕКТОРА нарушения нет — membank.SpoilerLeaks проверяет только появление dst-поверхности до окна (mempostcheck.go:205-224), не род глагола. Отложенность зафиксирована 06-memory-risk-registry.md:105 («Отложено в v1.1/Фазу 2 … морфо-гейт глагольного рода (C3)») — жива, не закрыта.
**Фикс/скоуп:** Строка верна как есть (python-сайдкар/pymorphy, связка с морфопроходом Decl из 73).
### [CONFIRMED_LOST] Строка 84: канон D39.21 «generic „гу" = средний род» без носителя
Канон ратифицирован (05-decisions-log.md:7, карта: «D39.21 = … generic-«гу» СРЕДНИЙ род, именные — по-термово из банка»), носителя в коде НЕТ: (1) enum рендера без neuter — genderConstraintNote принимает только male/m, female/f, hidden, любое иное значение МОЛЧА даёт "" (membank/memory.go:815-823); (2) инъекционные тексты пары — только GenderMale/GenderFemale/GenderHidden (lang/embedded.go:395-397,449-454), ключа gender_neuter нет; (3) схема БД комментирована «male|female|hidden|''» (store/migrate.go:183); (4) в backend/prompts/ и internal/ grep «средн|neuter» = 0 хитов; (5) схема сида ВЫРАЗИМА синтаксически (seed.go:68 Gender — свободная yaml-строка), но `gender: neuter` был бы ТИХИМ no-op: memseed.go:98 копирует без валидации, SeedLint (memseed.go:480) род не проверяет. Альтернативный носитель decl.Invariant существует (memory.go:128,151,311; seed.go:85), но несёт лишь несклоняемость формы, не род для согласования глагола/прилагательных.
**Фикс/скоуп:** Строка верна; уточнение в тело: (а) сегодня `gender: neuter` в сиде — ТИХИЙ no-op без линта, т.е. дыра хуже «невыразимо» — при стройке носителя добавить и seed-lint-отбраковку неизвестных значений рода; (б) «decl.invariant достаточно» закрывает только несклоняемость, не согласование — фиксировать это в формулировке альтернативы.
### [RESCOPE] Кандидат 73: ranked-set (инъективность рангов)
Половина УЖЕ ПОСТРОЕНА: инъективность dst (B2, «два исходных → один целевой») реализована как membank.InjectivityCollisions (membank/memory.go:1101-1126: группировка approved-строк по нормализованному dst, ≥2 разных src = коллизия) и вызывается на загрузке как warning-only диагностика (pipeline/seeding.go:157). НЕ построены две другие части исходного обязательства (04-unhappy-paths.md:19: «тип ranked-set + проверка инъективности … и порядка ступеней»): типа ranked-set нет (type — свободный текст «name|term|title|…», migrate.go:181; grep ranked-set/tier/ступен по backend = 0 кодовых хитов) и проверки ПОРЯДКА ступеней при перечислениях нет.
**Фикс/скоуп:** Переформулировать кандидата в 73: «ranked-set: тип записи + проверка порядка ступеней (инъективность dst УЖЕ есть — InjectivityCollisions, warning-only на seeding.go:157; решить, нужен ли hard-режим для ranked-set-строк)».
### [CONFIRMED_LOST] Кандидат 73: STITCH-ретирование инъекции отработанных термов
Механизма подавления инъекции терма, стабильно отработанного N чанков подряд (research/15-voice-and-state.md:204), в membank НЕТ: бюджет Select ранжирует по priorityRank = confirmed/exact/sticky (memory.go:645-661) без какого-либо счётчика «отработанности»; sticky A5 — ИНЕРЦИЯ в противоположную сторону (наследование в следующий чанк, memory.go:500-505); grep retire/streak/consecutive/отработ по internal/ даёт только loopguard (повтор сегментов) и retired-конфиг-флаги — не о том. Post-check (mempostcheck.go) следит за промахами, но не влияет на подачу.
**Фикс/скоуп:** Кандидат занесён правильно; в дизайн-паке учесть, что счётная база для «N чанков подряд без промаха» уже есть в retrieval_state/post-check — стройка сводится к политике селекции.
### [CONFIRMED_LOST] Кандидат 73: эмбеддинг-второй-эшелон A7/D2 (дать диспозицию)
В ДВИЖКЕ ретривала по эмбеддингам нет: единственные следы — плейсхолдер-колонка `embedding_tier_used INTEGER NOT NULL DEFAULT 0, -- always 0 in v1 (no embeddings on the hot path, Р3)` (store/migrate.go:248) и её протаскивание в store/glossary.go:71,305-391; miner_substrate.go:15 прямо декларирует «$0, no LLM, no embeddings»; grep cosine/vector/embedding по internal/ иных хитов не даёт. В eval бенч существует (eval/retrieval_bench.py). Реестр держит A7/D2 отложенными в Ф2 low-trust (06-memory-risk-registry.md:32,61,105) — живо, не закрыто.
**Фикс/скоуп:** Занесено правильно как «дать диспозицию» (строить low-trust Ф2-слой или явно закрыть); формулировка точна.
### [CONFIRMED_LOST] Кандидат 73: tmctl «замена термина с главы N»
Команды НЕТ: полный список tmctl = translate|report|status|export|redrive|seed-lint (cmd/tmctl/main.go:73-86); RedriveSelector выбирает только ФЛАГНУТЫЕ чанки по chapter/chunk/reason (pipeline/status.go:561-582), не «чанки с термом X». Источник кандидата — research/15-voice-and-state.md:200: одна команда ставит until_ch=N старой записи и since_ch=N новой. При этом СУБСТРАТ построен целиком: оконные строки в схеме (UNIQUE (book_id, src, sense, since_ch, until_ch), migrate.go:202) и $0-пере-пин при bank-only-сдвиге (pipeline/repin.go:14-36, D39.42 п.5/D39.45) — платятся только юниты, где инъекция реально изменилась.
**Фикс/скоуп:** Занесён правильно; в дизайн-паке скоупить как ТОНКУЮ CLI-обёртку над уже построенным (правка двух окон в сиде + штатный repin), не как пайплайн-работу.
### [CONFIRMED_LOST] Кандидат 86/73: feed_cap терминолога (D39.45) — «бюджет-гейт режет хвост батча»
feed_cap НЕ построен: grep feed_cap/FeedCap по backend/ = 0 (подтверждено и независимой ревью-шапкой docs/archive/reports/PACK20_BANK_BUILD_2026-07-26.md:14 «feed_cap действительно не построен (grep=0)»). Претензия строки к текущему механизму ВЕРНА и проверена кодом: бюджет проверяется ПЕРЕД каждым вызовом батча и при превышении остальные батчи остаются неконсолидированными status:auto (pipeline/terminologist.go:256-264), при этом кандидаты сортированы ЛЕКСИКОГРАФИЧЕСКИ по src (terminologist.go:191; terminology.go:212), а Batch сохраняет этот порядок (terminology.go:917-919) — т.е. гейт режет лексикографический хвост, не наименее ценное, ровно как констатирует D39.45 (лог:1119).
**Фикс/скоуп:** Занесено правильно (строка 86 + кандидат в 73); формулировка точна.
**Сводка среза:** Срез 80/82/84 + кандидаты 73/feed_cap: 6 CONFIRMED_LOST, 1 RESCOPE, 0 ALREADY_BUILT/CLOSED целиком. Строки 80 (резюме-слой: memoryVersion материализует только approved-глоссарий, snapshot.go:179-189; отложено Ф2, лог:373), 82 (морфо-гейт рода: ноль gender-хитов в checks/, sanitizer.go:83/429 явно оставляет морфологию Ф2) и 84 (neuter отсутствует в enum memory.go:815-823 и в инъекционных текстах embedded.go:395-397; `gender: neuter` в сиде — тихий no-op без линта) занесены правильно. Единственное опровержение — кандидат «ranked-set инъективность рангов»: инъективность dst УЖЕ ПОСТРОЕНА (membank.InjectivityCollisions memory.go:1101-1126, warning-only на seeding.go:157) — RESCOPE на «тип ranked-set + порядок ступеней». По tmctl-замене субстрат построен (окна since/until в схеме + $0-пере-пин repin.go) — не хватает только тонкой CLI-команды. feed_cap: не построен (grep=0), и претензия «гейт режет хвост, не наименее ценное» подтверждена кодом — батчи в лексикографическом порядке src, бюджет-стоп до вызова (terminologist.go:256-264).
## Срез: строка 25 — дефекты чекеров
### [CONFIRMED_LOST] #3 chevron-речь: детектор опознаёт только форму «Реплика», — сказал
backend/internal/checks/cheapgates.go:250-275 — chevronSpeechShape требует закрывающую » СРАЗУ с запятой (строка 263: `if j >= len(rs) || rs[j] != ','`), затем тире (270). Комментарий 248-249 прямо признаёт: «It deliberately MISSES exclamatory «Реплика!» — and unattributed «Реплика.» chevron dialogue». Сверх того, isSpokenChevronLine (checkers.go:603-619) требует глагол речи из закрытого списка speech_verb. Второго, более широкого детектора нет: voice.go:252-253 для кавычечного спана так же требует глагол речи в хвосте. Фаза-2 (D39.64) чекер не трогала — шестёрка закрыла только #11 и translitInterjections.
**Фикс/скоуп:** В пакете-чекеров: расширить attribution-join на «X!», «X?» и безатрибуционные реплики, точность судить по labels/-корпусу (порог Р4-контрактом: потолок recall записать в контракт правила). — **✅ ИСПОЛНЕНО (пакет-чекеров 02.08):** `chevronSpeechShape` — привязка = `«X», —` (запятая-джойн) ИЛИ `«X!»/«X?»/«X…» —` (sentence-final перед »); плоская цитата `«X» —` ОТВЕРГАЕТСЯ (гвоздь `TestChevronCitationNotFlagged` — «просто опциональная запятая» была первой версией, опровергнутой ревью), глагол-гейт держит точность. K4b recall 0.109→0.217, +5 tp, 0 новых fp. **Р4-потолок ~0.22 записан В КОНТРАКТ правила** (24 безатрибутивные реплики офлайн неотличимы от цитат).
### [CONFIRMED_LOST] #5 K5a-предохранитель: number_magnitude отсекает 数-префиксные магнитуды (数十万)
backend/internal/checks/cheapgates.go:508-519 — hasDigitBeforeBigMarker требует ЦИФРУ (一-九/两/0-9) до 万; 数 отсутствует в digit-классе lang/data/cjk-section.txt (digit-строки: 一二两兩三四五六七八九) и не является numeral rune вовсе, поэтому ран рвётся на «十万» и гасится. Комментарий cheapgates.go:482-483 признаёт: «It also drops bare-unit magnitudes (十万/百万) — an accepted recall trade». Нюанс: узкий DC2-проб покрывает РОВНО 数十万→«десятки тысяч» (configs/langpacks/zh-ru/dc-checkers.txt:61-63), но 数万/数百万/数千万 и другие рендеры 数十万 слепы для обоих механизмов.
**Фикс/скоуп:** Ввести «несколько»-коэффициент (数/几) как данные (cjk-section или dc-checkers), снять требование явной цифры для 数X-магнитуд; либо расширить DC2-пробы данными. — **⊘ ЗАКРЫТО (не чинить, пакет-чекеров 02.08):** единственный реальный дефект магнитуды на всём корпусе (`数十万人→«десятки тысяч»`, rerun2-mistral:2:0) УЖЕ пойман DC2 (K5b, recall 1.0). Расширение 数-коэффициента ловит **0 новых единиц** на labels ⇒ нужность = 0. На иных корпусах может понадобиться — текущая эмпирика не оправдывает.
### [CONFIRMED_LOST] #6 латиница-детектор пропускает токены с заглавной буквой (Cultivation, TM-BANK)
backend/internal/checks/checkers.go:527 — `if (rs[j] >= '0' && rs[j] <= '9') || (rs[j] >= 'A' && rs[j] <= 'Z') { reject = true }` — любая заглавная отбрасывает весь токен; 534 — флагуются только !reject. Комментарий 510-513: «flags an all-lowercase Latin token … a capital signals a proper noun/brand». «Cultivation» и «BANK» не флагуются никогда. Recovery битого сепаратора banknote.go:123-138 работает только на сплите ЧЕРНОВИКА (splitBanknote), финальный выход редактора маркер-скана не имеет.
**Фикс/скоуп:** Отдельный класс для Title-case/ALL-CAPS латиницы с allowlist имён/брендов + явный детект bankMarkerFragment в финальном тексте; корректность порога — по labels/. — **✅ ИСПОЛНЕНО (пакет-чекеров 02.08):** `lintLatinResidue` — снят reject-по-заглавной; caps/Title латиница флагуется (ловит `BANK`-фрагмент маркера + `Cultivation`), легит-бренды → per-project allowlist (case-insensitive). K2 recall 0.75→0.85, +4 tp; **измеренная precision 0.971** (1 fp «Qidian»=бренд; 1.0 лишь ЕСЛИ бренд занесён в `style_allowlist` — боевой конфиг сейчас не заносит, находка ревью-агента). Гвоздь `checkers_pack13_test.go`.
### [CONFIRMED_LOST] #7 порог minLatinResidueLen=3 (судьбу решить по labels + Р4)
backend/internal/checks/checkers.go:514 — `const minLatinResidueLen = 3` — порог по-прежнему захардкожен константой, токены ≤2 букв («ok», «ai») никогда не флагуются; никакого data-driven порога или записанного Р4-потолка в контракте правила нет (grep по minLatinResidueLen — единственный сайт).
**Фикс/скоуп:** Замерить распределение длин реальных утечек на labels/-корпусе; порог — в данные цели или зафиксировать 3 как Р4-потолок в контракте правила. — **⊘ ЗАКРЫТО (пакет-чекеров 02.08):** замер THRESHOLD=2 = **0 изменений** (recall 0.75→0.75). Гомоглиф «гy» — это MIXED-скрипт токен (1 латинская руна), не длина-порог; ловится существующим `tk.mixed` (`detectBrokenWords`, приёмка пройдена — гвоздь `TestHomoglyphDetectorAcceptance`). **3 зафиксирован как Р4-потолок** в контракте правила.
### [CONFIRMED_LOST] #10 пост-чек банка: «src сработал» = подстрочное вхождение, однознаковый 转 даёт ложные
membank/mempostcheck.go:12 — пост-чек стоит на посылке «SRC actually fired in THIS chunk»; «сработал» = Aho-Corasick ПОДСТРОКА (memory.go:532). Han-ключи намеренно НЕ проверяются на границы: memory.go:1071-1072 «KANA and HAN are deliberately NOT boundary-checked» (якорь уехал 1048→1071 после банк-пака). Односимвольный 转 попадает в автомат через allow_short (memory.go:152-154) и обходит и мин-длину, и понижение до Ambiguous: collisionProneKey ложен для Han (memory.go:88-90 `!runesAnyHan`), а allowShort гасит ветку (memory.go:653-654 `dispositionFor`). Итог: 转 внутри 转身/旋转 фиксирует «src сработал» → Confirmed-miss пост-чека. 转 живой в холодном банке: COLDRUN_REPORT_2026-07-31.md:143 «转 пришло само (freq 62, „ранг“)».
**Фикс/скоуп:** Дизамбигуация коротких Han-ключей: пер-вхождение с контекстной проверкой (не считать Confirmed-miss без границы/контекста); стыкуется с B6-токенизатором и аркой банка (строка 73). — **✅ ИСПОЛНЕНО пакетом-чекеров 02.08** ([reports/CHECKER_PACKAGE_2026-08-02.md](../archive/reports/CHECKER_PACKAGE_2026-08-02.md); D39.78): `mempostcheck.go` `singleHanKeyFired(p.Via)` — одно-руновый Han-ключ роутит dst-absent-миссы в Unverified observability, не Confirmed (мульти-руновые Han НЕ демотируются). Замер labels: K6 fp 14→6, precision 0.067→0.143, **fn=0 сохранён** (все 6 демотированных = 转 внутри глаголов; ни одного реального промаха не потеряно; ⚠ fn=0 КЛАСС-ВАКУУМЕН — в labels ноль одно-Han-позитивов, recall-цена демоции не измерена, hard-gate строки 12 на него не опираться — D39.78). Демотированный мисс несёт `PostcheckMiss.Demoted` в detail (постфикс §8). Гвозди `mempostcheck_test.go` (вкл. негатив: одно-руновый НЕ-Han остаётся Confirmed). Стеммер-путь `declinedFormPresent` (банк-пак §3) НЕ тронут. Остаточные 6 K6-fp (元石/蛊虫 плюральные формы) = сид-полнота, не код.
### [CONFIRMED_LOST] #1 K5c-супрессор гасит по всему юниту + Р2-семантика «значение» не имплементирована
Обе половины подтверждены. (а) checkers.go:411-412 — «A CORRECT rendering anywhere in the chunk (the ok-suppressor) suppresses the flag»; код 426-435: `!c.qianwanOKRE.MatchString(final)` и `strings.Contains(final, ...)` — весь чанк, не пер-вхождение; одно верное 千万 маскирует второе неверное. DC1 аналогично берёт только ПЕРВЫЙ матч (checkers.go:358 FindStringSubmatch). (б) Р2 (D39.63(1): «жёсткий флаг ТОЛЬКО за неверное ЗНАЧЕНИЕ; неконвертированная форма = мягкий счётчик») не имплементирован: lintPercentScale (checkers.go:482-506) файрит по ФОРМЕ (нет процентного слова + есть дробный кью), pct вычисляется только для сообщения, сравнения значений нет; cheapgates.go:84-89 прямо признаёт: «A correct fix compares the rendered VALUE… a design, not a patch. Left firing». Сплита hard/soft в CheapGateResult нет.
**Фикс/скоуп:** Пер-вхожденческое сопоставление (FindAllString + попарный матчинг) и имплементация Р2: сравнение значения (нужны цель-данные числительных), split жёсткий-дефект/мягкий-линт в результате чекера. — **Р2-split ИСПОЛНЕН (пакет-чекеров 02.08):** `CheapGateResult.UnitScaleHard()`={DC1 ruNum≠2n · NumberMagnitude — слово-магнитуда неверного ПОРЯДКА, ошибка значения (→HARD по находке ревью-агента)} / `UnitScaleSoft()`={DC2 гипербола-неоднозначна, PercentScale верное значение в форме-дроби}; `Total()` не тронут (голден-нейтрально). **Пер-вхожденческий супрессор — ⊘ НЕ строил:** под Р2 PercentScale стал SOFT-наблюдаемостью, локальность-window эвристична и низкоценна → Р4-потолок. HARD-value-чек 成/万 требует ru-numeral-word-данных (потолок записан в v5-блоке шапки cheapgates.go §5-A4 + отчёте; inline-записи на самих функциях НЕТ — хвост в строке 93) — §6-Q3 владельцу (строка 92).
### [CONFIRMED_LOST] #8 两 отсутствует в классе cheng_re
configs/langpacks/zh-ru/dc-checkers.txt:65 — `cheng_re ([0-9一二三四五六七八九十])成([0-9一二三四五六七八九]?)` — ни 两, ни 兩 нет ни в одном из классов, хотя тот же пак знает 两: строка 9 `cjk_numeral 两 2`, строка 41 shichen_re содержит 两. 两成 (20%) невидимо для lintPercentScale. По D39.63(3) данные-правки на этой фазе перестали быть дорогими (стендовый корпус одноразовый) — «данные, батчем» в строке 25 корректно.
**Фикс/скоуп:** Добавить 两/兩 в оба класса cheng_re батчем данных-правок (одна правка dc-checkers.txt, resnapshot по дисциплине D39.63). — **✅ ИСПОЛНЕНО как ДАННЫЕ (пакет-чекеров 02.08):** 两/兩 в оба класса cheng_re + 兩=2 в cjk_numeral (парс-полнота). **Нужность на labels = 0** — 两成 в acceptance:10:0/minirun:10:0 замаскировано супрессором #1 (там есть «процент»); правомерно как generality/consistency-фикс. 兩-traditional — §6-Q2 владельцу (0 стоимости, подтвердить или откатить).
### [CONFIRMED_LOST] Резидуал R4 пака-11: DC7 grade/role-чекер · omission-бэкстоп · DC2 word↔word дроби
Определение резидуала: PACK11_CONT_REPORT_2026-07-19.md:195-197 (DC7 grade/role; omission-бэкстоп = «лёгкий Go-ru-стеммер + лемма-матч по {dst,decl.forms,aliases}»; DC2 word↔word дроби q4a rule_b1/b2). Все три отсутствуют: grep DC7 по backend/internal — 0 совпадений (GradePrefix используется только майнером, miner_patterns.go:223 — не чекером); стеммер/лемма-матч отсутствуют — dstFormPresent (mempostcheck.go:144-154) матчит только точные whole-word формы, grep stemmer/lemma по backend даёт лишь комментарии; DC2 в коде = только два проба qianwan/shushiwan (checkers.go:417-438), word↔word-сравнения числительных нет. DC3-гендер из того же R4 корректно вынесен в строку 82 — скоуп строки 25 точен.
**Фикс/скоуп:** Строить в пакете-чекеров: DC7 (после promote 甲乙丙丁 — owner-only), omission-бэкстоп стеммером+лемма-матчем, DC2 rule_b1/b2; дизайны — план §5(б) пака-11. — **Диспозиция (пакет-чекеров 02.08):** (1) **omission-бэкстоп — ✅ УЖЕ построен** стеммером `declinedFormPresent` (лемма-матч {dst,decl.forms}); замер: сам починил 2 K6-fp (凡人/甲等); target-алиасы не заведены (сид-концерн). (2) **DC7 — на владельца (§6-Q1):** approved grade-строки ЕСТЬ (класс А/Б/В/Г), но КОЛЛИЗИЯ с draft «разряд X» — нужна канон-подпись ПРЕЖДЕ стройки (PACK11_CONT:195). (3) **DC2 word↔word — ⊘ ЗАКРЫТО:** 分之-дроби в корпусе есть (8 юнитов), но НИ ОДНОГО размеченного дефекта класса → precision/recall неизмеримы, строить вслепую против мандата; сперва разметить 分之-срез.
### [CONFIRMED_LOST] Alignment-защита рефренов: editor.md велит убирать повторы без исключения «повтор есть в оригинале»
backend/prompts/zh-ru/editor.md:6 — «Правь стиль: убирай кальки…, канцелярит, ПОВТОРЫ, неестественные конструкции» — без оговорки об авторском рефрене; тот же текст в editor-mono.md:5; editor.md:17 дополнительно велит «варьируй лексику». Требование защиты живо: 04-unhappy-paths.md:97 «alignment-защита: повтор в параллельных позициях оригинала = „не трогать“ … иначе редактор-агент убивает рефрены» и :130 п.5. Никакого детектора повторов лемм/alignment-механизма в checks/ нет.
**Фикс/скоуп:** Минимум $0: вписать в editor.md/editor-mono.md исключение «повтор, присутствующий в оригинале в параллельных позициях, сохраняй» (промпт-правка); полный механизм (детектор повторов лемм + alignment) — в пакет-чекеров. — **✅ Минимум ИСПОЛНЕН (пакет-чекеров 02.08):** editor.md + editor-mono.md несут исключение авторского рефрена (двигает боевой PromptSHA256, перекупок нет D39.63; голден на синтет-промтах не двинулся). Полный детектор повторов лемм — НЕ строил (нет размеченного класса; связка с alignment/Bertalign, строка 85).
**Сводка среза:** *(исторический след свипа D39.66 — якоря сводки НЕ актуализировались пакетом (memory.go:1048→1071, checkers.go:527/514, cheapgates.go:263,270 уехали); актуальные якоря — в evidence пунктов выше; срез исполнен D39.78.)* Адверсариальная верификация среза строки 25 (дефекты чекеров, свип D39.66): все 9 пунктов — CONFIRMED_LOST, ни один не опровергнут. Ничего из корзины II пака-21 фаза-2 не строила (D39.64 закрыла только #11 и translitInterjections): #3 — chevronSpeechShape требует ровно «X», — тире (cheapgates.go:263,270, признанные misses в комментарии); #5 — hasDigitBeforeBigMarker слеп к 数-магнитудам (数 нет в digit-классе cjk-section.txt), покрыт лишь узкий DC2-проб 数十万→«десятки тысяч»; #6 — заглавная латиница отбрасывается целиком (checkers.go:527); #7 — порог 3 захардкожен (checkers.go:514); #10 — «src сработал» = подстрока без границ для Han (memory.go:1048-1050), 转 через allow_short обходит все понижения и живой в холодном банке (COLDRUN:143); #1 — ok-супрессор DC2 чанк-уровневый (checkers.go:426-435), Р2-контракт «судить значение» (D39.63) не имплементирован (lintPercentScale файрит по форме, признано в cheapgates.go:84-89); #8 — 两 нет в cheng_re (dc-checkers.txt:65) при том, что пак его знает (строки 9, 41); R4 пака-11 — DC7/стеммер/word↔word отсутствуют в коде полностью (grep — 0 несущих сайтов); alignment-защита — editor.md:6 и editor-mono.md:5 велят убирать повторы без исключения для авторских рефренов вопреки 04-unhappy §7. Формулировки строки 25 точны, RESCOPE не требуется; нюансы (частичное DC2-покрытие 数十万, структурный мин-порог ключей, ограничивающий #10 случаями allow_short/подстрок) — в evidence соответствующих пунктов.
## Срез: строка 86 + дописки 79/41/24/74/49
### [CONFIRMED_LOST] (1) Echo-семантика дропнутого c-lite-члена (строка 86, D39.18): код сохраняет pre-c-lite семантику «эхо где угодно, вкл. дропнутых членов»
Код реально реализует pre-c-lite семантику, альтернатива не построена. backend/internal/pipeline/quality.go:216-218: «echo_draft is counted DIRECTLY from the draft rows (no c-lite per-unit re-derivation — a dropped member's own draft row already carries cjk_artifact)»; quality.go:295-318: draftEcho считается по ВСЕМ draft-stage рядам (FlagReason/FirstFlagReason == cjk_artifact), без фильтра по member-drop — т.е. эхо дропнутого c-lite-члена ВХОДИТ в метрику; backend/cmd/tmctl/render.go:308: «draft = the translator echoed (incl. dropped c-lite members)». Альтернативный путь «echo только в шипнутом тексте» в коде ОТСУТСТВУЕТ (в quality.go нет ветки, исключающей дропнутые члены из draftEcho). D-лог: 05-decisions-log.md:583 (D39.18) — «ОТКРЫТОЕ решение владельцу: сохранена pre-c-lite семантика…; альтернатива — one-line, за владельцем»; D39.66 (строка 1209) повторно числит его открытым. Решения после D39.18 не найдено (grep по голове D39.x).
**Фикс/скоуп:** Не требуется — строка 86 точна: решение реально отложено и живо, код в заявленном состоянии.
### [CONFIRMED_LOST] (2) Magnitude-кап тяжёлой CJK-утечки (строка 86, D38.3 п.4в): сейчас только strip+flag, капа >X%→drop нет
Капа в коде нет. backend/internal/checks/sanitizer.go:770 StripCosmetic — косметический стрип; backend/internal/pipeline/disposition.go:96-104 FlagSanitizerStripped — «cleaned, exported flagged, NOT dropped». detectCJKLeak (sanitizer.go:636) вообще не считает долю утечки — только собирает раны. Единственные share-пороги: disposition.go:275 cjkEchoThreshold=0.15 (это класс ЭХА → FlagCJKArtifact, не кап под-эховой утечки) и sanitizer.go:137 latinHeavyShare=0.25 (Latin-класс, не CJK). Промежуточного порога «CJK-доля >X% (X<15) drop» нет нигде в checks/ и disposition.go. D-лог: 05-decisions-log.md:530 (D38.3 п.): «альтернатива magnitude-кап (>X%→drop) НЕ реализована — нужен ли кап, за владельцем»; D39.66 повторно числит открытым.
**Фикс/скоуп:** Не требуется — строка 86 точна.
### [CONFIRMED_LOST] (3) lintNumberMagnitude без гейта по письму источника (дописка 79): активен по цель-данным, SourceScripts не читает
Гейта по письму источника нет. backend/internal/checks/cheapgates.go:414-416: единственный гейт — `if c == nil || len(c.magnitudeStem) == 0` — это ЦЕЛЬ-данные (checkers.go:51 «target-general: ru magnitude word stem», checkers.go:159 — из пар-конфига `magnitude_stem`). grep sourceScripts/SourceScripts по cheapgates.go — 0 вхождений: механизм SetSourceScripts существует (checkers.go:104-125) и используется другими путями, но lintNumberMagnitude его НЕ читает. Источник-сторона захардкожена: cjkMagnitudeOrders (cheapgates.go:464-466) ищет CJK-маркеры 万/萬/億/亿/兆 безусловно. На ja-книге чекер активен без гейта (случайно корректен — маркеры общие с ja); на не-CJK источнике инертен лишь по контенту, семантика источника остаётся захардкоженной в общем слое — находка §8 карты D39.60 актуальна.
**Фикс/скоуп:** Не требуется — дописка 79 точна («гейтить по объявленному письму источника», кандидат при ближайшем касании чекеров).
### [CONFIRMED_LOST] (4) Golden-счётчики голоса (дописка 41): в capture.golden voice-счётчиков нет
Подтверждено отсутствие: `grep -c -i voice backend/internal/pipeline/testdata/golden/capture.golden` = 0 (ни одного вхождения); в testdata/golden/pipeline.yaml ключа `voice:` нет (grep пуст) — гейт opt-in OFF по умолчанию (backend/internal/config/pipeline.go:279-281), фикстура его не включает, значит golden не пинит ни n_voice_flags/voice_detail, ни VoiceFlags/SpoilerLeaks (quality.go:269-278, 436 — счётчики существуют в коде, но в golden-контур не заведены). Хвост D39.58 реален и жив.
**Фикс/скоуп:** Не требуется — дописка 41 точна.
### [CONFIRMED_LOST] (5) Слот инъекции голоса (дописка 24): инъекционная половина построена условно и НЕ включена, оба провода
Оба провода подтверждены. Провод 1 (инъекция): половина построена в membank УСЛОВНЫМ фолдом — backend/internal/membank/memory.go:248-252 (`InjectVoice reports whether the voice/address rows reach the WIRE... It is the CONDITION`), 370-377 («A book with no voice rows, or a run with the injection off, hashes BYTE-IDENTICALLY»), 448-465 (фолд под `if !in.InjectVoice`); но pipeline захардкоживает выключенность: backend/internal/pipeline/seeding.go:130-133 — «InjectVoice is FALSE and has no config knob: pack-19 builds the schema and the flagger, and D21 п.2 holds the injection conditional until the polygon experiment... Wiring the injection means setting it and accepting a full --resnapshot». Провод 2 (флаггер): гейтится Gates.Voice.Enabled, opt-in OFF (backend/internal/pipeline/voicerun.go:46; config/pipeline.go:264-281). Совпадает с D39.55 (05-decisions-log.md:1177): «слот инъекции НЕ выбран, оба провода, решит полигон-эксперимент».
**Фикс/скоуп:** Не требуется — дописка 24 точна (решение по gates.voice и инъекции — на следующем живом прогоне).
### [CONFIRMED_LOST] (6) Остаток §12.7 (дописка 74): 8 несудимых fidelity-пар P4 существуют в ~/books/gu-zhenren/research15-probes/
Сырьё существует, суд не докуплен (проверено счётом файлов и метаданными, тексты не читались). P4-артефакты: ~/books/gu-zhenren/research15-probes/probes/raw/ — 100 файлов, вкл. полные сетки echo-ds-gu008-{D0,D1,D2,DP}×{s0,s1,s2} (12 шт.) и echo-grok-gu-001..010×{G0..G4} (50 шт.). Судейское сырьё: ~/books/gu-zhenren/promptlang/judge_p4/votes.jsonl = 36 голосов ровно над 16 distinct (fam,arm,frag)-комбо: deepseek только gu008-s2×{D1,D2,DP} (3), grok G1×{001,002,004,005,006} + G2×{001,002,004,005} + G4×{001,002,004,005} (13). Отчёт POLYGON_PROMPTLANG_ANTIECHO_2026-07-31.md:775-776 («Судья остановлен своим капом $0.28 на 16 парах из 24») и :784 («Добрать 8 несудимых пар P4 ≈$0.10»); файлы несудимых комбо (ds-gu008 s0/s1 × 3 арма; grok gu-006 G2/G4 и далее) в raw/ присутствуют.
**Фикс/скоуп:** Не требуется — дописка 74 точна: сырьё лежит, добор ≈$0.10 реально отложен «до предмета wiring».
### [RESCOPE] (7) Протокол гендер-твиста D5.1 (дописка 49): «redrive есть, селективного by-until_ch пути нет»
Посылка «селективного пути нет» ОПРОВЕРГНУТА: селективная пере-редактура по изменению банка + смета ПОСТРОЕНЫ и живьём проверены. backend/internal/pipeline/repin.go:14-35 — «POINTWISE re-edit by key (pack-20 point 5, D39.42 п.5)»: bank-only сдвиг снапшота + неизменный content_hash → пере-пин юнита за $0, изменённые инъекции — платно; «The same predicate drives the ESTIMATE: projectRebill uses it» (смета «N units, ~$X»); встроено в штатный резюм — stagerun.go:87 (repinnable); согласие на пере-оплату — rebill.go:11-40 (D20.2-Q2). until_ch-апдейт = правка строки банка → двигается ТОЛЬКО memory_version → ровно этот путь (D39.42 п.5: «поздняя подпись и ЛЮБАЯ правка», 05-decisions-log.md:1089; D39.45, :1113-1115: «точечная ре-редактура по ключу с $0-пере-пином — построено, живьём проверено... 20 юнитов пере-пинены за $0 при bank-only-сдвиге»). При этом верно: tmctl redrive существует (cmd/tmctl/main.go:81-82, 214), но его селектор — только chapter/chunk/reason по ФЛАГНУТЫМ чанкам (status.go:564-582), until_ch-пути в НЁМ нет — селективность живёт в другом инструменте (translate-резюм + repin + rebill), и это by-design правильный носитель.
**Фикс/скоуп:** Пере-формулировать дописку в строке 49: тех-механизм «until_ch-апдейт → селективная пере-оплата затронутых юнитов + смета» УЖЕ построен (repin.go/rebill.go, D39.42 п.5, D39.45) — слова «селективный redrive» убрать (redrive — инструмент флагнутых чанков, не носитель). Остаток дописки — только операторский ПРОТОКОЛ-документ релиза D5.1 (последовательность: выставить until_ch у gender=hidden-терма → tmctl translate → согласие на rebill-смету; + курация 白凝冰 из строки 24), либо закрыть дописку явной ссылкой на D39.45.
**Сводка среза:** Адверсариальная проверка среза (строка 86 + дописки 79/41/24/74/49) свипа D39.66: 6 из 7 пунктов подтверждены как корректно занесённые (CONFIRMED_LOST) с file:line-доказательствами отсутствия в коде: (1) pre-c-lite echo-семантика реально сохранена (quality.go:216-218,295-318), альтернатива не построена; (2) magnitude-кап CJK-утечки отсутствует — только strip+flag (sanitizer.go:770, disposition.go:96-104; пороги 0.15/0.25 — другие классы); (3) lintNumberMagnitude гейтится только цель-данными magnitude_stem (cheapgates.go:414-416), sourceScripts не читает; (4) capture.golden — 0 voice-вхождений, гейт в фикстуре выключен; (5) инъекция голоса построена условным фолдом (memory.go:248-252,448-465), но InjectVoice захардкожен false без ручки (seeding.go:130-133), флаггер off (voicerun.go:46); (6) 8 несудимых P4-пар — сырьё на месте (research15-probes/probes/raw: 100 файлов, judge_p4/votes.jsonl = ровно 16 судимых комбо из 24). Пункт (7) — RESCOPE: посылка «селективного by-until_ch пути нет» опровергнута — точечная ре-редактура по изменению банка со сметой и $0-пере-пином построена и живьём проверена (repin.go:14-35, stagerun.go:87, rebill.go; D39.42 п.5, D39.45); tmctl redrive действительно не имеет until_ch-селектора, но носитель — translate-резюм+repin. Предложена правка дописки строки 49: оставить только операторский протокол-документ релиза D5.1 или закрыть ссылкой на D39.45. Ничего не менялось, не коммитилось, $0.