textmachine/docs/archive/reports/PACK14_GENERALITY_REPORT_2026-07-24.md

37 KiB
Raw Blame History

PACK-14 «генеральность-пасс» — приёмочный отчёт (2026-07-24)

Ревью-шапка оркестратора №7 (24.07, приёмка исполнением, два воркфлоу: 11 линз ~970k ток. + доприёмка дельты 4 линзы; 0 блокеров). Байт-точность КАЖДОГО переноса независимо сверена против git HEAD (refusal 12/12 · injection 6/6 с ведущими пробелами · dc-регексы · санитайзер · CJK-числительные · фонотактика · форманты — ноль расхождений); парити EXACT свежими -count=1 прогонами; golden байт-нетронут; тесты не ослаблены (2 удалённых ассерта — законные замены). Поправки к телу отчёта: (а) Приложение A — ведро «distinct/matches (8 refs)» = греп-артефакт: все 8 в комментариях, кодовых ссылок 0; заголовок «miner→membank 35» реально 32 полных вхождений / 14 кодовых; остальные вёдра точны, вывод «хойст первым» НЕ задет; (б) ёфикатор = 38 слов (строка «40 ru-слов» — обсчёт в прозе); (в) свип-47 воспроизводится как 41 (точный класс) + 6 строк ё/кана (класс сессии был шире заявленного регекса), скрытых пар-данных нет; класс «пунктуация-сепараторы» в 47 не представлен (перенос из классификации-100). Дельта доприёмки принята (generic-Палладий по аддендуму, c2-segmentation, README-пути, want-list magnitude, packAlgoVersion v2). Остаток в пак-15 (зафиксирован): тесты unknown-category-толерантности и required-fail Палладия · fail-loud оверлея уровнем выше (пропавший overlayRoot/чужой подкаталог/категория-опечатка в overlay-файле — тихие) · семантика override unionStringMap · isRuTarget/'ru'-швы · empty-probe гард lintMagnitudeScale · дуп терминаторов chunker/coverage · . Прод-оверлей 古月 подключён оркестратором в оба стендовых book.yaml (rerun2).

Бэкенд-сессия. Источник: docs/BACKEND_GENERALITY_PASS_SESSION_PROMPT.md (9 пунктов) + два аддендума оркестратора (A: ingest 章节節回+CJK-числительные → та же ед. точки истины, что у чанкера; B: форманты 等/转/阶). Норматив: docs/architecture/12-go-style-notes.md §0. Перенос ДАННЫХ, не редизайн алгоритмов. Сессия НЕ коммитит.

Вердикт: жёсткий инвариант выполнен

  • golden БАЙТ-ИДЕНТИЧЕНtestdata/golden/capture.golden не тронут (git diff пуст). Сильнее допущенного «version-only»: у golden-книги нет langpack (ja→ru, langpack_root не задан → pack==nil), поэтому packVersion()=="" и её снапшот НЕ двигается ни от одного НОВОГО langpack-файла; TestGolden сверяет capture побайтно и зелёный.
  • майнер-парити EXACTTM_MINER_PARITY=1: n=13618 catastrophe{方源:0 蛊:1 蛊师:2 古月:22} recall@proposed=0.9655 — тождественно дореформенному (вкл. 古月-механику через книго-расширение).
  • go build/vet/test -race зелёные (весь модуль, вкл. новый internal/lang).

Ключевой факт, определивший архитектуру

golden — ja→ru книга БЕЗ langpack (pack==nil), но она живьём: (1) флагает hard_refusal (RU «Не могу помочь»), (2) инъектит русские заголовки глоссария в wire (16×), (3) режет главы 第X章, (4) style_flags=0. Значит рефузал-паттерны, CJK-числительные глав и →ru-инъекцию НЕЛЬЗЯ держать в книжном паке (nil для golden). request_hash фолдит snapshotID (render.go) — любое движение снапшота golden-книги сдвинуло бы wire. →

