textmachine/docs/archive/reports/CHECKER_PACKAGE_2026-08-02.md

185 lines
38 KiB
Markdown
Raw Permalink 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.

# Отчёт: ПАКЕТ-ЧЕКЕРОВ — детекторы качества против размеченного корпуса ($0)
> **✅ ПРИНЯТ И ЗАЛЕНДЕН (оркестратор №9, 02.08.2026, D39.78; постфикс §8 — тем же лендингом, v7 бампнут ОДИН раз).** Двухраундовая приёмка исполнением: labels-харнесс перепрогнан лично (все ячейки §2 побайтно; фрозен-ДО #3 5/1/41/99 из дерева; k4a 0/0/0/348 — 12/12); голден — независимый маскированный дифф ПУСТ дважды (v7-захват и постфикс-no-op); build/vet/-race/майнер-парити зелёные. **Раунд 1** (10-агентный адверсариал-воркфлоу): 0 блокеров, 5 CONFIRMED major — скоуп k4_inverse (= весь хвост строки), 2 ложных «вскрытых» примера #3 (§2 первой редакции), BASE==EXT кандидат-теста, рассинхрон репэйр-твина латиницы, Р4-потолки не в контракте — ВСЕ закрыты постфиксом §8 до коммита. **Раунд 2** (дельта, 3 агента + верификация): 0 major; остаточные минорки → бэклог-строка 93; вопросы §6 + жанр-ось register_neg («xianxia» в msg-шаблоне пар-пака) + асимметрия 兩-батча → строка 92. Честные границы ратифицированы: «fn=0» #10 — класс-вакуумен (hard-gate строки 12 на него не опираться); p=1.0 k4_inverse не ограничивает вне-корпусные формы. Лендинг-штамп: «D39.76» в постфикс-пометках → фактический **D39.78** (здесь + 2 код-коммента — механическая нумерация). Незаявленные в §-списке дерева файлы (langpack.go — коммент-указатели ведра D; memdecl_test.go — gofmt) тривиальны, проверены.
**Дата:** 02.08.2026 · **Сессия:** бэкенд · **Промт:** `docs/BACKEND_CHECKER_PACKAGE_SESSION_PROMPT.md` (строка 25 + 79, D39.67/68).
**Зона:** `backend/` (+ `configs/langpacks/zh-ru/`) + этот отчёт. **Деньги:** $0 — ни одного платного вызова; `--resnapshot`-эквивалент не запускался; голден пере-захвачен фейк-провайдером ОДИН раз в конце. **Статус:** НЕ закоммичено — лендит оркестратор. **СТОП в конце — приёмка оркестратора.**
## ЭХО-БЛОК (как понят скоуп)
1. **Скоуп:** $0-детекторы качества против `~/books/gu-zhenren/labels/`; перечень = строка 25 + 79. Для КАЖДОГО пункта — вердикт-тройка (посылка/нужность/форма) ДО кода; допустимый исход = «не чинить, закрыть с обоснованием».
2. **$0:** денег ноль, вызовов провайдеров нет.
3. **Зона:** `backend/` + `configs/langpacks/` + отчёт + краткий итог в PROGRESS §Бэкенд (бэклог-таблицу/CURRENT-STATE не трогаю).
4. **Стоп-точки:** НЕ коммитить; `TM_UPDATE_GOLDEN` один раз в конце; чужие правки `backend/` → СТОП+пинг.
5. **Мандат:** ревизия посылок; замер против посылки → СТОП+пинг; самопроверка исполнением (author≠reviewer).
---
## §1. Харнесс labels — пересобран В GIT, калибровка на неизменённом коде
Прежний харнесс утрачен в scratch («персист, не scratch»). Пересобран как **env-гейченный Go-тест В GIT** (образец майнер-парити), durable:
- `backend/internal/checks/labelharness_test.go``TestCheckerLabelsBaseline` (K1/K2/K3/K4b/k4_inverse/K5a/K5b/K5c×2/K5d), вызывает НАСТОЯЩИЕ `internal/checks` через компиляцию zh-ru пака точно как раннер.
- `backend/internal/membank/labelharness_test.go``TestK6LabelsBaseline` (пост-чек K6; `dstFormPresent`/`entry` не-экспортны → white-box здесь).
- `backend/internal/checks/labelcandidates_test.go``TestCheckerLabelsCandidates` (замер КАНДИДАТ-правил ДО коммита — «мерить, потом решать»).
Гейт: `TM_CHECKER_LABELS=1`; данные вне git (текст книги) → тест СКИПается без стенда. Пути overridable env (`TM_CHECKER_LABELS_DIR`, `TM_CHECKER_LANGPACK_ROOT`).
### Воспроизведение `metrics.json` (колонка ДО) — ПОБАЙТНО на неизменённом коде
**ВСЕ 12 ключей `metrics.json` воспроизведены точно** до внесения правок. Два независимых пути счёта совпали: (а) Go-харнесс; (б) независимая пере-реконструкция джойн-конвенций из СОХРАНЁННЫХ `verdicts/` (units.jsonl/misc.json/k4.jsonl) — обе бьются с `metrics.json`. ⚠ **Поправка ревью-агента (D39.78):** первая редакция писала «11 ключей» — k4a (n=348, all-TN, дефект-МАРКЕР по всем 348 строкам k4.jsonl) молча выпал. Теперь воспроизведён `measureK4a` МАРКЕР-ОНЛИ (ведущая « " » / « - » / « »-опечатка, НЕ фолд-счётчик `DialogueDash`), закреплён 0/0/0/348 — иначе фолд `inverseMarker` в `DialogueDash` читал бы 3 инверс-файра как маркер-дефекты. 11 из 12 в `checks`-харнессе + K6 в `membank`.
Конвенции джойна (реверс-инжинирены из сохранённых вердиктов, зафиксированы в харнессе):
- **Юнит-классы (K1/K5a/K5b/K5c):** окончания-разметки агрегируются к юниту с приоритетом **defect > disputable > ok**; вердикт = суб-счётчик чекера > 0.
- **K2:** пер-токен по размеченному полю (детектор гоняется и на draft, и на final).
- **K3:** пер-словотип.
- **K4b:** пер-ёлочная-строка (`chevronSpeechShape && isSpokenChevronLine`), spoken=defect, ambiguous=disputable. **k4_inverse:** пер-тире-строка, thought=defect.
- **K6:** `dstFormPresent` пер-строку пула; `predDefect = !present`.
**Ловушка ApplyHeading (README):** боевой гейт видит финал ДО `chunk.ApplyHeading` (waverun.go:547/export.go:215 идут ПОСЛЕ RunCheapGates на :501); корпус запёк детерминированный «Глава N». Харнесс снимает голый «Глава N» (`stripManifestHeading`) — иначе номер главы читается регресс-гардом как «появившееся число». Это ровно даёт `k5d` = 4 fp + 1 tn: `minirun:10:0` («Глава 10», номер только в заголовке) → TN после снятия; старостековые acceptance-заголовки («Раздел N: title») — запечённое ТЕЛО, не снимаются → остаются fp. Воспроизведено точно.
### Конвенция K5c — выбрана и названа
Две конвенции разметки:
- **`k5c_unit`** (читательская мерка, значение=дефект): precision **0.167** — 5 срабатываний несут ВЕРНОЕ значение в форме дроби (六成六→«шесть десятых и шесть сотых»=0.66=66%). Это **целевая мерка Р2** (жёсткий флаг только за неверное ЗНАЧЕНИЕ).
- **`k5c_unit_codeconv`** (форма=дефект): precision **1.0** — верность кода КАК НАПИСАН (файрит по форме).
**Выбор:** обе именованы и меряются. `k5c_unit_codeconv` = фиделити текущего кода; `k5c_unit` = контракт Р2, к которому код должен прийти (см. вердикт-тройку #1 ниже).
### Две дельты пост-банк-пака (объяснены, не код-баги)
- **K6 стеммер (D39.75):** `metrics.json` предшествует стеммеру. Текущий `declinedFormPresent` (стеммер) принимает `凡人→смертных` и `甲等→разряд А` ⇒ K6 fp 14→**12** ещё ДО моих правок. Первопричина — банк-пак §и/§3 (стеммер + combmark-фикс `text.TokenizeLetters`). Харнесс меряет ОБА пути (стеммер off = базлайн, on = текущий) — дельта локализована и объяснена.
- **K3 combmark (D39.64/75):** U+0301-фикс НЕ двинул `k3` на этом наборе (ни один размеченный дефект не бил в кейс `бо́льшим`-сплита) — метрика байт-идентична.
---
## §2. Метрики per-class ДО/ПОСЛЕ (вскрытые единицы)
| класс | ДО (metrics.json) | ПОСЛЕ | что двинулось |
|---|---|---|---|
| K1 DC1 время | 6/0/0/9 · p1.0 r1.0 | = | не трогал |
| **K2 латиница** | 30/0/10/52 · p1.0 **r0.75** | **34/1/6/51 · p0.971 r0.85** | **#6:** +4 tp (BANK×2, Cultivation×2); 1 fp = «Qidian» (бренд; p→1.0 лишь ЕСЛИ занесён в allowlist — сейчас конфиг не заносит) |
| K3 битые формы | 1/0/9/2167 · r0.1 | = | Р4-потолок (один шаблон «-йть») |
| **K4b ёлочная речь** | 5/1/41/99 · p0.833 **r0.109** | **10/1/36/99 · p0.909 r0.217** | **#3:** +5 tp (восклиц. атрибуции), 0 новых fp |
| **k4_inverse** | 0/0/4/71 · **r0** | **3/0/1/71 · p1.0 r0.75** | **build:** inner_marker-на-тире (+3 tp, 0 fp) |
| K5a магнитуда | 0/0/1/26 · r0 | = | **#5 закрыт:** единственный дефект DC2-покрыт |
| K5b DC2 | 1/0/0/7 · p1.0 r1.0 | = | не трогал |
| K5c 成 (значение) | 1/5/1/8 · **p0.167** | = детекция; **Р2:** PercentScale→SOFT | 5 fp = верное значение/форма-дробь ⇒ мягкий счётчик |
| K5c 成 (форма) | 7/0/1/8 · p1.0 | = | #8 (两) замаскирован супрессором |
| K5d дрейф | 0/4/0/1 · p0 | = | вне скоупа-дефектов (регресс-гард, D38) |
| **K6 глоссарий** | 1/**14**/0/243 · **p0.067** | **1/6/0/251 · p0.143** | **#10:** 6 fp (转); +стеммер 2 (凡人/甲等); **fn=0 сохранён** (古月方正 пойман) |
**Вскрытые единицы (глазами, ≥1 с каждой стороны):**
- **#3 K4b +5 tp** (все со связкой-глаголом ИЗ `speech_verb`, ранее слепые из-за требования запятой после `»`): `acceptance:6:0:draft:100` «Гуюэ Фан Чжэн!» — **крикнул** старейшина; `acceptance:17:0:final:22` «…в такую позднюю пору…» — **пробормотал** слуга; `acceptance:21:0:final:38` … — **сказал** … (+ `15:0:draft:68` «крикнул», `6:0:final:96` «крикнул»). 0 новых fp (глагол-гейт `isSpokenChevronLine` держит точность). ⚠ **Поправка ревью-агента (D39.78):** прежние примеры «раздался голос»/«скривился кто-то» БЫЛИ ЛОЖНЫ — «раздался»/«скривился» НЕ в `speech_verb`, эти строки остаются FN; агрегат 10/1/36/99 честен (реальные +5 tp — по id выше, сверены с `fn_ids` базлайна), но «вскрыто глазами» держится на глаголах из списка, не на этих двух.
- **#6 K2 +4 tp:** `BANK` (маркер банка), `Cultivation` (утечка англ. термина) в финалах — реальные утечки. 1 fp = `Qidian` (платформа-бренд, метка ok) → allowlist книги нейтрализует.
- **#10 K6 6 fp:** все 6 = 转 внутри 转身/辗转/转为 (глаголы, не ранг) — демотированы в observability; **ни одного реального промаха не потеряно** (fn=0). ⚠ **fn=0 здесь КЛАСС-ВАКУУМЕН (поправка D39.78):** в размеченном наборе НОЛЬ реальных промахов на одно-руновом Han-ключе, поэтому демотация не могла спрятать реальный промах — но и recall-ЦЕНА демотации этим корпусом НЕ измерена; hard-gate строки 12 на «fn=0» здесь опираться не должен.
- **k4_inverse +3 tp:** «— …, — вздохнул ПРО СЕБЯ Фан Юань» — мысль, набранная тире; 1 остаточный промах = маркер вне списка (потолок ДАННЫХ, не правила).
---
## §3. Вердикт-тройки (ВСЕХ пунктов, включая «не чинить»)
Легенда: **(а)** посылка · **(б)** нужность на labels · **(в)** форма/исход.
### Построено
**#10 — однознаковые Han-ключи пост-чека** (`membank/mempostcheck.go`). (а) Посылка ВЕРНА: 转 через `allow_short` фаерит подстрокой в 转身, `collisionProneKey` ложен для Han ⇒ ложный Confirmed-miss (6 из 14 fp). (б) 6 fp на labels, fn=0 — чистое precision-улучшение. (в) **Построено:** миссы с одно-руновым Han-ключом (`singleHanKeyFired(p.Via)`) роутятся в **Unverified observability**, не Confirmed. Мульти-руновые Han (元石) НЕ демотируются (контроль-тест). Гвозди: `mempostcheck_test.go` (single→Unverified, multi→Confirmed). Контракт коротких Han-ключей описан §-блоком в коде + скоординирован с B6-токенизатором. **⚠ Стеммер-путь `declinedFormPresent` НЕ тронут** (правка на уровне роутинга миссов, не `dstFormPresent`).
**#3 — атрибуция ёлочной речи** (`cheapgates.go chevronSpeechShape`). (а) Посылка ВЕРНА (38/46 реплик мимо). (б) Замер: +5 tp, K4b recall 0.109→0.217. (в) **Построено (уточнено после ревью):** принимается `«X», —` (запятая) ИЛИ `«X!»/«X?»/«X…» —` (восклиц. реплика); плоская цитата `«X» —` (буква перед », без запятой) ОТВЕРГАЕТСЯ. ⚠ **Ревью-агент нашёл FP** моей первой версии (просто «опциональная запятая»): цитата-прозвище `«Бессмертный» — так его называли, …произнёс старик` ловилась (глагол в другом предложении). Уточнение закрыло FP, сохранив все +5 tp (labels не двинулись). Гвоздь `TestChevronCitationNotFlagged`. **Р4-потолок ~0.22 by construction** (24 безатрибутивные реплики).
**#6 — заглавная латиница/маркеры** (`checkers.go lintLatinResidue`). (а) Посылка ВЕРНА (Cultivation/BANK слепы). (б) Кандидат: caps-aware ⇒ +4 tp, **ИЗМЕРЕННАЯ precision 0.971** (1 fp «Qidian»=бренд). (в) **Построено:** снят reject-по-заглавной; легит-бренды → per-project allowlist (case-insensitive). ⚠ **Честно (находка ревью-агента):** precision 1.0 достижима, ТОЛЬКО если книга заносит бренд в `style_allowlist` — ни один боевой конфиг gu-zhenren этого сейчас НЕ делает, так что честное число = **0.971**, не 1.0. Гвоздь: `checkers_pack13_test.go`.
**k4_inverse — inner_marker-вето-на-тире** (`cheapgates.go lintDialogueDash`). (а) Посылка (D39.64 §5.5): тире-строка ВСЕГДА корректна, мысль-на-тире невидима. (б) Замер: +3 tp, recall 0.75. (в) **Построено (уточнено после ревью):** маркер ищется в АТРИБУЦИИ (после первого `[,.!?…] —` join), НЕ по всей строке. ⚠ **Ревью-агент нашёл FP** моей первой версии (маркер по всей строке): `«— Повтори это про себя, — сказал учитель»` (законная РЕЧЬ, лишь УПОМИНАЕТ «про себя») ловилась. Скоуп на атрибуцию закрыл FP, сохранив +3 tp. Гвоздь `TestInverseMarkerDashError` (вкл. adversarial-FP + multi-clause кейс).
**#8 — 两/兩 → cheng_re** (данные `dc-checkers.txt`). (а) Посылка ВЕРНА (两 в `cjk_numeral`/`shichen_re`, нет в `cheng_re`). (б) **Нужность на labels = 0:** 两成 в acceptance:10:0/minirun:10:0 замаскировано супрессором #1 (там есть «процент»). (в) **Построено как ДАННЫЕ** (batch): 两/兩 в оба класса cheng_re + 兩=2 в cjk_numeral (парс-полнота). Правомерно как generality/consistency-фикс (санкция D39.63 «данные, батчем»); 0 измеренного эффекта — честно.
**#1 (половина) — Р2-контракт hard/soft** (`cheapgates.go`). (а) Посылка (D39.63): жёсткий флаг только за неверное ЗНАЧЕНИЕ; неконвертированная форма = мягкий счётчик. (б) 5 из 6 k5c-fp = верное значение/форма-дробь. (в) **Построено:** `UnitScaleHard()`={DC1 — сверяет ruNum≠2n · **NumberMagnitude — слово-магнитуда неверного ПОРЯДКА, 三万→«три миллиона»**} / `UnitScaleSoft()`={DC2 千万→«тысячи» гипербола-неоднозначна · PercentScale верное значение в форме-дроби}. ⚠ **NumberMagnitude→HARD по находке ревью-агента** (файрит на реальной ошибке значения, не только форме — исходно был в soft). `Total()` НЕ тронут ⇒ голден-нейтрально. Классификация — вокабуляр для report/`postcheck_gate`.
**Строка 79 (первые два компонента + magnitude-гейт):** (а) Посылки ВЕРНЫ (§8 карты D39.60). (в) **Построено, generality, 0 эффекта на zh→ru:** `isCyrLetter``c.isTargetWordLetter` (wordScript) в `lintRegisterLexicon` + `repair.go` DC1-трим; `lintNumberMagnitude` гейтится `sourceHasDenseScript()` (объявленное письмо источника). Гвоздь: `TestNumberMagnitudeSourceScriptGate` (Han/ja фаерит, Latin инертен). **Побочно закрыл находку ведра C-2** (register-boundary на не-кириллической цели вырождался в подстрочный матч — GENERALITY_RESEARCH §3.3). **⚠ Третий компонент (граница ПЛОТНОСТИ `cjkScriptNames`) — НЕ в скоупе, остаётся строке 79.**
**Рефрен-alignment (минимум $0):** editor.md + editor-mono.md — вписано исключение «повтор в параллельных позициях исходника = авторский рефрен, сохраняй». Двигает PromptSHA256 боевого пака (перекупок нет, D39.63); голден-фикстура на синтет-промтах ⇒ prompt_sha256 голдена НЕ двинулся.
### Закрыто с обоснованием («не чинить»)
**#5 — K5a 数/几-магнитуды.** (б) **Нужность = 0:** единственный реальный дефект магнитуды на всём корпусе (`数十万人→«десятки тысяч»`, rerun2-mistral:2:0) УЖЕ пойман DC2 (K5b, recall 1.0). Расширение 数-коэффициента ловит 0 НОВЫХ единиц. **Закрыто** (на других корпусах может понадобиться — но текущая эмпирика не оправдывает).
**#7 — порог minLatinResidueLen=3.** (б) Замер: THRESHOLD=2 даёт **0 изменений** (recall 0.75→0.75). Гомоглиф «гy» (K2-мотив #7) — это MIXED-скрипт токен (1 латинская руна), не длина-порог; ловится существующим детектором `tk.mixed` (см. ниже). **Закрыто; 3 записан как Р4-потолок** в контракте правила.
**Гомоглиф-детектор `tk.mixed` — приёмка (D39.64 §5.5).** Замер: `detectBrokenWords` ловит «гy» (Cyrillic г + Latin y) как homoglyph. Единственный гомоглиф корпуса (acceptance:24:1) пойман. Гвоздь: `TestHomoglyphDetectorAcceptance`. **Приёмка пройдена.**
**Omission-бэкстоп (R4).** **УЖЕ построен** — стеммер (`declinedFormPresent`, примитив C банк-пака) в пост-чеке ЕСТЬ лемма-матч по {dst, decl.forms}. Замерено: стеммер сам починил 2 K6-fp (凡人/甲等). Уроки softsign соблюдены (только флаггер; «ь»-класс не тронут; finding-1 закрыт на сид-формах A, движковый C загейчен D39.76). Пробел: target-**алиасы** в матч не заведены — сид-концерн, не код. **Закрыто (переиспользован, измерен).**
**DC2 word↔word дроби (rule_b1/b2).** (б) 分之-дроби есть в корпусе (8 юнитов), НО ни одного РАЗМЕЧЕННОГО дефекта класса нет → precision/recall неизмеримы. Строить вслепую = против мандата. **Закрыто; рекомендация — сперва разметить 分之-срез, потом строить.**
**research/22 §2 №5 (char-freq-degeneration, control-code-loss).** Классов НЕТ в размеченном наборе → не подтверждены на данных. **Закрыто** (строить только если labels подтвердят).
**Строгий OffLanguage.** Оговорка 36а: «甲等 → класс Цзя» строгой формой НЕ ловится. **Не заявляю выигрышем;** остаётся deferred.
### На владельца (см. §6)
**DC7 grade/role** — approved grade-строки ЕСТЬ (класс А/Б/В/Г), но КОЛЛИЗИЯ с draft «разряд X». Нужна канон-подпись «класс» vs «разряд» ПРЕЖДЕ стройки (PACK11_CONT:195 — дизайн + вопрос, не стройка вслепую).
---
## §4. Голден-протокол (пере-захват ОДИН раз в конце)
`TM_UPDATE_GOLDEN=1 go test ./internal/pipeline/ -run TestGoldenDeterminism` — маскированный дифф (`hex≥12→HEX` + `cheapgate-vN→vX`) — **ПУСТ**.
- **Единственная содержательная ось:** `style_check_version` `cheapgate-v6…``cheapgate-v7-checkerpack-attribution+latincaps+p2split+combmark` в двух снапшот-payload'ах (бамп CheapGateVersion — ратифицирован промтом).
- **Каскад:** `snapshot_draft`/`snapshot_edit` (фолдят payload) → все `final_hash` (АДРЕС авторитетного чекпойнта, `chunkstatus.go:31`, не хеш текста).
- **НЕ двинулись (побайтно):** `content_hash`, `disp`, `flag`, `cost`, `attempts`, `escalated`, `detail`, `stage_text`, `memory_version`, `prompt_sha256`, `embedded_version`, `render_format_version`, все dispositions/finish. **Вердикт-нейтрально:** новые детекции не файрят на ja-фикстуре голдена (там нет паттернов #3/#6/inner-marker). Перекупок нет (D39.63).
---
## §5. Приёмка и самопроверка (author≠reviewer исполнением)
- `go build ./...` · `go vet ./...`**зелёные**. `go test -race ./...`**зелёные все пакеты** (единственный ожидаемый двиг — голден, пере-захвачен раз).
- **Майнер-парити EXACT** (`TM_MINER_PARITY=1`).
- **Мутационные тесты на новые классы:** `mempostcheck_test.go` (#10 single/multi-Han), `checkers_generality_test.go` (SourceScripts-гейт, гомоглиф, inner_marker), `checkers_pack13_test.go` (caps-latin+allowlist).
- **Общность:** свип ДОБАВЛЕННЫХ engine-Go-строк на pair/book/lang-литералы — **пусто**. `unicode.Han` в #10/magnitude-гейте = скрипт-структурный (любой CJK-источник), не пара/книга. «Пара не из репо заведётся без правки Go» держится.
- **Самопроверка исполнением:** каждый фикс замерен на labels ДО стройки (кандидат-харнесс); каждый двиг вскрыт глазами (≥1 единица с каждой стороны); #10 проверен И харнессом (модель p.Src), И прямым продакшн-тестом (p.Via). Базлайн воспроизведён двумя независимыми путями счёта.
### Адверсариальное агентское ревью (3 refute-biased агента) — по вопросу владельца, ПОСЛЕ лендинга
Соло-замер на labels недостаточен: корпус мог не содержать адверсариальных форм. Три агента (корректность · честность харнесса/метрик · общность+стиль) читали код и ГОНЯЛИ харнесс. Итог: **2 корректностных FP найдено и ИСПРАВЛЕНО ДО приёмки** (оба — observability, не диспозиция), 1 honesty-правка, 1 Р2-реклассификация, DRY + подрезка комментариев. **Манифактуренной сходимости НЕ найдено; харнесс подтверждён честным ЗАПУСКОМ (byte-for-byte metrics.json, «before» реконструированы из git).** Именно это — ценность мандата: лейбл-замер показал 0 fp, адверсариал вскрыл реальные:
1. **k4_inverse FP:** `lineHasInnerMarker` искал маркер по ВСЕЙ строке → законная речь, УПОМИНАЮЩАЯ «про себя», ловилась. **Фикс (уточнён D39.78):** сегмент атрибуции ограничен с ДВУХ сторон — ведущий спокен-клауз отсечён (первый `[,.!?…] —` join), И (постфиксом) хвостовой клауз отсечён на СЛЕДУЮЩЕМ `[,.!?…]` (продолжение после «. —» / нарративный хвост «. Про себя…» без второго тире); `lineHasInnerMarker` — по границе слова («в уме» ≠ «в умении»). +3 tp сохранены (3/0/1/71), 4 контрпримера закрыты гвоздём (`TestInverseMarkerDashError`).
2. **#3 chevron FP:** «опциональная запятая» ловила плоскую цитату `«X» —` с глаголом в другом предложении. **Фикс:** принимать только `«X», —` или `«X!/?/…» —` (sentence-final перед »), отвергать плоскую. +5 tp сохранены. Гвоздь.
3. **Р2 NumberMagnitude → HARD:** файрит на слове-магнитуде неверного порядка = ошибка значения (был ошибочно в soft).
4. **K2 честность:** «precision 1.0 с allowlist» — спин; измеренное = **0.971**, боевой конфиг бренд не заносит. Исправлено во всех формулировках.
5. **DRY + стиль:** `lang.IsDenseScript` (единый реестр плотных скриптов) для `sourceHasDenseScript`; подрезаны 4 doc-простыни (метрики → отчёт) по норме владельца 26.07.
Все правки re-замерены (labels не двинулись: k4b 10/1/36/99, k4_inverse 3/0/1/71 сохранены), голден остался вердикт-нейтрален (пере-захвата НЕ потребовал — фиксы не файрят на ja-фикстуре).
---
## §6. ВОПРОСЫ ВЛАДЕЛЬЦУ (отдельным блоком)
1. **DC7 grade/role:** approved-строки грейда ЕСТЬ, но канон коллизирует — approved «乙等→класс Б / 丁等→класс Г / 丙等→класс В / 甲等→класс А» ПРОТИВ draft «甲等→разряд А / 丙等→разряд В / 丁等→разряд Г». Какой ряд канон — «класс X» или «разряд X»? DC7 нельзя строить без этого решения (иначе чекер флагует по неверному эталону). Реком: подписать «класс X» (уже approved), демотировать «разряд»-draft, тогда DC7 = data-driven серия-чекер.
2. **#8 兩 (традиционные иероглифы):** добавил 兩=2 в cjk_numeral и cheng_re для generality (симпл-корпус их не содержит). Подтвердить, что traditional-Chinese поддержка данными желательна сейчас (0 стоимости), или откатить до появления traditional-книги.
3. **Р2 hard/soft:** HARD={DC1, NumberMagnitude} (ошибка значения), SOFT={DC2 гипербола, PercentScale форма}. Полноценный HARD-value-чек для 成 (PercentScale) требует ru-numeral-word-данных (Р4-потолок записан). Строить value-детектор для 成 сейчас или держать soft-наблюдаемость до `postcheck_gate` (строка 12)?
4. **register_neg в ПАР-паке:** лексемы «терем…» (target-ru свойство) живут в `zh-ru/dc-checkers.txt`. Инвариант «без правки Go» держится (новая пара кладёт свой dc-checkers), но ja-ru продублирует список. Перенести register_neg в target-данные (общий для всех ru-целей) — отдельным дата-паком? (Не блокер; наблюдение.)
---
## §7. Итог (в PROGRESS §Бэкенд)
Пакет-чекеров ($0): харнесс labels пересобран В GIT (env-гейт, 2 пути счёта), `metrics.json` воспроизведён ПОБАЙТНО (12 ключей — k4a добавлен маркер-онли D39.78), k5c-конвенция названа (codeconv=фиделити кода / unit=цель Р2). **Построено:** #10 (пост-чек однознак. Han → observability, K6 fp 14→6, fn=0) · #3 (атрибуция +5 tp, K4b r0.11→0.22, Р4-потолок в контракт) · #6 (заглавная латиница +allowlist, K2 r0.75→0.85) · k4_inverse (inner_marker-на-тире, +3 tp, p1.0) · #8 (两/兩 данные, 0 эффекта — generality) · Р2 hard/soft split · строка 79 (isCyrLetter→wordScript · DC1-трим · magnitude SourceScripts-гейт, закрыла и ведро C-2 register-boundary) · рефрен editor.md/mono. **Закрыто с обоснованием:** #5 (DC2-покрыт) · #7 (порог=0-эффект; гомоглиф=`tk.mixed`, приёмка пройдена) · DC2 word↔word (нет размеченного дефекта) · research/22 (не на labels) · omission-бэкстоп (уже стеммером) · строгий OffLanguage (36а). **На владельца:** DC7 grade/role (коллизия канона класс/разряд). Голден: пере-захват раз, маскированный дифф ПУСТ (двинулся только `style_check_version` v6→v7 + хеш-каскад; вердикты байт-идентичны). build/vet/-race зелёные, майнер-парити EXACT.
**Обязанность лендинга:** актуализировать якоря «строка 25»/#10 в `docs/architecture/13-tech-debt-anchors.md` (memory.go/mempostcheck.go сдвинулись; #10 помечен исполненным D-номером) — сделано отдельной правкой.
---
## §8. Пост-фикс пакета (D39.78 — адверсариал-ревью оркестратора, 0 блокеров / 5 major + minors, $0)
Приёмка оркестратора вернула 5 major + minors к починке ДО лендинга. Все закрыты; `CheapGateVersion` НЕ бампнут (v7 не коммичен); labels-цифры не двинулись (k4b 10/1/36/99 · k4_inverse 3/0/1/71 · k2 34/1/6/51 · K6 1/6/0/251 · **k4a 0/0/0/348 добавлен**); голден — маскированный дифф проверен.
1. **k4_inverse скоуп (major):** `speechAttribution` теперь режет сегмент атрибуции с ДВУХ сторон (первый `[,.!?…] —` join → следующий `[,.!?…]`), `lineHasInnerMarker` — по границе слова. 4 контрпримера (продолжение речи после «. —», нарратив-хвост, гомоглиф «про себя»=«о себе», «в уме»⊂«в умении») закрыты гвоздём. Р4-потолок ~0.22 вписан inline в `chevronSpeechShape`.
2. **repair латинский близнец (major):** `latinResidueCandidates` синхронизирован с #6-lint (снят caps-reject, roman/allowlist case-insensitive) — «BANK»/«Cultivation» теперь дают кандидат, а не 0. Ложные комменты repair.go:16-20/144-146 поправлены; гвоздь `TestLatinResidueCandidateCapsSynced` + caps-строка в `TestRepairCandidatesAgreeWithLints`.
3. **candidate-тест самоинвалидация (major):** `labelcandidates_test.go` BASE звал переписанный продакшн (BASE==EXT). Заморожен pre-#3 `chevronSpeechShapeCommaOnly` локально → «ДО» 5/1/41/99 воспроизводится из дерева; отвергнутый `chevronSpeechShapeExt` снесён (коммент :26-27 опровергнут).
4. **Р4-потолки в контракт (major):** `minLatinResidueLen` (THRESHOLD=2=0-изменений; 3=потолок) и `chevronSpeechShape` (~0.22, 24 безатрибутивные) — числа inline, не пойнтером.
5. **пост-чек контракт/комменты (major+minors):** «B6 tokenizer» = строка 81 (не 12); «multi-rune keeps a word span» → честное «статистически сильнее; Han границами не проверяется, memory.go:536»; контракт `PostcheckResult` дописан про ДВЕ Unverified-популяции (для демотированной «entitled to reject» ложно); добавлен `PostcheckMiss.Demoted` (omitempty, голден-нейтрально) — снимает противоречие disp:"confirmed" при confirmed=0; негатив-гвоздь `TestSingleNonHanKeyMissStaysConfirmed` (одно-руновый НЕ-Han остаётся Confirmed).
6. **харнесс-честность:** k4a воспроизведён (12/12); k4b-конвенция = предикатная (не mixing, 0 расхождений); «36 миссов» = 24 безатрибутивных + 12 с глаголом вне `speech_verb`; примеры #3 заменены реальными tp; «fn=0 класс-вакуумен» оговорено.
7. **isSpokenChevronLine скоуп (опц., вердикт-тройка → ОТЛОЖЕНО):** citation+stray-verb FP-класс имеет 0 инстансов в корпусе (единственный K4b fp — запятая-мысль, иная форма); скоуп тронул бы фрозен-путь спекулятивно → загейчен нотой (нужен ёлочный экстрактор атрибуции + корпус-замер ПРЕЖДЕ стройки).
**СТОП — приёмка оркестратора.**