textmachine/docs/BACKEND_TRACKA_PACK15_SESSION_PROMPT.md

100 lines
12 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.

# Промт: сессия-БЭКЕНД — Трек A, пак-1.5 (экспорт-поверхность + глосс-whitelist + пример), 2026-07-16
> Малый хирургический пак ПОСЛЕ приёмки пака-1 (D39.2, `d3f6b34`). Три задачи — все НЕ гейтятся
> эмпирикой exp15 и закрывают открытые вопросы D39.2 с решениями владельца от 16.07. Крупные слои
> (чанкер B1, кнобы когезии, дифф-apply) **НЕ строить** — они гейтятся результатами exp15 (research/19 §D).
> Смысл окна: все снапшот-сдвиги этого пака ложатся В ТОТ ЖЕ единый `--resnapshot`, который и так
> предстоит (D38.5+пак-1) — сейчас они бесплатны, после resnapshot стоили бы вторую переоплату книги.
## Зона/дисциплина (как в паке-1)
`backend/` только; не коммитить; `.env` не читать; мандат самопроверки ИСПОЛНЕНИЕМ (build/vet/gofmt/
test -race, каждый фикс запинен firing+non-firing тестом, ДО/ПОСЛЕ на сконструированном входе);
golden = инвариант №8 — re-capture только с обоснованием «что и почему сдвинулось» (ратифицировано
D39.2-open + решения владельца 16.07); git status перед работой — в дереве возможны параллельные сессии.
## Онбординг
`CLAUDE.md` → D-лог **D39.2** (что залендено паком-1 + открытые вопросы) → `09-target-architecture.md`
§2 (слой 6) → свой же код пака-1 (sanitizer.go exportNormalize/detectCJKLeak/stripCosmetic,
chunkrun.go FinalText, cmd/tmctl).
## T1 — Read-only экспорт-поверхность для полигона (закрывает D39.2-open №1; НУЖНО ДО пере-прогона)
**Проблема:** exportNormalize живёт на бэкенд-поверхностях (translate stdout / report), а полигонная
экстракция (`records.json`/exp12_extract-класс) читает СЫРЫЕ чекпоинты из store → полигон и
читатель-сэмплы увидят НЕнормализованный текст. Решение оркестратора: НЕ Python-зеркало нормализации
(анти-паттерн зеркального дрейфа), а **бэкенд-поверхность**.
**Сделать:** read-only команда `tmctl export` (проекция класса `status`/`report`: OpenReadOnly, $0,
без снапшот-влияния): для каждого чанка книги эмитит финальный экспорт-текст РОВНО по прод-семантике
(`chunk_status.final_hash` → checkpoint.response_text → [для `sanitizer_stripped` — это уже
стрипнутый derived-чекпоинт] → `exportNormalize`) + метаданные (chapter/chunk/disposition/flag/
snapshot_id) в стабильном JSON (+опц. plaintext). Флагнутые-непоправимые — пустой текст + причина
(как FinalText-семантика). Это и есть отложенный `tmctl export` из D15.2-этап-Б в минимальной форме —
НЕ строй annotations/override-часть, только чтение. Тест: export == translate-FinalText байт-в-байт
на golden-фикстуре (fresh и resume).
## T2 — CJK-глосс-whitelist (решение владельца 16.07: глоссы СОХРАНЯТЬ)
**Сейчас:** `stripCosmetic` стрипает намеренный глосс «Кулак Ло Ханя (羅漢拳)» и пустит скобку;
`detectCJKLeak` флагует такой Han-ран. **Сделать:** узкий whitelist — **сбалансированный Han-ран
целиком внутри скобок, непосредственно после кириллического/латинского слова-головы** (паттерн
«терм (漢字)») — НЕ утечка: `detectCJKLeak` не флагует, `stripCosmetic`/`exportNormalize` сохраняют
байты глосса (вкл. НЕ-фолд его полноширинных символов, если они часть глосса). Голый Han вне этого
паттерна — по-прежнему утечка (прод-класс cjk_leak цел). Краевые: вложенные скобки, глосс с пробелами/
пиньинем, глосс в начале строки без головы (→ утечка), два глосса подряд. `sanitizerVersion` v5→v6 +
golden re-capture (обоснование: решение владельца). Тесты: глосс сохранён (strip и normalize),
standalone-Han флагуется, пустая скобка больше не рождается.
## T3 — `example/book.yaml`: вернуть runnable
После pair-сеама ja-пример fail-loud'ится через zh-ru-keyed pipeline-c1 (сеам работает как задуман).
**Сделать:** переоформить пример на **zh→ru** (реальный прод-контент пары уже есть) — пример снова
проходит end-to-end; рядом закомментированный ja-блок с пояснением «fail-loud до появления ja-ru
пакета» (демонстрация сеама, не заглушка). ja-ru пакет НЕ сочинять (контент пары = данные под
реальную книгу, инвариант общности §0.1).
## T4 — ФИКС-ЛИСТ адверсариала (долг D39.2 ПОГАШЕН 17.07: 8 осей, оба пака; 0 CRITICAL / 1 HIGH / 6 MEDIUM)
T1T3 исполнены и верифицированы оркестратором (не лендились — ждут этих фиксов, чтобы санитайзер-бамп
и golden re-capture легли ОДНИМ лендингом). Обязательные (F1F6) + дешёвые LOW (F7F9):
**F1 (HIGH, санитайзер — обход гейта, воспроизведён исполнением).** 5 из 6 классов детектят по СЫРОМУ
тексту (fold делает только detectCJKLeak), а exportNormalize шипит СВЁРНУТЫЕ байты → полноширинная
вариация сигнатуры обходит детектор, и нормализация ИЗГОТАВЛИВАЕТ ASCII-форму дефекта в экспорте:
«Вот отредактированный перевод:»(U+FF1A) / «### Глава 5» / trailing «Примечание:…» / fullwidth-латиница
с U+3000 — все total=0, а в экспорте — ASCII-дефект (ASCII-близнецы при этом флагуются). Регресс vs v4
(тот фолдил весь U+FF00FFEF блок и re-check ловил). **Фикс:** fold-first — `t := recoverableFold(text)`
в начале sanitizeOutput; ВСЕ шесть классов + глосс-маскирование работают по свёрнутому тексту
(детекция по folded; strip/export-пути сохраняют оригинальные байты; глосс-спаны пере-анкерить
согласованно). + инвариант-тест гейта: для чистого вердикта `sanitizeOutput(exportNormalize(x)).total()==0`
по всему тест-корпусу. Версия: v6 НЕ лендился — влить fold-first в ТОТ ЖЕ бамп v5→v6, один golden re-capture.
**F2 (MED, глосс — unbounded латиница; найден независимо осями 4 и 8).** isValidGloss ограничивает
только CJK: «Кулак (拳 the quick brown fox…) взлетел.» = total 0, английская фраза уезжает чистой (без
拳 — substantive drop). **Фикс:** ограничить не-CJK контент — кап полной внутренней длины (~24 руны) +
пиньинь-правдоподобные латин-токены (lowercase, ≤~7 рун токен, ≤~maxGlossCJKRunes+2 токенов). Запинить
тестом «(拳 the iron fist that breaks the sky)» → НЕ глосс.
**F3 (MED, export — gate-drift).** `Export()` читает `PostcheckGate` из ТЕКУЩЕГО конфига: флип гейта
между прогоном и экспортом тихо шипит удержанный текст (или фабрикует glossary_miss). **Фикс:** сравнить
SnapshotID строк с текущей проекцией (`currentSnapshotProjected`, как status) → fail-loud ИЛИ top-level
`config_drift` поле + WARN; docstring-caveat расширить на gate-flip вариант.
**F4 (MED, export — нет manifest-сверки).** Частичная книга экспортится молча как полная (класс
D37-скью для полигона); пустая книга даёт `"chunks": null`; ghost-строки удалённой главы экспортятся.
**Фикс:** `Chunks` = non-nil `[]`; join с $0-манифестом (`bookChunks`) → pending/missing явными
строками или `total/missing`-счётчиками; строки вне манифеста — drop или громкая метка.
**F5 (MED, quality — популяция KPI).** QualityReport считает gate-withheld чанки в TextChunks/KPI
(их экспорт = ""), расходясь с export. **Фикс:** зеркалить gateOn re-derivation (данные уже читаются) —
исключать из TextChunks/KPI.
**F6 (MED, quality — метка метрики).** `cjk_leak_rate` считает ВСЕ sanitizer_stripped, вкл.
markdown-only (ложные 30% «CJK-утечек»). **Фикс:** сплит по классу strip (из detail) на
`markdown_strip`/`cjk_leak` ИЛИ переименовать в `cosmetic_strip_rate`.
**F7 (LOW, 1 строка).** resume.go stripped-ветка: `sr.Model = cp.ModelActual` (зеркало ok-ветки) —
иначе resumed-строка телеметрии атрибутируется конфиг-слагу вместо фактической модели.
**F8 (LOW, 1 строка).** example/book.yaml: `transcription: pinyin``palladius` (ru-target конвенция;
самопротиворечие примера).
**F9 (LOW).** Export fail-loud parity: DispOK-строка с ПУСТЫМ final_hash → тоже громко (сейчас уже
комментарий обещает resume-дисциплину — довести до неё).
В ledger/очередь (НЕ этот пак): Retries не в снапшоте (pre-existing, дизайн); pair-fail-loud после
store.Open + report/export не требуют промптов (дизайн-вопрос); trustGateEvent только первый отказ;
WarnContext на каждом resume; quality 0.00 при all-dialogue; пунктуационные «огрызки» в НЕ-whitelisted
скобках; golden-ячейка глосса и escalated+stripped (желательно добавить тестами при F1/F2).
## Deliverable
Отчёт в ответе (не в PROGRESS): per-T — file:line, ДО/ПОСЛЕ, какие снапшот-версии/golden сдвинулись и
почему, результаты build/vet/gofmt/test -race, само-ревью исполнением. Открытые вопросы — списком.
Не коммитить — лендит оркестратор.