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

13 KiB
Raw Blame History

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 сломан адверсариал-прогоном (переносит коллизию; чистота книги = транслит-везение); измеренный промах мал и локализован (~47 пер-чанк/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 «Винного червя» + хвост). Но пост-чек срабатывает ПО-ЧАНКОВО: на реальном размере чанка (~12k токенов) честный промах = ~47 на 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:89memory.go:315); майнер морфологию НЕ майнит (его «decl» = отвергнутые поверхности, miner_emit.go:60); генератора склонений в Go нет. Для ВСЕГО мягкого класса сид-перечень = «142/142-null», что §3 и убивал.

Общность (ключевой вопрос владельца) — решение остаётся ВНЕ ядра

  • Рекомендуемый путь (A) — данные сида decl.forms, матч generic containsWholeWord (mempostcheck.go:158): ноль строк Go, новая пара кладёт свои формы в свой сид, Go не трогается → инвариант «пара, которой в репо нет, без правки Go» выполнен. Grep ядра membank/stemmer на книго/пара-ЛИТЕРАЛЫ и lang-ВЕТКИ — пусто (единственный хит — иллюстративный коммент-пример 方源→Фан Юань в mempostcheck.go:128, не ветка кода).
  • Движковый (C) ТРОНУЛ бы алгоритм declinedFormPresent (ядро membank) + «ь» в target-ru.txt (lang-данные). Алгоритм generic — архитектурно чисто ЕСЛИ строить; но его БЕЗОПАСНОСТЬ валидирована на одной паре → в ядро на одно-парном свидетельстве нельзя. Именно это и есть «плохое решение в ядре», которого владелец не хочет.

Опции для решения

Что Плюсы Минусы
A Сид-перечень декл-форм 12 ВИДИМЫХ мягких канон-имён («Винный червь»; «Фан Юань» если важен SpoilerLeaks) дёшево (~10 строк YAML), точный матч, ноль коллизии, вне ядра, закрывает ~весь измеренный промах ручной труд; не масштабируется на хвост; per-book
B Ничего + NB-коммент/регресс-гвоздь (уже в HEAD) ноль риска/работы ~47 ложняков/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 до вебновелл-кросс-парного среза.