textmachine/eval/softsign-decl/README.md

136 lines
15 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.

# softsign-decl — разрыв мягкого знака в декл-пост-чеке банка (fix-pack §а, finding-1)
Замер $0 к backend-бэклог-строке 91 (finding-1): чем закрывать разрыв, когда мягкознаковое имя
(«Фан Юань», «Винный червь») склоняется («Фан Юаня», «Винного червя»), а стеммер §3 «ь» не стрипает,
и потому декл-форму НЕ принимает. Наивное «добавить «ь» в `decl_suffix`» отвергнуто в fix-pack (глобальная
коллизия «Синь/Линь»→«синий/линия»). Вопрос: движковый anchor-gated матч ЛУЧШЕ ли сид-перечисления — и
безопасен ли он на реальном корпусе, а не на бумаге.
## Метод (конвенция полигона)
- Харнесс `main.go` — БОЕВОЙ стеммер `lang.NewTargetStemmer(lang.TargetChecksFor("ru"))`; `build.sh`
материализует `go.mod`+`replace` ВНЕ репо, пин бэкенда на коммит (`git archive`) — прецедент
pkg7/minerharness. Ноль сети, ноль моделей, $0. Пин прогона: `78b7b34` (HEAD на момент замера — «ь»
уже реверсирован, D39.75).
- Корпус: банк `~/books/gu-zhenren/coldrun-a/BANK-FULL.tsv` (147 уник. dst) × боевой 25-глав-выход
`~/books/gu-zhenren/acceptance/guzhenren-25ch-ru.txt` (37 480 слов, editor=glm-5, приёмка Ф1).
- Сырьё/выход — durable `~/books/gu-zhenren/softsign-decl/` (правило 9): `softsign_probe_out.txt`
(отчёт харнесса), `adversarial-review.txt` (author≠reviewer прогон).
- Правило 10 (вскрытие единиц + 2-й путь счёта): каждый агрегат ниже сверен независимым `grep -oE`
по боевому выходу; A0-реимплементация харнесса сверена с реальным (unexported) `dstFormPresent`
in-package пробой — 0/29 расхождений — до порта на экспортные символы.
Четыре правила матчинга декл-окна (база-цельнословная не меняется — она уже ловит номинатив):
- **A0** — боевое: `declinedFormPresent` (mempostcheck.go:169-191), «ь» НЕ стрипается.
- **A1** — наивное: «ь» в реестр, на КАЖДЫЙ компонент, БЕЗ якоря (отвергнутое; для контроля вреда).
- **A2** — anchor-gated: мягкий стрип разрешён, если ДРУГОЙ компонент совпал ТОЧНО.
- **A3** — anchor-gated: мягкий стрип разрешён, если ДРУГОЙ компонент совпал по НОРМАЛЬНОМУ стему (⊇ A2).
## Цифры
### Разрыв реален, но КОНЦЕНТРИРОВАН и много-словный
29 из 147 dst несут мягкознаковое слово. Захват окон над A0 (occurrence-level):
| dst | слов | soft→stem | A0 | A3 | A3A0 | статус |
|---|---|---|---|---|---|---|
| Фан Юань | 2 | юань→юан | 324 | 508 | **+184** | TRUE (склонение хвоста «Юаня/Юаню/Юанем/Юане», якорь «фан» точный) |
| Винный червь | 2 | червь→черв | 46 | 113 | **+67** | TRUE (оба слова склонны: «Винного червя»; A2 промахивает ВСЕ 67) |
| ветвь Чи | 2 | ветвь→ветв | 0 | 3 | +3 | TRUE (soft в ГОЛОВЕ, якорь «чи» точный) |
| ветвь Фан | 2 | ветвь→ветв | 1 | 3 | +2 | TRUE |
| демонический путь | 2 | путь→пут | 1 | 2 | +1 | TRUE («демонического пути») |
| горная крепость | 2 | крепость→крепост | 0 | 1 | +1 | TRUE («горной крепости») |
| девять рангов | 2 | девять→девят | 1 | 2 | +1 | **МЯГКАЯ НЕТОЧНОСТЬ** (см. ниже) |
Итого A3A0 ≈ **259 окон**, 258 истинных + 1 мягкая. A2A0 = 189 (A2 промахивает 70 истинных
«Винного червя» и др. — нет ТОЧНОГО якоря → A2 хуже A3).
### Практический эффект — на ПОРЯДОК меньше 259, и число НЕ робастно
Пост-чек срабатывает ПО-ЧАНКОВО (наличие любой принятой формы в чанке), не по вхождениям. Частые
имена почти всегда имеют номинатив в том же чанке. «Склонён-ТОЛЬКО (номинатив отсутствует)» —
СИЛЬНО зависит от размера блока (2-й путь счёта, самопроверка поймала завышение):
| блок ~симв | Фан Юань | Винный червь | Мочэнь | Чилянь | ИТОГО/25 глав |
|---|---|---|---|---|---|
| 800 | 32 | 22 | 2 | 1 | 57 |
| 1500 | 8 | 16 | 1 | 1 | 26 |
| 3000 | 0 | 12 | 1 | 0 | 13 |
| **6000** | **0** | **6** | **1** | **0** | **7** |
| **12000** | **0** | **4** | **0** | **0** | **4** |
Боевой чанк ≈ 12k ТОКЕНОВ (~612k симв) → честный per-chunk промах = **~47 на 25 глав, почти весь —
«Винный червь»**; «Фан Юань» на реальном размере чанка → **0** (номинатив всегда рядом). Прежняя оценка
«~26» была артефактом блока 1.5k симв (меньше боевого чанка) — снята. ⚠ Это ПРОКСИ (не боевой чанкер;
faithful — через `tmctl export` границ чанков). Порядок величины (одноцифровой, один термин) робастен.
### A1 отвергнут корректно — вред ГЛОБАЛЬНЫЙ, книго-независимый
M4: `softSameStem("Синь","синим")=true`, `("Линь","линий")=true`, `("Тень","теней")=true` — стем
совпадает («син/лин/тен»). Голое «ь» в реестр поражает глобальный `SameStem`, а через него — весь путь
`declinedFormPresent`, т.е. и `Postcheck`, и `SpoilerLeaks`, в любой книге. Единственный функциональный
потребитель `SameStem``declinedFormPresent` (mempostcheck.go:181); `seeding.go:138` только
конструирует стеммер; `voice.go` его НЕ подключает.
## Adversarial-ревью (author≠reviewer) — что оно сломало
A3 **не закрывает** коллизию Синь/Линь — оно её **ПЕРЕНОСИТ** с одно-словного класса на форму
`[общий-титул] + [ь-фамилия]` (самая частая много-словная форма имени в жанре):
- **Перенос (структурно ВЕРНО, здесь НЕ реализовано):** гипотетический банк-термин «старейшина Синь»
под A3 ложно примет «старейшина синего» (титул «старейшина» — нормальный якорь, «синего»→«син»
мягко). В gu-zhenren этого НЕТ: 18 из 30 soft-строк — CJK-транслит (юан/шэн/чилян/мочэн), чьи
3-руновые стемы просто не русские слова. Чистый прогон — **транслит-везение корпуса, не свойство
гейта.** Форма-риска в банке есть («старейшина школы», «вождь четвёртого поколения»); реализуется в
книге с русско-коллизионной фамилией. (Проверка: «старейшины синеватый» ×1 в выходе есть, но
«синеватый»→«синеват»≠«син» — не сработало бы; точный «старейшина синего» — конструкт, не корпус.)
- **Числовой класс — системно и НЕ защищён (реально на корпусе):** каждый ь-финальный кардинал
(девять/десять/пять/шесть…) мягко сливается с ординалом/косвенной формой. В выходе: «пятого ранга»
×13, «шестого ранга» ×10, «девятого ранга» ×1 — поверхность 24+ вхождения; якорь («ранга») — общее
слово, гейт даёт **ноль защиты**. «девять рангов»~«девятого ранга» — та самая 1 реализованная мягкая
неточность. Класс растёт со счётом рангов (плотный в культивации).
- **Поправка по SpoilerLeaks:** мой тезис «A3 не трогает SpoilerLeaks» — неверно обоснован.
`declinedFormPresent` достижим из `SpoilerLeaks` (mempostcheck.go:254) → A3 его МЕНЯЕТ. Спасает не
«неприкосновенность», а то, что SpoilerLeaks — observability-only, не диспозиция (mempostcheck.go:241):
мягкий ложняк там = шум, не флип гейта. A3 всё же СТРОГО лучше A1 для SpoilerLeaks (закрывает
одно-словный глобальный яд), но не чист (много-словный титул+фамилия остаётся).
- **Ни один вариант не доминирует:** min-стем-гейт бесполезен («юан» и «син» оба 3 руны — не разделить);
tail-restricted (soft только на последнем компоненте) точнее здесь, но теряет «ветвь Чи/Фан» (голова
склоняется) и всё равно ловит хвост-фамилию; стоплист коллизий — хорош как ДОБАВКА, плох соло
(открытый список — форма, от которой `target-ru.txt:19` уже предостерегает); сид-перечисление — золото
для подписного канона, но не масштабируется на авто-майненный хвост.
## Вывод и рекомендация (на ратификацию, НЕ строить без слова владельца)
> Заострено после 2-го адверсариал-прогона (аудит кода+рекомендации). Код харнесса — TRUSTWORTHY
> (6/6 NO-BUG, 147 dst сверено с файлом). Рекомендация исправлена: §3 ниже НЕ «ноль действия».
1. **Разрыв реален, но мал:** ~47 ложных промахов/25 глав на реальном размере чанка, почти весь —
ОДИН термин «Винный червь» («Фан Юань» → 0 per-chunk). Числа окон код-верифицированы.
2. **Голое A3 НЕ рекомендуется:** переносит коллизию на титул+фамилию (риск в другой книге) и не
защищает числовой класс; чистота на gu-zhenren — транслит-везение (пара-зависимое доказательство).
3. **Стопгэп для finding-1 — сид-перечисление декл-форм для 12 ВИДИМЫХ мягких канон-имён**
(«Винный червь»; «Фан Юань» если важен SpoilerLeaks): `declForms` матчатся `containsWholeWord` ТОЧНО —
ноль стемминга, ноль коллизии, ноль правок Go; данные книжного канона в сиде — легитимная общность.
⚠ Честно: `decl.forms`РУКО-ПИСАНЫЙ сид ([memseed.go:89](../../backend/internal/membank/memseed.go#L89)),
майнер морфологию НЕ майнит (его «decl» = ОТВЕРГНУТЫЕ поверхности, miner_emit.go:60); генератора
склонений в Go нет. Значит для ВСЕГО мягкого класса это = ручной труд «142/142-null», который §3
и убивал → сид-перечень оправдан ТОЛЬКО как ограниченный стопгэп на горстку видимых имён, НЕ системно.
4. **Движковый anchor-gated матч — не «отложить» отмашкой, а ЗАГЕЙТИТЬ на корпус-замере** частоты
ложняков переноса ([титул]+[ь-фамилия]) и числового класса — они НЕ измерены (M4 = 3 руко-выбранные
пары, одна книга = предварительно, CLAUDE.md §4), а не опровергнуты. Форма, если строить — СЛОЙНАЯ
(tail-restricted + стоплист ь-кардиналов), данные в `target-ru.txt`, алгоритм generic; но ядро Go не
трогать, пока кросс-парный замер (≥2 пары) не оправдает.
5. Backend-действие сейчас: NB-коммент + регресс-гвоздь (`stemmer_test.go`,
`TestSoftSignNamesDoNotCollideWithCommonWords`) ОСТАЮТСЯ как страховка от наивного ре-адда «ь».
Гвоздь «Линь/линию» инертен — заменить на «Линь/линий» (M4 подтверждает: «линий»→«лин»).
6. **Долгий общий дом (НЕ существует сегодня):** майнер-морфология (наблюдать склонённые поверхности,
а не кодировать «ь») был бы пара-агностичен — но это ОТДЕЛЬНЫЙ механизм bank-autonomy, не бесплатный
и не «минер уже майнит» (ранняя формулировка была неверна — такого пути нет).
## Воспроизвести
```
cd eval/softsign-decl && ./build.sh <work-dir> HEAD
<work-dir>/softsign-decl/softsign-decl \
-bank ~/books/gu-zhenren/coldrun-a/BANK-FULL.tsv \
-output ~/books/gu-zhenren/acceptance/guzhenren-25ch-ru.txt \
-report ~/books/gu-zhenren/softsign-decl/softsign_probe_out.txt
```
Прогон ~135с (O(слова×термины×режимы)). go.mod/replace — вне репо; второго модуля в git не появляется.