Два дома данных (правило, выдержавшее «100 языков» линзу владельца)

  1. configs/langpacks/<src>|<pair>/ + книжный overlay — пер-исходник / пер-пара / пер-книга данные. Добавить язык = положить каталог, без перекомпиляции; убрать = удалить каталог; загрузчик падает ГРОМКО, называя файл (никогда тихо-пусто). Сюда: item 1 (surnames/古月), 5 (терминаторы, Палладий- фонотактика), 6 (DC-таблицы), addB (форманты). Overlay: добавить/убрать КНИГУ = ±один каталог; DC-таблицы OPT-IN (убрать файл → чекеры инертны, не болтаются).
  2. internal/lang/data/ (go:embed, секционировано по языку/таргету) — данные, нужные движку БЕЗ книжного пака (golden доказал: рефузал, CJK-нарезка, →ru-инъекция — все без langpack). Добавить язык = добавить секцию в один data-файл; убрать = удалить секцию. Перекомпиляция — приемлемо: это инженерные КОНСТАНТЫ (версионируются с бинарём, как код), а байт-точность no-pack golden запрещает фолдить их в книжный пак. Сюда: item 3 (refusal.txt), 4+addA (cjk-section.txt), 2 (injection.txt), sourceAbbrevs (sentence-abbrev.txt).

По пунктам (что сделано, чем доказана нейтральность)

1. 古月 ВОН из общего zh-langpack. Удалён из configs/langpacks/zh/surnames-compound.txt. Механизм — книго-скоупный overlay: новое поле book.yaml: langpack_extend (каталог той же раскладки), lang.LoadWithOverlay делает АДДИТИВНЫЙ union (множества дополняются, слайсы append; overlay ничего не удаляет), байты overlay фолдятся в Version() (правка книжного канона = громкий --resnapshot ТОЛЬКО этой книги). Парити: testLangPack грузит testdata/langpack-overlay-guzhenren → эффективный пак = старый (base {古月}) → {古月:22} EXACT. Стенд- overlay создан /home/ubuntu/books/gu-zhenren/langpack-extend/zh/surnames-compound.txt. Прод-book.yaml — см. «Хвосты владельцу».

