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

53 lines
18 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.

# Отчёт: ФИКС-ПАК БАНКА (бэклог-строка 87 + Q5) — D39.71
> **✅ ПРИНЯТ И ЗАЛЕНДЕН (оркестратор №9, 02.08.2026, D39.75).** Приёмка исполнением: `build`/`vet`/`-race` все пакеты · майнер-парити EXACT · голден сверен независимо (86/86 строк, маскированный дифф ПУСТ; двинулся только `embedded_version` — `memory_version`/`prompt_sha256`/`content_hash`/все вердикты побайтно на месте) · 3-агентное адверсариальное ревью: **14/15 клеймов CONFIRMED, 1 PARTIAL, 0 REFUTED**. Ключевое подтверждено контрфактикой: с возвращённым «ь» `SameStem("Синь","синим")=true` — откат (а) верен, регресс-гвозди работают (3 из 4 пар; пара Линь/линию инертна — заменить на Линь/линий при касании); (з) даже сильнее заявленного — инструкция реалий в промптах с D39.45, не D39.58. PARTIAL: дизайн-кейс «Фан Юаню»→«Фан Юань» закреплён только комментарием + анти-коллизионным ассертом — прямой гвоздь добавить при решении finding-1 (строка 91). Combmark-щель (и) воспроизведена живьём на копии старого кода («сло́во»→[сло во]) и закрыта. Ниты: тихий head-final-дефолт незаявленного скрипта (осознанно, все 4 текущих объявлены) · BatchRunes лёгкий overcount (+2/блок, самосогласован). Finding-1 → строка 91 (выбор владельца); граница плотности `cjkScriptNames` → дописка 79. Строка 87 ЗАКРЫТА.
**Дата:** 02.08.2026 · **Сессия:** бэкенд (продолжение банк-пака D39.68/69) · **Зона:** `backend/` + этот отчёт · **Деньги:** $0 (ни одного платного вызова; `--resnapshot`/`--resnapshot`-эквивалент не запускался; голден пере-захвачен фейк-провайдером) · **Статус:** НЕ закоммичено — лендит оркестратор.
## Вердикт-тройки (по мандату D39.68; «не делать с обоснованием» — легитимно для в/е/и)
| # | Пункт | Вердикт | Что сделано / обоснование |
|---|---|---|---|
| **а** | `decl_suffix` +«ь», палладиевский класс | **ОТКАЧЕНО — предложенный фикс ФЛАВЕД (адверс. находка) → ПИНГ** | Bare «ь» был добавлен, затем ОТКАЧЕН: адверсариальное ревью (подтверждено white-box) нашло, что стрип «ь» неотличим по форме от ВРЕДНОЙ коллизии. «юань»→«юан» (нужный выигрыш) и «синь»→«син» (коллизия) — идентичная форма 4-рунного мягкознакового имени→3-рунный стем, ни одно min-stem-правило их не разделяет. Топ-фамилии Палладия «Синь/Линь» (辛/信/新, 林) схлопываются на «син/лин» = стемы общих слов «синий/линия»: `Bank.SpoilerLeaks` на отклонённой «Синь» выдаёт ЛОЖНЫЙ спойлер-лик на любом «синий» (направление ШУМА, против precision-дисциплины); `Postcheck` маскирует дроп «Синь» на любом «синем» (safe-направление, но частота много выше допущения D24.4 — «имена не рекуррируют случайно»; тут рекуррирует ОБЩЕЕ слово). Симметрия «нь/ль/й/ью» проанализирована, но нерелевантна — корень в самом «ь». РЕШЕНИЕ: не тащить коллизию; NB-коммент в `target-ru.txt` + регресс-гвоздь `TestSoftSignNamesDoNotCollideWithCommonWords` (падает, если «ь» вернут). Finding 1 (палладий) остаётся ОТКРЫТЫМ в safe-направлении — правильный путь пингом. |
| **б** | `head_final` → данные | **СДЕЛАНО** | head-finality вынесена из Go-константы в `data/script-series.txt` (`head_position<TAB>script<TAB>final\|initial`). `SeriesMorphology` резолвит head-final через `SeriesHeadFinal(script)` (данные; дефолт для незаявленного плотного скрипта = final, CJK-норма). Плотность (`enabled`) по-прежнему `cjkScriptNames` — предсуществующая граница общности, НЕ трогалась (пинг ниже). Тест: `TestSeriesMorphologyUnchanged` (zh/ja/ko→true,true; en/ru/unknown→false,false) + `TestSeriesHeadFinalIsDataDriven` (синтетический `initial`-скрипт резолвится head-initial без правки Go; corrupt-строки — loud). |
| **в** | Лживый коммент Batch + оверсайз-серия | **СДЕЛАНО (WARN)** | Коммент Batch переписан на правду: порядок ДЕТЕРМИНИРОВАН (стабильная сортировка по чистой функции контента) → $0-resume держится, НО ординал батча фолдится в request-hash (потребитель адресует batch i как ChunkIdx i), значит хеш НЕ независим от порядка (смена частот → сдвиг ординалов → перепокупка затронутых батчей). Оверсайз-серия: вердикт **WARN, не резать** (резать серию убивает со-батчинг §1; тихо оставить — против дисциплины «no silent degradation»). Добавлен `terminology.BatchRunes` + WARN в терминологисте, называющий over-cap-юнит (мина cap-8000). Тест: `TestBatchRunesFlagsOversize`. |
| **г** | `classify_types` при выкл. гейте | **СДЕЛАНО** | При `enabled:false, classify_types:true` — раньше ТИХИЙ no-op (`runClassifier` достижим только через включённый гейт, и валидация была вложена в `if tg.Enabled`). Теперь `else if tg.ClassifyTypes → bad(...)` (fail-loud, класс «гейт, который не может выстрелить»). Тесты: valid-load · нет classifier.md · budget≤0 · неизвестная classify_model · **выкл.гейт+classify_types** (`terminology_classify_test.go`). |
| **д** | Мутационный тест neuter-фолда | **СДЕЛАНО** | `memneuter_test.go` по образцу memvoice-пина: `TestNeuterRowMovesTheBankVersion` (строка gender:neuter двигает memory_version) + `TestNeuterFoldRespectsTheMinedScope` (mined-only neuter фолдится в enriched, НЕ в base — draft-волна не перепокупает; гвоздит порядок `hasNeuter`-после-`continue`). Честная оговорка в комментарии теста: тег `neuter-directive-v1` НЕ black-box-изолируем от уже-фолдящегося поля gender — тесты пинят наблюдаемый контракт. |
| **е** | Voice-checker × стеммер | **НЕ ДЕЛАТЬ (контракт в код)** | Стеммер НЕ заводится в voice-канал. Обоснование (записано в `voice.go`): имена уже приходят склонённо-осведомлёнными (`Forms` = база + перечисленные decl-формы, тот же `decl.forms[]`); accept-biased стеммер поверх добавил бы лишь риск стем-коллизий/мис-атрибуции чекеру с доктриной precision-over-recall. Для SelfRef/NG стеммер НЕ единонаправленно безопасен: стем SelfRef подавил бы ложный self-ref-флаг (безопасно), но стем NG РАСШИРИЛ бы матч запретной леммы (шум) — противоположные направления на одном чекере. Склонение SelfRef/NG — забота ДРАЙВЕРА (перечислять формы из сида, как уже Forms), не match-time стеммера. |
| **ж** | Дистилл-фикстура BANK-FULL | **СДЕЛАНО** | Поверхности `books/gu-zhenren/coldrun-a/BANK-FULL.tsv` (150) → `terminology/testdata/bankfull-surfaces.txt` (пар тест-данные). `TestDetectSeriesOnBankFullFixtureIsStable` пинит ТОЧНО 4 серии по реальному голова-скелету: 转-ранг {一二三四五六九转} (7), 等-грейд {甲乙丙丁等} (4), 等资质 {甲乙丙等资质} (3), 阶-тир {初中高阶} (3). «Ноль блоба» = каждая серия РОВНО равна ожидаемой группе (лишний член = провал), а не эвристика «≤N членов» (легитимная 7-членная ранг-серия — не блоб). 方源/元石/元海 вне. |
| **з** | Q5 — реалии в пар-промпты | **НЕ ДЕЛАТЬ (уже есть) → ПИНГ** | Инструкция «реалии по смыслу; транслитерация — именам» УЖЕ присутствует в `terminologist.md` §26-27 (закоммичено с D39.58) и `classifier.md` §10-27 (с harm-примером 元石→«юаньши»). Это ровно те два реалия-рендерящих промта, что НЕ снапшот-фолдятся (терминология-гейт) → «перекупок нет» уже соблюдено. Переводчик/translator-banknote рендерят реалии инлайн, НО их промт снапшот-фолдится (draft-стадия) → правка перекупила бы draft-волну, против «перекупок нет» → исключены сознательно. Итог: `PromptSHA256` НЕ двинулся (голден подтверждает). |
| **и** | Дубль токенизации | **СДЕЛАНО (консолидация)** | `lang.TokenizeWords` теперь делегирует в новый `text.TokenizeLetters` (script-agnostic, combining-mark-aware), разделяющий ядро с `text.TokenizeScript`. Слой соблюдён: `lang` импортирует `text` (не наоборот; цикла нет — сборка/vet зелёные). Побочно чинит combining-mark щель в decl-пост-чеке (стресс-акцент больше не рвёт слово). Тест: `text.TestTokenizeLetters` (в т.ч. совпадение с TokenizeScript на односкриптном тексте). |
## Метрики / приёмка
- `go build ./...` · `go vet ./...`**зелёные**.
- `go test -race ./...`**зелёные, все пакеты** (в т.ч. `internal/miner` майнер-парити EXACT, `internal/pipeline` голден).
- Новые тесты: lang (2 функции series + soft-sign регресс-гвоздь), config (5 classify-веток), membank (2 neuter + анти-коллизия «Синь»), terminology (BANK-FULL фикстура + BatchRunes), text (TokenizeLetters).
## Голден-протокол (пере-захват ОДИН раз в конце)
- `TM_UPDATE_GOLDEN=1 go test ./internal/pipeline/ -run TestGoldenDeterminism` — 86 строк изменилось.
- Маскированный дифф (`sed 's/^[+-]//; s/[0-9a-f]{12,}/HEX/g' | sort | uniq -u`) — **ПУСТ**: каждое изменение отличается ТОЛЬКО в hex-токенах → вердикт-нейтрально.
- Оси (HEAD vs new, точечная сверка; голден пере-захвачен ДВАЖДЫ — второй раз после отката «ь», финальный авторитетный):
- `embedded_version`: `embed-v1-37bf9699835f``embed-v1-3df4329e3b9e`**ЕДИНСТВЕННЫЙ корень** (NB-коммент `target-ru.txt` (а) + новый `script-series.txt` (б); функциональных данных «ь» в файле НЕТ после отката).
- Каскад: `snapshot_draft`/`snapshot_edit`, все request-хеши (`final_hash` = «request_hash авторитетного чекпойнта», `chunkstatus.go:31` — АДРЕС, не хеш текста; request-log `hash=`) — сдвинулись как адресация, фолдящая снапшот.
- **НЕ двинулись**: `memory_version`, `content_hash`, `prompt_sha256` (⇒ (з) не правил промт), `render_format_version`, и ВСЕ dispositions/flags/finish/degraded/cost/tokens.
- Общность: греп ДОБАВЛЕННЫХ engine-Go-строк (без комментов/тестов/данных) на CJK/пар/книго-литералы — **пусто**. Движок остаётся общим (пара не-из-репо заведётся без правки Go; head-position — данные).
## Самопроверка исполнением + адверсариальное ревью (author≠reviewer)
Самопроверка (алгоритмы · соответствие стандартам репо · правильность предложенных фиксов): соло-проход пере-верифицировал каждый пункт исполнением (тесты · маскированный голден · греп-общность · точечная сверка осей) и не нашёл дефектов сам.
Адверсариальное ревью (Workflow `wf_fea3802b-5a1`: 5 refute-biased ревьюеров по измерениям × refute-verify; 7 агентов, 0 ошибок):
- **1 ПОДТВЕРЖДЁННАЯ находка (medium) — акцептирована и ИСПРАВЛЕНА:** коллизия bare «ь» (пункт (а) выше). Ревьюер репродуцировал white-box против реального кода; я независимо пере-верифицировал (`SameStem("Синь","синим")=true`, `dstFormPresent(«Синь», …синим…)=true`; до диффа — false). Действие: откат «ь» + регресс-гвоздь + пинг. ЭТО и есть ценность мандата само-проверки — флавед-фикс пойман ДО лендинга.
- **1 ОТВЕРГНУТА (refuted):** критика комментария об исключении «й» — верно по механике (пре-существующий safe-направленный miss на не-гейтящем флаггере), но НЕ дефект, вносимый диффом; исключение «й» — осознанное задокументированное решение (и «й» всё равно не закрыл бы «Юаньхай» из-за коллизии с «-ая»).
- **4 из 5 измерений (б·в+и·г+д·общность/ж/е/з): findings пусты** — 0 дефектов.
## Пинги оркестратору (расхождение промта с кодом · открытые решения)
1. **(а) finding 1 НЕ закрыт — нужен НЕ-стеммерный механизм (РЕШЕНИЕ владельца).** Предложенный «ь» флавед (см. выше). Палладиевский мягкознаковый gap («Фан Юаню»~«Фан Юань») требует одного из: **(1) сид-перечисление decl-форм** для мягкознаковых имён собственных (тот же драйвер-путь, что записан для (е) — точный матч, коллизия невозможна; вне бэкенд-скоупа, задача полигона/сида); либо **(2) anchor-gated soft-final матч** — новая ДАННЫЕ-категория мягких окончаний + правило «декл-матч требует ≥1 ТОЧНО совпавшего компонента-якоря», так что одиночные «Синь» без якоря не матчатся, а «Фан Юань» матчится через якорь «Фан». Вариант (2) — новое ДИЗАЙН-решение (по моему уроку — валидировать на корпусе и ратифицировать, не совать в фикс-пак реактивно). Прошу выбор владельца.
2. **(з) уже сделано:** Q5-инструкция реалий уже в `terminologist.md` §26-27 (D39.58)/`classifier.md` — фикс-пак предполагал её отсутствие. Правки не требуется; `PromptSHA256` не двинулся (в отличие от ожидания приёмки).
3. **(б) граница общности:** данными вынесена ТОЛЬКО head-finality; `enabled` (плотность) по-прежнему piggyback на Go-константе `cjkScriptNames` — новый плотный скрипт всё ещё требует Go-строки там (предсуществующая граница, вне (б)-скоупа). Полной дата-общности серий — отдельная задача, если нужна.
4. **`docs/BACKEND_BANK_FIXPACK_SESSION_PROMPT.md`** в рабочем дереве несёт ЖИВУЮ правку владельца (снят «$0/очерёдность»-абзац, переписана строка приёмки на «селф ревью») — НЕ моя, не трогал (чужой незакоммиченный файл).
**СТОП — приёмка оркестратора.**