# SOFTSIGN-DECL (finding-1) — отчёт оркестратору для совместного решения с владельцем > **✅ ПРИНЯТ И ЗАЛЕНДЕН; ОБА ВОПРОСА РЕШЕНЫ (оркестратор №9 + владелец, 02.08.2026, D39.76).** Спот-чеки приёмки: пин харнесса через rev-parse (build.sh:17) · счёт dst сверен (150 строк / 147 уник.) · durable-сырьё и оба адверсариал-прогона на месте · контрфактика «Синь/синим» бьётся с независимой проверкой фикс-пака. **Решения: (Q1) СТОПГЭП A — ДА**: сид-формы «Винный червь» И «Фан Юань» (цена нулевая, спойлер-точность протагониста важна); формы пишет бэкенд-сессия (детерминированная морфология, не вкус), подпись владельца обычным сид-циклом; сдвиг `memory_version` → штатный repin, перекупок нет; тем же касанием — гвоздь Линь/линию→Линь/линий и ПРЯМОЙ позитивный тест «Фан Юаню» через forms[] (закрывает PARTIAL ревью D39.75). **(Q2) finding-1 ЗАКРЫВАЕТСЯ на A; C (движковый anchor) — в ЗАГЕЙЧЕННЫЙ ТРИГГЕР**: реопен только при второй паре живьём, кросс-парный полигон-замер (перенос «[титул]+[ь-фамилия]» + числовой класс, ≥2 пары) = гейт любой правки ядра. Основание: A1 глобально вреден; anchor-gated сломан адверсариал-прогоном (переносит коллизию; чистота книги = транслит-везение); измеренный промах мал и локализован (~4–7 пер-чанк/25 глав, почти весь «Винный червь», «Фан Юань»=0). **Что:** исследование finding-1 (мягкознаковый декл-разрыв банк-пост-чека), отпочковавшегося от BANK_FIXPACK §а при лендинге D39.75 (бэклог-строка 91). **Кто/где:** бэкенд-сессия; по прямому указанию владельца замер проведён в eval-конвенции (`eval/softsign-decl/`, пин-харнесс, $0). **Дисциплина:** 2-й путь счёта · вскрытие единиц глазами · author≠reviewer ДВА прогона (дизайн + код/рекомендация). Владелец: «провести замеры, решать вместе с оркестратором» — отсюда этот отчёт. **Строить/править — по слову владельца; ядро Go этой сессией НЕ трогалось.** ## Вопрос `declinedFormPresent` не принимает склонённую мягкознаковую форму («Фан Юаню»~«Фан Юань»): стеммер §3 «ь» не стрипает. Наивное «добавить «ь» в `decl_suffix`» отвергнуто в fix-pack (глобальная коллизия «Синь/Линь»→«синий/линия»). Чем закрывать: (A) сид-перечень декл-форм · (C) движковый anchor-gated матч · (B) ничего. И — не ляжет ли решение книго/языко-зависимо в ЯДРО (вопрос владельца). ## Метод Харнесс `eval/softsign-decl/main.go` на БОЕВОМ стеммере (`lang.NewTargetStemmer`), `build.sh` пинит бэкенд коммитом (78b7b34) через `git archive`, `replace`-модуль вне репо — прецедент pkg7/minerharness. Корпус: банк `~/books/gu-zhenren/coldrun-a/BANK-FULL.tsv` (147 уник. dst) × боевой 25-глав-выход `acceptance/guzhenren-25ch-ru.txt` (37 480 слов). Сырьё+2 адверсариал-прогона — durable `~/books/gu-zhenren/softsign-decl/`. Четыре правила матчинга: A0 (боевое, «ь» не стрипается) · A1 (наивное глобальное «ь») · A2 (anchor=точный) · A3 (anchor=норм-стем). ## Находки (с исправлениями самопроверки — обе ошибки мои) 1. **Разрыв реален, но МАЛ.** Occurrence-level 259 окон (184 склонённых «Фан Юань» = Юаня 152/Юаню 19/Юанем 7/Юане 6 + 67 «Винного червя» + хвост). Но пост-чек срабатывает ПО-ЧАНКОВО: на реальном размере чанка (~1–2k токенов) честный промах = **~4–7 на 25 глав, почти весь — ОДИН термин «Винный червь»**; «Фан Юань» → **0 per-chunk** (номинатив всегда рядом). ⚠ Моё раннее «~26» было артефактом мелкого блока (1.5k симв) — снято 2-м путём (свип 800→12000 симв: 57→26→13→7→4). Число — прокси (не боевой чанкер). 2. **Код харнесса аудирован TRUSTWORTHY** (author≠reviewer, статик): 6/6 NO-BUG — `stemAug` доказуемо faithful (реестровые суффиксы все на гласную → ь-финал no-op под реальным реестром), якорь не лицензирует сам себя (`norm[k]=false ⟹ exact[k]=false`), `loadBankDst`=147 сверено с файлом (150 строк, 3 дубля dst). Числа окон код-верифицированы + воспроизведены 2-й Python-реализацией. 3. **A1 (наивное «ь») отвергнут корректно — вред ГЛОБАЛЬНЫЙ, книго-независимый.** M4: `softSameStem("Синь","синим")=true`, `("Линь","линий")=true`. Голое «ь» поражает глобальный `SameStem`, а через него весь путь `declinedFormPresent` → и Postcheck, и SpoilerLeaks, в любой книге. 4. **Adversarial-прогон 1 (дизайн) сломал A3:** anchor-gated НЕ закрывает коллизию — **ПЕРЕНОСИТ** её с одно-словного класса на форму `[титул]+[ь-фамилия]` (гипотетич. «старейшина Синь» ложно примет «старейшина синего»). В gu-zhenren 0 коллизий — **транслит-везение** (CJK-стемы юан/шэн не русские слова), НЕ свойство гейта → доказательство безопасности **пара-зависимо**. Числовой класс НЕ защищён реально на корпусе: «пятого ранга» ×13, «шестого ранга» ×10 — якорь «ранга» общий, гейт даёт ноль защиты. Поправка: A3 ТРОГАЕТ SpoilerLeaks (общий путь), спасает лишь observability-статус. 5. **Adversarial-прогон 2 (рекомендация) поймал мою противоречивость:** я звал сид-перечень «нулём действия», а он — РУЧНОЙ труд. Сверено по коду: `decl.forms` руко-писаны в сиде ([memseed.go:89](../../../backend/internal/membank/memseed.go#L89)→[memory.go:315](../../../backend/internal/membank/memory.go#L315)); майнер морфологию НЕ майнит (его «decl» = отвергнутые поверхности, miner_emit.go:60); генератора склонений в Go нет. Для ВСЕГО мягкого класса сид-перечень = «142/142-null», что §3 и убивал. ## Общность (ключевой вопрос владельца) — решение остаётся ВНЕ ядра - Рекомендуемый путь (A) — данные сида `decl.forms`, матч **generic** `containsWholeWord` ([mempostcheck.go:158](../../../backend/internal/membank/mempostcheck.go#L158)): **ноль строк Go**, новая пара кладёт свои формы в свой сид, Go не трогается → инвариант «пара, которой в репо нет, без правки Go» выполнен. Grep ядра `membank`/`stemmer` на книго/пара-ЛИТЕРАЛЫ и lang-ВЕТКИ — пусто (единственный хит — иллюстративный коммент-пример 方源→Фан Юань в `mempostcheck.go:128`, не ветка кода). - Движковый (C) ТРОНУЛ бы алгоритм `declinedFormPresent` (ядро membank) + «ь» в `target-ru.txt` (lang-данные). Алгоритм generic — архитектурно чисто ЕСЛИ строить; но его БЕЗОПАСНОСТЬ валидирована на одной паре → в ядро на одно-парном свидетельстве нельзя. Именно это и есть «плохое решение в ядре», которого владелец не хочет. ## Опции для решения | | Что | Плюсы | Минусы | |---|---|---|---| | **A** | Сид-перечень декл-форм 1–2 ВИДИМЫХ мягких канон-имён («Винный червь»; «Фан Юань» если важен SpoilerLeaks) | дёшево (~10 строк YAML), точный матч, ноль коллизии, **вне ядра**, закрывает ~весь измеренный промах | ручной труд; не масштабируется на хвост; per-book | | **B** | Ничего + NB-коммент/регресс-гвоздь (уже в HEAD) | ноль риска/работы | ~4–7 ложняков/25 глав остаются (у шумовой планки) | | **C** | Движковый СЛОЙНЫЙ (tail-restricted anchor + стоплист ь-кардиналов) | общий once-done, любая будущая книга бесплатно; данные в lang, алгоритм generic | трогает ядро; safety (перенос/числа) НЕ измерена (M4=3 пары, 1 книга); нужен кросс-парный гейт-замер ПРЕЖДЕ стройки | ## Рекомендация (на совместное решение) - **Сейчас: A (+B).** Сид-перечень «Винного червя» (+«Фан Юань» при нужде SpoilerLeaks) — закрывает измеренный промах вне ядра; NB-коммент + гвоздь остаются; поправить инертный гвоздь «Линь/линию» → «Линь/линий». В ядро — ничего. - **C — НЕ строить на одно-парном свидетельстве.** Если решаем закрывать системно, сперва ЗАКАЗАТЬ полигону кросс-парный корпус-замер частоты ложняков переноса ([титул]+[ь-фамилия]) и числового класса на ≥2 парах (zh→ru + ja→ru/en→ru) как ГЕЙТ; только положительный замер оправдывает правку ядра. - Честный исход-кандидат: **закрыть finding-1 на A, снять со строки 91**, C оставить как загейченный бэклог-триггер (не открытый долг). ## Что решить вместе с владельцем 1. Делаем стопгэп A? Кто пишет сид-формы (полигон / владелец канона)? 2. Заказываем кросс-парный гейт-замер под C — или закрываем finding-1 на A и C снимаем в загейченный триггер? ## Артефакты - `eval/softsign-decl/` — `main.go` · `build.sh` · `README.md` (методика+цифры+пределы, исправлен). - `~/books/gu-zhenren/softsign-decl/` — `softsign_probe_out.txt` · `adversarial-review.txt` (дизайн) · `code-recommendation-audit.txt` (код+рекомендация). - backend HEAD (D39.75): NB-коммент `target-ru.txt:231-237` · гвозди `stemmer_test.go`/`memdecl_test.go`. ## Честные пределы Одна книга (gu-zhenren zh→ru); M4 = 3 руко-выбранные пары; per-chunk промах — прокси (не боевой чанкер, faithful — через `tmctl export`); чистота A3 на корпусе — транслит-везение, НЕ доказательство общей безопасности. Числа окон код-верифицированы и 2-м путём; интерпретации (перенос/числовой класс) — предварительны по CLAUDE.md §4 до вебновелл-кросс-парного среза.