textmachine/docs/BACKEND_ARCH_CLEANUP_SESSION_PROMPT.md

138 lines
16 KiB
Markdown
Raw 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.

# Промт: сессия БЭКЕНД (промежуточная) — изоляция языковых данных из пайплайна + алгоритмы/чистота кода, 2026-07-19
> **Место в очереди:** ПЕРЕД R1-драйвер-свитчем (директива владельца 19.07 — вставить архитектурный проход до
> завершения волнового исполнителя, пока не накопился ещё язык-специфичный код и до того, как майнер станет
> живым в W1.5). После этой сессии → R1-продолжение (`BACKEND_PLAN11_SESSION_PROMPT.md`) → resnapshot →
> пере-прогон → чтение. **Это не R1 и не пере-прогон.**
## Директива владельца (дословно, ратифицирована — это НЕ гипотеза сессии)
Язык-специфичные русско-китайские вставки НЕ должны жить внутри `internal/pipeline/`. Горизонт — сотни
языков. Пересмотреть архитектурный подход: язык-данные — вне движка, через **библиотеки где уместно** и
**данные-файлами, а не константами**. **Писать ЧИСТЫЙ КОД с НОРМАЛЬНЫМИ АЛГОРИТМАМИ — как сеньоры из Google.**
**НО:** не упарываться на миноры, переписывание ради переписывания НЕ делать. Один оправданный крупный
рефактор (изоляция языка) + известные реальные фиксы — и всё; не плодить косметику.
## Кто ты и что сдаёшь
Бэкенд-сессия. **Зона: `backend/` (вкл. `configs/`, `prompts/`) + новый каталог языковых данных.** Прочее —
read-only. **НЕ коммитить** (лендит оркестратор). Сдаёшь:
1. Код рефактора + фиксов + тесты; **поведенчески НЕЙТРАЛЬНО для zh→ru** (это РЕФАКТОР-перемещение данных, не
смена поведения — доказывается байт-стабильностью golden с точностью до одного version-поля).
2. **`backend/ARCH_CLEANUP_REPORT.md`** — результаты каждой фазы-воркфлоу (ресёрч-буллеты, синтез, фикс-лист с
диспозициями do/defer/don't, лог исполнения, ревью-вердикт), golden-дифф, «багфиксы вне плана», residual.
## Онбординг
1. `CLAUDE.md` (гардрейлы) → `backend/README.md` (**инварианты 18**) → `docs/architecture/09-target-architecture.md`
**§0.1 инвариант общности** (любая книга/пара/структура; пара = ось данных — это север) + §2 слой-2.
2. `docs/architecture/10-prompt-architecture.md`**прецедент, который расширяем:** промпты УЖЕ живут pair-keyed
(`Stage.Prompts[pair]` + `PromptPathFor` + fail-loud + снапшот-фолд). Языковые данные получают ту же форму.
3. `docs/architecture/11-implementation-plan.md` §3 **§B5 (плагины P1P6)** — 6 интерфейсов языковых данных уже
спроектированы; эта сессия делает их **data-backed и вне `pipeline/`**.
4. D-лог D39.12D39.15; `docs/experiments/00-provider-quirks.md`.
5. Грунтовка по коду (где сейчас зашит язык): `miner_patterns.go` (百家姓 `surnamesSingleRaw`, суффиксы),
`miner_palladius.go` (таблица Палладия), `miner_alias.go` (`aliasParticle` 的了在是…), `checkers_zh_ru.go`
(时辰-таблица, числительные, «терем»-регистр), `cheapgates.go` (allowlist междометий), `disposition.go`
(`isRuTarget`/`isCJKTarget`), `chunker.go` (фертильность CJK/other). Референсы данных — `eval/exp16/*.py`.
## Фазовая структура (ВОРКФЛОУ — ultracode включён; каждая фаза = отдельный воркфлоу)
### Фаза 1 — РЕСЁРЧ (независимый, 2 направления × 3 источника, свои буллеты)
Параллельные агенты, каждый ищет СВОИ находки (refute-by-default, независимая перспектива). Источники каждого:
**(1) Go-идиоматика/stdlib/`golang.org/x/text`, (2) наш репозиторий, (3) интернет (websearch)**. Направления:
- **A. АЛГОРИТМЫ:** правильные ли алгоритмы в текст-работе (майнер n-граммы/c-value, matcher Aho-Corasick,
нормализация, union-find алиасов, фертильность)? Что из этого — переизобретённый велосипед, заменяемый
stdlib/`x/text` (сегментация/коллация/нормализация/`language.Tag`)? Что — уже правильный нормальный алгоритм,
который ТРОГАТЬ НЕ НАДО (напр. union-find `clusterAlias` — оставить)? Где Go-библиотека реально поможет, а где
честно нет (морфология/NER — вынесено в облако, не Go)?
- **B. АРХИТЕКТУРА КОДА / ОБЩНОСТЬ:** как изолировать языковые данные из `pipeline/` под сотни языков.
Паттерны: data-as-files + реестр-per-пара, plugin-интерфейсы, `x/text/language.Tag`. Прайор-арт: наш
pair-keyed промпт-сеам; Go project-layout идиомы; i18n/l10n data-separation из индустрии (websearch).
Выход фазы: два набора буллетов (алгоритмы / архитектура) с обоснованием и file:line/ссылками.
### Фаза 2 — СИНТЕЗ (короткий воркфлоу): свести все входы
Реконсилировать: **ресёрч-буллеты + буллеты оркестратора (ниже) + буллеты владельца (ниже) + известный
фикс-лист (ниже)**. Дедуп, разрешить конфликты, ранжировать по ценности×риску. Явно пометить, что —
консенсус, что — спорно.
### Фаза 3 — ВЫВОД фикс-листа + предложений (резюмирующий воркфлоу)
Из синтеза вывести **финальный actionable-список** с диспозицией КАЖДОГО пункта: **DO** (делаем сейчас) /
**DEFER** (в резидуал, с причиной) / **DON'T** (переписывание-ради-переписывания — отвергнуть явно). Это
рубеж против «упарывания на миноры»: пункт без ясной ценности → DON'T. Отдельно — предложения по
алгоритмам/архитектуре, которые сверх скоупа этой сессии (в план/владельцу).
### Фаза 4 — ИСПОЛНЕНИЕ (редактура кода)
Только DO-пункты. Временные тесты — можно. **Поведенческая нейтральность zh→ru обязательна** (см. приёмку).
### Фаза 5 — РЕВЬЮ (воркфлоу): изменения с разных точек зрения + функциональное
Мульти-линзовый адверсариал (author≠reviewer): (i) корректность/поведенческая нейтральность (golden,
детерминизм, снапшот); (ii) сеньор-код-ревью (Go-идиоматика, чистота сеамов, отсутствие велосипедов и
над-инженерии); (iii) функциональное (пара резолвится, fail-loud на неизвестную пару, добавление 2-й пары =
только данные). Находки чинить до сдачи. **Ревью НЕ должно генерить длинный минор-лист** — оно проверяет, что
рефактор корректен и нейтрален, а не хантит косметику.
## Входные буллеты для синтеза (Фаза 2)
**Буллеты ОРКЕСТРАТОРА (стартовое предложение — ПРЕСС-ТЕСТ ресёрчем, не имплементить слепо):**
- Движок (`pipeline/`) — общий, язык-данных НЕ содержит.
- Новый пакет `internal/lang/` (или лучшее по ресёрчу): интерфейсы `LangPack`/P1P6 + загрузчик + реестр,
**без самих данных**.
- `configs/langpacks/<lang>/*.yaml` + `<pair>/*.yaml`: 百家姓/суффиксы/частицы (zh), Палладий (zh-ru),
регистр/числительные/гендер-местоимения (ru), единицы 时辰 (zh-ru).
- Резолв по `Book.LangPair()`, снапшот-folded (как промпты). Добавить язык = положить каталог, **без
перекомпиляции, без правок `pipeline/`**.
- `golang.org/x/text/language.Tag` вместо `isRuTarget`/ручных рун-сетов (реестр языков с фолбэком; `x/text`
уже в зависимостях).
- НЕ трогать правильные алгоритмы: union-find, детерминированные сортировки, целочисленные пути — они верны;
из движка уходят ДАННЫЕ, алгоритм остаётся.
**Буллеты ВЛАДЕЛЬЦА:** язык вне `pipeline/`; сотни языков; библиотеки где уместно; чистый код + нормальные
алгоритмы, стандарт «сеньор Google»; не упарываться на миноры; никакого rewrite-ради-rewrite.
**Известный фикс-лист (реальные, рождены рубежом-2 D39.14 + §0.1-разбор — риды-along, не хантить сверх):**
- **FL-1 (MINOR):** свернуть `bankMaxLines`/`bankTokenBudget` в `banknoteSnap` (`snapshot.go`) — сейчас
`max_tokens += bankTokenBudget` wire-affecting, но не свёрнут → правка конста без бампа `bankParserVersion`
= тихий re-bill на резюме.
- **FL-2 (MINOR, observability):** `resumeFromChunkStatus` (`resume.go:22`) не ставит `BankFlags`
банкнота-телеметрия обнуляется на резюме готовых чанков; коммент «self-heals» ложен. Re-derive из сырого
чекпоинта / не обнулять эти колонки на резюме / поправить коммент.
- **FL-3 (PARTIAL, порт-fidelity):** `miner_emit.go:68` идёт по полному `mr.ranked`; референс капит
`a3[:200]`/`[:30]` ДО фильтров (`eval/exp16/{alias.py:165, emit_owner_sheets.py:143,162,169}`) → карта
подписи шумнее референса. Добавить top-N кап перед emission-фильтрами.
- **Тест-путь:** абсолютные `/home/ubuntu/...` в `miner_parity_test.go` → env-var/`testdata`-относительные
(тест-гигиена; не прод).
## Скоуп
**IN:** ресёрч; изоляция языковых данных (движок→`lang`/`langpacks`); `x/text/language`-реестр; FL-1/2/3;
тест-путь; доказательство общности «2-я пара = только данные» (минимальный второй langpack-скелет ИЛИ тест
загрузки синтетической пары через сеам — НЕ полный ja→ru-контент). **OUT:** R1 драйвер-свитч (след. промт);
пере-прогон; любая смена ПОВЕДЕНИЯ перевода zh→ru; полная ja→ru-реплика (отдельная задача); минор-хант.
## Гардрейлы (жёсткие)
- **Поведенческая нейтральность zh→ru:** рефактор = перемещение ДАННЫХ; langpack-значения обязаны быть
байт-равны прежним константам. Golden после = байт-стабилен С ТОЧНОСТЬЮ до одного нового version-поля
(langpack-версия в снапшоте); НОЛЬ изменений вердиктов/wire/final. Один чистый resnapshot (масштаб — как
chunkerVersion). Если langpack-путь меняет хоть один вердикт — это БАГ рефактора, не «улучшение».
- **Снапшот-дисциплина:** langpack-данные wire-определяющи (майнер/чекеры/фертильность) → версия пакета
фолдится в `snapshotID` (правка данных = громкий resnapshot, как `chunkerVersion`/промпты). Детерминизм:
загрузка сортирована/версионирована, без map-order в выводе.
- **Чистый код, сеньор-Google:** идиоматичный Go (`gofmt`/`vet`/`-race` чисто; обёртка ошибок `%w`; без
глобального мутабельного стейта; table-driven тесты); **stdlib/`x/text` вместо велосипедов**; НО НЕ
над-инженерия (union-find не превращать в «библиотеку»; не плодить абстракции без второго потребителя —
а он есть: 2-я пара). Комментарии — как в окружающем коде (констрейнты, не пересказ).
- **Инварианты 18 не трогать** (деньги/durability, снапшот, эхо-мина, детерминизм, экспорт-контракт, golden).
- **$0 к провайдерам:** ресёрч — websearch + чтение кода; верификация — build/test/golden/фикстуры. LLM-вызовов
перевода НЕТ.
- **Неконсистентность/аномалия** — даблчек всеми тулзами (grep, git log, вендор-дока, websearch — правило двух
направлений); реальное расхождение → эскалация запиской, не тихо.
- Git: `.env` не читать; книга/производные вне git; PUML не рендерить; не коммитить.
## Приёмка (оркестратор — знай заранее)
Пере-исполнение фикстур; спот-чек file:line; **golden байт-стабильность** (масштаб — только langpack-версия,
ноль вердикт-правок); адверсариальный рубеж-2 (перемещение данных нейтрально? общность реальна — 2-я пара
грузится без правок `pipeline/`? алгоритмы не сломаны, велосипеды сняты, над-инженерии нет?); проверка «не
упоролись на миноры» (фикс-лист = DO-пункты с ценностью, не косметика). Затем лендинг → D-блок → R1-продолжение.