2. Инъекция-тексты → таргет-данные, с гейтом. glossaryBlockHeader/editorConstraintHeader/маркер ⟨проверить⟩/3 gender-ноты вынесены в internal/lang/data/injection.txt (target-keyed, lang.InjectionTextsFor), рендереры гейтятся на tx.HasData() — →en книга получит ПУСТО, не русский блок (это и есть фикс утечки). Значимые ведущие пробелы ( (муж.…, ⟨проверить⟩) сохранены дословно (парсер НЕ триммит value). renderFormatVersion НЕ тронут → снапшот golden не двигается → wire байт-идентичен (проверено golden). Langpack-ФАЙЛ (а не embedded) отложен: golden без пака потребовал бы target-loader вне book-langpack_root, что сдвинуло бы снапшот golden — запрещено инвариантом.

3. Рефузал-блэклист → универсальные embedded-данные. internal/lang/data/refusal.txt (секции en/ru/ja/zh

  • маркер), disposition.go строит refusalRE из lang.RefusalPatterns(). Байт-в-байт 12 паттернов в том же порядке (сверено скриптом). golden флагает hard_refusal тождественно.

4 + addendum-A. CJK-числительные — ОДНА точка истины. internal/lang/data/cjk-section.txt (digit/unit значения, zero, chapter_unit) — читают И чанкер (isHeadingNumeral/cjkSectionDigit/cjkSectionUnit, путь заголовков, nil для golden), И ingest (chapterNumeralRE строится из HeadingNumeralClass(), detectChapterUnit итерит ChapterUnitOrdered — авторский порядок сохранён для детерминированного тай-брейка). Устранён ingest↔chunker байт-дубль. golden режет 第X章 тождественно (ingest живёт для golden — верифицировано TestGolden). sourceAbbrevsinternal/lang/data/sentence-abbrev.txt (секции по ИСХОДНИКУ, en=29 токенов); чанкер потребляет секцию en (как и раньше — универсально; исходник-параметризация сплиттера = мелкий отложенный шаг, чтобы не трогать 18 колл-сайтов SplitChunks на не-приёмочном пути).

5. Терминаторы 。!? + Палладий-фонотактика. zh/sentence-terminator.txt (p.SentenceTerminator, splitMinerSentences); фонотактика jqx/ретрофлексы/ü-финалы → zh-ru/palladius-phonotactics.txt (PalladiusRetroflex/VFinal/VFinalInitial), l/n-исключение стало данными vfinal_initial. Майнер-only, парити EXACT.

6. DC-таблицы → пар-данные, регексы = алгоритм. dcCNNum+dcRuHourWord+dcRegisterNegList → OPTIONAL zh-ru/dc-checkers.txt (lang.DCCheckerData), прокинуто через cheapGateConfig (nil пак → пусто → чекеры 0 → golden style_flags=0). ДЕТЕКТ-регексы (时辰/千万//терем-паттерны) остались как пар-скоупный алгоритм чекера (§12.2 — «данные наружу, алгоритм остаётся»).

7. Калибровка (config/pipeline.go). Только пере-документирование (числа НЕ тронуты): дефолты 1797/3200/ 1.1978/0.3852 помечены как «zh-ru пар-калибровка = последний generic-fallback», шиппинг-конфиги (c1/армы) ставят блок ЯВНО (пар-конфиг = источник истины). Релокация в langpack ОТВЕРГНУТА (была бы мёртвой для всех живых путей: конфиги ставят явно, у golden нет langpack; least-mechanism §12.1). Числа держатся EXACT: no-langpack книга (golden) чанкается на этом fallback — пере-выведенное число сдвинуло бы её границы→wire.

addendum-B. Форманты 等/转/阶. zh/title-formant.txt (p.TitleFormant, formantType). Рядом с TopoSuffix (сосед уже data-driven). Майнер-only, парити EXACT.

9. Промпты → prompts/zh-ru/. backend/prompts/{translator,editor,editor-mono,judge-selector}.mdprompts/zh-ru/ (git mv, БАЙТЫ не тронуты — снапшот фолдит PromptSHA256 от СОДЕРЖИМОГО, не пути). Обновлены 5 шиппинг-конфигов (../prompts/zh-ru/…) + 4 тест-ссылки на реальные файлы. Тесты, грузящие реальные c1/арм-конфиги (prompt_pack_test, echo_mine_test), зелёные.

Item 8 — свип-добор (полный grep non-test .go, построчно)

Метод: изолирован non-comment grep [\x{4e00}-\x{9fff}]|[а-яА-Я] (строчные комментарии срезаны). Было 133 дата-литерала → перенесено 33 (items 16+addA/B) → осталось 100, классификация:

  • SQL-DDL комментарии (migrate.go, 26): русская документация ВНУТРИ raw-string схемы. Не пар-данные, 0 поведения. OK / вне скоупа (это перевод комментариев, отдельная забота).
  • Диагностика/сообщения-флагов (~11): book.go:188(Р7), models.go:184(Р4)/231, pipeline.go:411(Р2), checkers_zh_ru.go:63/119/124/200, cheapgates.go:451/294/319, checkers:285 — operator-диагностика / observability-строки (англ.-первичные, цитируют матч для человека). НЕ wire, НЕ пар-данные. OK.
  • Пар-скоупный ДЕТЕКТ-алгоритм (регексы), §12.2 (данные уже вынесены, регекс остаётся): checkers_zh_ru.go:34/38/101/102/103/117/118/122/175/178/187/283 (DC1/DC2/percent/broken-word детект); sanitizer.go:213/215/217/219/240/251/362 (ru-таргет editorial-preamble/note/invalid-sign детект). OK.
  • Алгоритм-инвариантные литералы (OK-generic): chunker.go:222 (класс СЕПАРАТОРОВ пунктуации :、,。…); memnorm.go:180-181 (ё→е фолд ключа памяти, 1-символьное правило); memseed.go:570 (ー/・ в кана-ридингах, ja-норм); miner_palladius.go:71 (ъ-drop перед сегментацией). ingest.go:128 — мой новый регекс, остался литералом (кандидат — см. ниже).
  • Ратифицированный DEFER (НЕ тронут): cheapgates.go:361 translit-interj блоклист (ара-ара/маа/…) — D39.16 явно (ja-филлеры, мис-кей-ловушка). оставлен.

Кандидаты СЛЕДУЮЩЕГО пака (тот же класс, НЕ в подтверждённом фикс-листе — решение оркестратора)

Одного класса с перенесёнными, но не названы в 9 пунктах/аддендумах; байт-нейтральны (golden фаерит 0), но переносить их сейчас = расширять скоуп сверх санкционированного + повтор D39.16-концерна «живой пара-агностик». Флагаю для след. пака:

  • cheapgates.go:265-276 yofikator homograph-whitelist (40 ru-слов) — ru-таргет readability-данные (класс DC6). Нужен ru-TARGET langpack-слот (сейчас нет).
  • cheapgates.go:459-619 万/億 magnitude-gate — zh-исходник числ-значения (万萬億亿兆 — ДРУГОЙ инвентарь, не section) + ru-стемы (тысяч/миллион/…). Кандидат: расширить lang.CJKSection категорией magnitude + ru-слот.
  • sanitizer.go ru-фрагменты — data-экстракция лексем-детекторов в ru-таргет-слот (регексы = алгоритм).
  • ingest.go:128 — маркер главы; можно добавить в cjk-section.txt рядом с chapter_unit (1 руна).

«100 языков» линза (ответ на вопрос владельца)

  • Добавить пару: положить configs/langpacks/<src>/(11 required src-файлов)+<src>-<tgt>/(2 pair + опц. heading/dc-checkers) + book.yaml. НИ строки под internal/pipeline. Загрузчик fail-loud называет отсутствующий файл. Смелл: title-formant/surnames-* осмысленны только для CJK-исходника (весь минер CJK-центричен — ПРЕ-существующее свойство, не ухудшено; для не-CJK исходника миннер сам подлежит переосмыслению).
  • Добавить таргет: секция в injection.txt/refusal.txt — правка ДАННЫХ + перекомпиляция (go:embed). Оправдано: инженерные универсалии/таргет-генерики.
  • Убрать язык: удалить каталог пака / секцию embedded-файла — ничего не болтается (DC opt-in инертен; overlay опционален; загрузчик громкий). Тесты не ломаются на удалении пары (fail-loud по требованию).

Хвосты владельцу (операционка, вне зоны backend/)

  • Прод-book.yaml gu-zhenren (стенд rerun2/book.yaml, book-mistral.yaml): добавить langpack_extend: /home/ubuntu/books/gu-zhenren/langpack-extend — иначе прод-майнинг потеряет 古月 (overlay- каталог уже создан на стенде). Не тронул сам: зона книжных данных владельца + закрытый эксперимент rerun2. Любой ре-ран и так --resnapshot (langpack Version() сдвинут новыми файлами).
  • Стенд pipeline-конфиги (rerun2/pipeline-*.yaml) и docs, ссылающиеся на старый путь backend/prompts/… (истор. записи в archive/experiments) — обновить путь на prompts/zh-ru/… при следующем касании (зона оркестратора/владельца).

Само-проверка (мандат 12.07) + адверсариальный 4-линзовый ревью

Ревью ИСПОЛНЕНИЕМ: каждый item верифицирован golden+parity сразу после кода (не в конце). Линзы: байт-точность / парити / общность-ja-ru / масштаб-100-языков (доп. линза владельца).

Итог адверсариального 4-линзового ревью (воркфлоу, 4 независимых агента, 289k токенов)

  • БАЙТ-ТОЧНОСТЬ: CLEAN — не опровергнуто. Агент независимо байт-сверил КАЖДЫЙ перенесённый литерал против git HEAD: injection (6 значений вкл. ведущие пробелы: unverified_marker len=13, gender len=31), refusal (12 паттернов, joined_equal=True), cjk-section (digit/unit/zero MATCH, chapter_unit ПОРЯДОК [章 节 節 回], heading-класс symmetric-diff пуст), sentence-abbrev (en=29 exact), dc-checkers (11+9+6 rows match), Палладий- фонотактика/форманты/терминаторы MATCH, промпты = чистые rename (0 байт). golden capture пуст в git, TestGolden байт-сверка PASS.
  • МАЙНЕР-ПАРИТИ: CLEAN — не опровергнуто (свежий -count=1). Overlay-union доказан аддитивным (base古月 {古月} = старый 16-сет); l/n-исключение фонотактики логически тождественно старому switch.
  • ОБЩНОСТЬ: CONCERNS — 1 MINOR + 3 NOTE (ниже, все либо пофикшены, либо документированы).
  • МАСШТАБ-100-ЯЗЫКОВ: CONCERNS — 1 MAJOR (пофикшен) + 3 MINOR/NOTE (документированы).

Пофикшено по ревью (пост-ревью, верифицировано golden+parity):

  • MAJOR (масштаб): LoadWithOverlay ТИХО игнорировал overlay-файл вне манифеста (опечатка surname-compound.txt или книжный heading.txt в overlay → приватный канон не доезжает до майнера, recall падает БЕЗ сигнала). Фикс: overlayDirFiles сканирует overlay-каталоги и падает громко, называя неожиданный файл. + тест (misnamed-overlay fails loud). Восстанавливает fail-loud-гарантию на масштабе десятков книг-overlay.
  • NOTE (масштаб): refusal.txt — комментарий-заголовки # --- xx --- вводили в заблуждение («удали секцию = отключи детект для пары»). На деле RefusalPatterns() читает плоско, ВСЕ паттерны фаерят для ВСЕХ книг. Комментарий переписан: секции ОРГАНИЗАЦИОННЫЕ; удаление триммит УНИВЕРСАЛЬНЫЙ сет (только #-строки — байты паттернов, golden не сдвинут).
  • MINOR (масштаб): header srcFiles — уточнён скоуп: «drop a directory» верно ВНУТРИ zh-family name-miner морфо-схемы; другое семейство исходников требует новых Pack-полей (не просто каталог).

Документированные остатки (не фикшу — конфликт с инвариантом/мандатом/пре-существующее):

  • MINOR (общность): калибровка = ТИХИЙ zh-ru дефолт при пропуске блока (ломает fail-loud). НЕ фиксится: item 7 предписал «оставить механизм», а golden (ja→ru) ПРОПУСКАЕТ блок и опирается на этот fallback — падение громко на пропуске сломало бы golden. Тайтен возможен лишь когда golden сам явно проставит сегментацию (будущий пак, который и так пере-снимет golden).
  • NOTE (общность+масштаб): sourceAbbrevs захардкожен на en — исходник-параметризация сплиттера отложена (18 колл-сайтов SplitChunks, не-приёмочный путь). Секция не-en = мёртвые данные до треда sourceLang.
  • NOTE (общность+масштаб): DC2 lintMagnitudeScale держит НЕЗАВИСИМЫЙ CJK-числ-парсер (万/億/兆), дублирующий lang.CJKSection — пре-существующий, self-gating (инертен на не-zh), не тронут этим диффом. Кандидат след. пака (в списке item-8).
  • NOTE (общность): DC ДЕТЕКТ-регексы пар-скоупны в Go (§12.2 by-design: данные вынесены, детект-алгоритм остаётся; self-gating → добавление ПАРЫ не требует Go, только СВОИ чекеры пары — да).
  • NOTE (масштаб): двух-домовая когезия — шов. →ru target-wire-text в ДВУХ домах: injection (embedded, recompile) vs heading.txt «Глава {n}» (pack, data-drop). Причина — байт-точность no-pack golden: то, что golden НУЖНО без пака → embedded; пар-гейтнутое, что golden НЕ трогает → pack. Честный шов, задокументирован; унификация потребовала бы target-loader вне book-langpack_root (сдвиг снапшота golden — запрещён). + сиблинг target/source-данные ещё в Go (cheapgates ё-политика/оному/magnitude) — граница data/algorithm проведена неравномерно (кандидаты item-8).

Финальная верификация (пост-фиксы): go build/vet clean; TM_MINER_PARITY=1 go test -race ./... весь зелёный; парити n=13618 {方源:0 蛊:1 蛊师:2 古月:22} EXACT; git status golden capture пуст (байт-идентичен).


ДОБАВКА: полный data-out чекеров/гейтов/санитайзера (директива владельца + оркестратора)

Триггер: владелец (после core-пака) — «магические названия остались в checkers_zh_ru.go/checkers_pack13_test.go; что при +100 языках? это мелкие примеры, ты всё отловил?». Честный ответ: НЕТ — core-пак вынес LOOKUP-таблицы, но оставил DETECTION-регексы + сиблинг-гейты как «алгоритм/DEFER» (слишком мягко для планки 100 языков). Решение оркестратора: доводи data-out, структуру НЕ трогай (сплит — след. пак с форм-фиксами). Выбор владельца: «Full: все паттерны → данные, Go generic» + «тесты грузят фикстуры из пака».

Внешняя сверка (харнесы /home/ubuntu/projects/tmp, 5-агентный воркфлоу)

  • crush (Charm, Go AI-агент, ~300 .go) — ~71 фокус-пакет, один каталог = один концерн; провайдеры = ДАННЫЕ (внешний SDK + JSON-каталог, 0 per-provider Go); промпты = embedded .md; пост-обработка РАЗНЕСЕНА по фокус-пакетам, НЕ «checkers-куча». Сильное свидетельство против нашей 38-файловой кучи И за «volatile-ось = данные».
  • anthropic/openai-go — плоский root = кодоген-артефакт (не образец); но ручные части = МАЛЫЕ single-purpose пакеты (apijson/apiquery/…).
  • GalTransl/AiNiee (домен, что мы зеркалим) — валидируют data-мандат (глоссарий TSV, промпты per-язык, WHICH-чеки = config-список, control-codes regex.json = ДАННЫЕ). НО обе ТЕКУТ языком в ТЕЛА чекеров (残留日文/独白男他 gated on target_lang; per-lang Unicode-регексы) — ровно наша утечка; AiNiee regex.json = чистый контр-пример = наш фикс.

Что вынесено (Full data-out)

checkers_zh_ru.gocheckers.go, ПОЛНОСТЬЮ пар-агностичен. DC1/DC2/percent DETECTION-паттерны (shichen_re/ru_hours_re/qianwan_*/shushiwan_*/cheng_re/decimal_fraction_re/percent_word) → пар-пак dc-checkers.txt (pattern<TAB>key<TAB>value, verbatim); компилируются ОДИН раз в compileCheckers*dcCheckers спек, живёт в r.checkers (openRunner) → cheapGateConfig. Target-general (broken-word -йть) → embedded internal/lang/data/target-ru.txt. dc*-символы стали ключами данных; чекеры — методы generic-спека, nil-инертны для no-pack. cheapgates.go: yofikator homograph-whitelist (38 слов) → target-ru yo_homograph; 万億 magnitude — CJK-парсер (digit/unit/magnitude 万萬億亿兆) ДЕДУП в lang.CJKSection (закрыл reviewer-NOTE о дубле), ru-стемы (тысяч/миллион/…) → target-ru magnitude_stem. lintYofikation/lintNumberMagnitude — методы спека. Оставлено (документировано): ё↔е фолд (1-символьная орфография = алгоритм), dialogue-dash (пунктуация), translit-interj ара-ара/… = РАТИФИЦИРОВАННЫЙ DEFER (D39.16, prompt NOT-do — единственный ru-output-блоклист, придержан). sanitizer.go: 4 preamble + trailing-note + edit-meta + invalid-sign регексы → target-ru (извлечены из исходника СКРИПТОМ, round-trip byte-match — не перепечатка). Санитайзер уже isRuTarget-гейтнут → паттерны = ru-target данные, загружаются ruSanitizer = lang.TargetChecksFor("ru"); strip/detect-АЛГОРИТМ остаётся. «ru»-ключ зеркалит гейт (тред таргета = follow-up, как sourceAbbrevs). Тесты грузят из пака: testCheckers(t) = compileCheckers(pack.DCCheckers, TargetChecksFor("ru")); checkers/cheapgates-фикстуры прогоняют АЛГОРИТМ над паттернами пака — 0 дублирования пар-значений (входные примеры-сценарии остаются, §0.3 легитимно).

Дома по ГЕЙТИНГУ: source-gated пара-чекеры (DC1/DC2/percent, нужен zh-исходник) → пар-пак (nil для golden→инертны); target-general (register/broken/yofikator/magnitude-стемы/sanitizer, бегут на любом →ru) → embedded target-ru (нужны no-pack golden'у); source-CJK (magnitude-руны) → embedded cjk-section.

Байт-точность (пост-каждый-инкремент): golden БАЙТ-ИДЕНТИЧЕН (capture.golden не тронут — вкл. ch6, где санитайзер СРЕЗАЕТ ru-преамбулу → доказано, что паттерны из данных = те же байты); парити EXACT n=13618 {方源:0 蛊:1 蛊师:2 古月:22}; -race весь зелёный. Свип: 100→47 остаток (26 SQL-коммент migrate.go · flag-МESSAGE-диагностики checkers/cheapgates · 1-символьные фолды ё→е/ъ/kana · пунктуация-сепараторы · translit-DEFER · -маркер ingest — кандидат). Все классифицированы/легитимны.

Приложение A — карта связности подсистем (измерено grep'ом, вкл. тесты) — ДЛЯ ПРОМТА СЛЕД. ПАКА

Кандидаты-пакеты и их файлы: miner (miner*.go, mining.go — 8) · membank (memory/memnorm/mempostcheck/memseed/seeding — 5) · chunk (chunker/ingest — 2) · checks (cheapgates/checkers/sanitizer/coverage/quality/regressionguard — 6). Драйвер (runner/bookrun/waverun/wave/stagerun/chunkrun/resume) + инфра (snapshot/render/export/status/banknote/disposition/escalation) = композит-корень.

Кто ссылается ВНУТРЬ каждого (non-test · TEST):

  • miner ← non-test: runner:2, waverun:2, seeding:2 (узко!) · test: miner_test:63, miner_parity:7, seedlint:4, waverun:2.
  • membank ← non-test: waverun:18, wave:14, runner:13, snapshot:13, +многие (горячий путь) · test: memory:78, memseed:54, memnorm:38.
  • chunk ← non-test: waverun:12, wave:8, runner:5, status:5, stagerun:5, memseed:4 · test: chunker:35, ingest_encoding:28, ingest:23.
  • checks ← non-test: chunkrun:17, waverun:16, status:16, export:9, disposition:9 · test: sanitizer:90, coverage:29, regressionguard:19, cheapgates:15.

Латеральная связность — НЕ «ноль» (уточнение к survey «star topology»): есть ОБЩИЙ СУБСТРАТ, который надо ХОЙСТНУТЬ ПЕРВЫМ, иначе сплит потечёт:

  • miner → membank: 35 refs, но это ШАРЕД-утилиты, не membank-API: normalizeSourceKey@memnorm (12 — текст-нормализация, общая для майнера И банка), loadGlossarySeed/seedTerm/seedAlias/seedFile@memseed (9 — майнер читает СИД как GT/entity-guard), runesEqual@mempostcheck (3), distinct/matches@memory (8 — мелкие дженерик-хелперы).
  • membank → chunk: 7 (Chunk-тип), checks → membank: 19 (memoryEntry/pickedEntry/tokenizeCyrillic), chunk/miner → checks: 6+6.

Вывод для сплита (порядок): (1) ХОЙСТ шаред-базы ПЕРЕД подсистемами — Chunk/MinerChunk value-типы + текст-нормализация (normalizeSourceKey/runesEqual/tokenizeCyrillic) + сид-типы (SeedTerm/loadGlossarySeed) в базовый пакет (напр. internal/pipeline/model + internal/text); (2) затем miner (самый узкий: 6 внешних не-тест ссылок, импортит только lang+store+base) → checks (чистые ф-ии над строками, импортят config+lang+base) → membank → chunk. Драйвер импортит всё (композит-корень, как crush internal/agent). Форм-фиксы оркестратора (Export/RequestHash/resolveChunkState) едут в тот же пак — golden ревьюится ОДНИМ слоем.

Приложение B — предлагаемая экспорт-поверхность (что капитализируется / что прячется)

  • internal/text (база): NormalizeSourceKey, RunesEqual, TokenizeCyrillic. (сейчас memnorm/mempostcheck; общие для miner+membank+checks).
  • internal/pipeline/model (база): Chunk, MinerChunk, SegBudget, Document (value-типы, вокабуляр).
  • miner: ЭКСПОРТ MineBank, MinerConfig, MinedTerm, Contrast, LoadContrast; ПРЯЧЕТ mineDetect/proposeAliasEdges/buildPalladiusCyrSyllables/patternCandidates/emissionEligible. Импорт: lang, store, text, model.
  • membank: ЭКСПОРТ MemoryBank, Select, Version, BaseVersion, MemoryEntry, инъекц-рендереры; ПРЯЧЕТ pickedEntry/Aho-Corasick/suppressContained. Импорт: lang, store, text.
  • chunk: ЭКСПОРТ SplitChunks, Ingest, IngestEncoded; ПРЯЧЕТ chapterDraftChunks/packSentences/splitSourceSentences. Импорт: lang, model.
  • checks: ЭКСПОРТ RunCheapGates(+CheapGateConfig/CheapGateResult), SanitizeOutput(+SanitizerResult), CompileCheckers(+Checkers); ПРЯЧЕТ lint*-методы/dcCheckers-внутренности. Импорт: config, lang, text.

ДОПРИЁМОЧНАЯ ДЕЛЬТА (лендинг-блокер оркестратора, 24.07)

(1) ОБЯЗАТЕЛЬНО — аддендум parsePalladius ВЫПОЛНЕН. (а) generic-парсер parseCategoryRowsmap[категория]map[key]value (3-field key→cyr, 2-field key→"" set-member); НЕТ per-category switch, незнакомая категория ≠ ошибка парсера. (б) ОДИН типизированный Palladius-struct (Initials/Finals/YW/SpecialI + Retroflex/VFinal/VFinalInitial) вместо 4-картежа + 7 параллельных Pack-полей → Pack.Palladius Palladius. (в) required-категории валидирует ПОТРЕБИТЕЛЬ (validate()), не парсер. Удалены parsePalladius+parsePalladiusPhonotactics; assignPair/mergePair схлопнуты в parse+merge (оба пар-файла через generic-путь, union нил-сейф через newPalladius()); потребители (miner_palladius.go, langpack_test.go) обновлены. Hash-нейтрально (байты .txt не тронуты); packAlgoVersion v1→v2 (схемо-изменение по политике константы — выбрал БАМП; сдвиг Version() = version-only, golden без пака не тронут).

(2) Хвосты: pipeline-c2.yaml — явный segmentation-блок (1797/3200/1.1978/0.3852, байт-нейтрально, закрыл обещание коммента pipeline.go «все шиппинг ставят явно») · backend/README.md:59 пути промптов → prompts/zh-ru/ · embedded.go parseCJKSection unknown-category want-list → +magnitude · packAlgoVersion бамп (см. выше).

(3) НЕ тронуто (кандидаты пака-15, по указанию оркестратора): fail-loud оверлея уровнем выше · override-семантика unionStringMap · isRuTarget/'ru'-швы · empty-probe гард lintMagnitudeScale · дуп терминаторов chunker/coverage · 第.

Верификация дельты: go build/vet/test -race зелёные · golden БАЙТ-ИДЕНТИЧЕН (capture.golden не тронут) · парити EXACT n=13618 {方源:0 蛊:1 蛊师:2 古月:22}. Сессия НЕ коммитит.