53 lines
18 KiB
Markdown
53 lines
18 KiB
Markdown
# Отчёт: ФИКС-ПАК БАНКА (бэклог-строка 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/очерёдность»-абзац, переписана строка приёмки на «селф ревью») — НЕ моя, не трогал (чужой незакоммиченный файл).
|
||
|
||
**СТОП — приёмка оркестратора.**
|