136 lines
15 KiB
Markdown
136 lines
15 KiB
Markdown
# 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 | A3−A0 | статус |
|
||
|---|---|---|---|---|---|---|
|
||
| Фан Юань | 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 | **МЯГКАЯ НЕТОЧНОСТЬ** (см. ниже) |
|
||
|
||
Итого A3−A0 ≈ **259 окон**, 258 истинных + 1 мягкая. A2−A0 = 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** |
|
||
|
||
Боевой чанк ≈ 1–2k ТОКЕНОВ (~6–12k симв) → честный per-chunk промах = **~4–7 на 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. **Разрыв реален, но мал:** ~4–7 ложных промахов/25 глав на реальном размере чанка, почти весь —
|
||
ОДИН термин «Винный червь» («Фан Юань» → 0 per-chunk). Числа окон код-верифицированы.
|
||
2. **Голое A3 НЕ рекомендуется:** переносит коллизию на титул+фамилию (риск в другой книге) и не
|
||
защищает числовой класс; чистота на gu-zhenren — транслит-везение (пара-зависимое доказательство).
|
||
3. **Стопгэп для finding-1 — сид-перечисление декл-форм для 1–2 ВИДИМЫХ мягких канон-имён**
|
||
(«Винный червь»; «Фан Юань» если важен 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 не появляется.
|