1069 lines
140 KiB
Markdown
1069 lines
140 KiB
Markdown
# План реализации пере-прогонного стека (слои 1+4+5 + данные слоя 2) — дизайн-синтез, 2026-07-19
|
||
|
||
> **Статус: РАТИФИЦИРОВАН — D39.12 (19.07, оркестратор №7); дизайн-оф-рекорд бэкенд-стройки.** Проектный
|
||
> документ дизайн-синтез-сессии (D39.11): синтез всей исследовательской программы арх-ресета (research/19–20,
|
||
> exp15/16, аудит 08, дефект-классы слепого чтения) в план стройки с верифицированными ($0) алгоритмами.
|
||
> **Ревью-провенанс (три рубежа):** ревью-2 оркестратора (F1–F11, все внесены — 36 маркеров) → пост-фикс
|
||
> 7-агентный адверсариал-воркфлоу сессии (5 находок впитаны, вкл. переписанный F8 и mined-write-путь) →
|
||
> 3-агентный подтверждающий пас (2 резидуала закрыты). Бэкенд строит СТРОГО по этому плану
|
||
> (`BACKEND_PLAN11_SESSION_PROMPT.md`, единый пак — решение владельца); **4 гейтнутых арма — §11**.
|
||
>
|
||
> **Источник истины:** при конфликте побеждает D-лог (`05-decisions-log.md`, D1–D39.11). Все `file:line` —
|
||
> против HEAD `766a60e`. Все пороги/коэффициенты — число + источник. $0-верификации — `eval/design11/`,
|
||
> результаты в `books/gu-zhenren/design11/` (вне git); сводка — `VERIFICATION_RESULTS.md`.
|
||
>
|
||
> **Дисциплина цитат:** аудит 08 и D-лог местами несут устаревшие `memory.go`-строки (~+11…+26 к HEAD:
|
||
> `renderEditorConstraintBlock` :515 не :489, `suppressContained` :684, `dispositionFor` :441; санитайзер = v6
|
||
> не v4). Этот план цитирует HEAD-строки.
|
||
|
||
---
|
||
|
||
## §0. Рамка: доказанная база и зоны
|
||
|
||
**Строим (ратифицировано D39.x; в план внесено, НЕ пере-открывается):** волновой раннер W0→W1(∥)→W1.5→W2(∥);
|
||
бюджет чанкера в ВЫХОДНЫХ токенах (фертильность 1.20/0.39); банк W1.5 слоя 4 (детектор V-C WHICH + банкнота dst +
|
||
Палладий + консолидация §C2 + алиас-ярус-1 + карта подписи); декаплинг draft=мелкий-чанк / edit=крупная-единица;
|
||
свап редактора glm→mistral/deepseek-pro; дефект-класс чекеры + данные пакета пары.
|
||
|
||
**НЕ строим (доказано/ратифицировано):** сцен-детекция и carryover-машинерия (D39.7/8, метрики под полом 0.126 И
|
||
читатель); DP/logical-граница чанкера (Q1: «граница не рычаг»; Q1a 0/7); ко-оккуренция для dst (canon-recovery
|
||
0.20–0.68 < 70%); LLM-сегментация/ML-сцены/эмбеддинг-границы/RAG-оверлап; фронтир в дефолт; жанр-паки; локальный
|
||
9B-споттер (код ≥ локаль). **Парковки (не тестировано, консервативный дефолт — НЕ строим, НЕ хоронить):**
|
||
lookahead (Q3b), diff-редактор §C2 (Q4b), reflow-отдельным-пассом (Q4c), широкое-окно/узкая-эмиссия (Q2c),
|
||
W2.5-швейный пасс (Q5). Каждая парковка помечена «не тестировано» — диспозиции в §9 (lookahead/diff-редактор через
|
||
§1(е)/E.7; Q4c/Q2c/Q5 — явные строки в §9).
|
||
|
||
**Столпы (инварианты 1–8 `backend/README.md`, ломать нельзя):** деньги/durability (committed==SUM, kill-9);
|
||
снапшот-дисциплина (правка wire/вердиктов = громкий resnapshot; все правки этого плана → ЕДИНЫЙ resnapshot §8);
|
||
детерминированный банк (не вектора); эхо-мина DeepSeek (thinking НИКОГДА не off); 18+; конфиг-первое ядро;
|
||
экспорт-контракт (внешняя экстракция ТОЛЬКО `tmctl export`); golden-гард детерминизма; инвариант общности §0.1
|
||
(любая книга/пара/структура; пара = ось данных).
|
||
|
||
**Сводка $0-верификаций (все PASS, детали в каждом WS (г)):**
|
||
|
||
| WS | Верификация | Результат |
|
||
|---|---|---|
|
||
| WS2 | фертильность независимо пере-выведена | `1.1978/0.3852, R²=0.9633` (Δ<3e-5); классиф.-mismatch на zh = 0 |
|
||
| WS2 | нарезка на 25 главах | target_out=1797 → тот же СЧЁТ 56 чанков (4 ре-сегм / 2 абзац-сдвига, НЕ byte-identical); edit-единица: 8000-арм 25/25 в 2k–8k, **ратиф. дефолт 3200 → 37 единиц** (11 глав делятся; размер ГЕЙТИТСЯ Q2a) |
|
||
| WS3 | майнер-v1 golden | катастроф `{方源:0,蛊:1,蛊师:2,古月:21}` EXACT (вариант A / Python-референс; при ратиф. дефолте **B** → `古月:22`, скрин PASS — §3(г)/(д) split-фикстура); 13618 канд.; recall 0.965/0.932 |
|
||
| WS3 | сид-дельта + линт | 61 терм, 0 фейл-лаудов; флагает D38-дефект как draft ⟨проверить⟩ |
|
||
| WS4 | банкнота пере-парс | 95 строк/65 src/0 fail/0 trunc EXACT; hash resume-стабилен |
|
||
| WS5 | чекеры | 6/6 позитивов; DC1/2/6 n=1 (реальные, FP-rate §5д); DC3 3.5% (1 паратекст + 1 narrative-coref на hidden); **DC5 74%/42% → не гейт**; DC7 не покрыт $0 |
|
||
| WS1 | деньги под ∥ + wall-clock | money-инвариант ALL PASS (границы ПАРАЛЛЕЛЬНЫ); within-wave compute ≈7.3× (end-to-end + W1.5-стоп) |
|
||
| WS6 | COGS per-арм | glm-5 $0.335 / mistral $0.205 / deepseek-pro $0.117 (25-гл, warm/valley) |
|
||
|
||
---
|
||
|
||
## §1. WS1 — Волновой раннер (слой 1 / оркестровка)
|
||
|
||
Целевой раннер: **W0** (чанкер + контекст-пакеты, $0) → **W1** черновики параллельно → **W1.5** (стоп-граница:
|
||
банк-синк, подпись владельца, resnapshot) → **W2** редактуры параллельно. Сегодня перевод строго последователен:
|
||
`bookrun.go` итерирует плоский список чанков, `translateChunk` (`chunkrun.go:90`) гонит ВСЕ стадии одного чанка по
|
||
порядку под ОДНИМ `snapID`. Волны разносят: W1 = только draft-стадия по всем чанкам; W2 = только edit-стадия по всем
|
||
единицам; W1.5 между ними.
|
||
|
||
### (а) Что меняем (модули, file:line)
|
||
- **`runner.go`** — новый волновой драйвер (или `bookrun.go` расширяется режимом waves); **закрыть гонку lazy-init
|
||
`Runner.client` (`runner.go:171-181`)**: `r.clients map[string]llm.LLMClient` читается+пишется без лока.
|
||
- **`bookrun.go`** — цикл книги переходит на волны; per-chapter sticky-reset (`stickyWin=nil`, HEAD ~`bookrun.go:144`)
|
||
переезжает в W0-precompute.
|
||
- **`chunkrun.go`** — `translateChunk` расщепляется на per-волна проходы; sticky-цепочка (`chunkrun.go:107-115`:
|
||
`memSel=r.memory.Select(...)` → `activeIDs` → следующий stickyPrev) precompute'ится в W0.
|
||
- **`snapshot.go`** — `snapshotID()` (`:101-279`) становится **пер-волновым** (см. (в)).
|
||
- **`stagerun.go`** — деньги/чекпоинт-путь (`Reserve`→`SettleWithCheckpoint`, `:312-449`) без изменений семантики,
|
||
но вызывается из N горутин; `client(model)` предвычислен.
|
||
- **`config/pipeline.go`** — новый конфиг `waves.workers` (число воркеров волны — НЕ `fanout.workers`: `Fanout`
|
||
занят C2-кандидатами, `CheckRunnable` отвергает `candidates>1` `pipeline.go:208-209`; оси ортогональны) +
|
||
`pricing_windows` провайдера + **пер-модельный rate-guard** (ревью-2 F4): `models.yaml` `max_concurrency`/опц.
|
||
`min_interval` НА МОДЕЛЬ (конфиг, НЕ хардкод); rate-guard = транспорт-ось, НЕ снапшот (wire-байты не трогает).
|
||
|
||
### (б) Алгоритм (детерминизм явно)
|
||
|
||
**W0 (детерминированный, $0):**
|
||
1. `SplitChunks` (draft-чанки, WS2) + сборка edit-единиц (WS2).
|
||
2. **Predвычислить sticky-цепочку:** один упорядоченный проход по чанкам КАЖДОЙ главы; для чанка `i`
|
||
`stickyPrev_i = union предыдущих stickyDepth=2 чанков той же главы` (порт `bookrun.go` unionSticky), затем
|
||
`memSel_i = memory.Select(chunk_i, chapter, stickyPrev_i, budget)`, `activeIDs_i` кормит `stickyPrev_{i+1}`.
|
||
`Select` — ПУРЕ детерминированная функция `(chunk, chapter, stickyPrev, budget, frozen-bank)` (`memory.go:324`),
|
||
src-производна, БЕЗ модель-выхода → precompute воспроизводит БАЙТ-в-БАЙТ ту же инъекцию, что онлайн-цепочка
|
||
последовательного раннера. **Инвариант: precompute'нутые инъекц-байты ≡ байтам текущего раннера** (golden-тест в
|
||
(д)) → sticky-переезд НЕ двигает request_hash, НЕ строка манифеста resnapshot. ⚠ Byte-identity держит только над
|
||
BASE-банком и над НОВОЙ нарезкой (WS2 сдвигает 4 чанка); golden-тест (д) сверяет против нового чанк-сета, не старого.
|
||
(Параллелизм байты НЕ меняет — `Select` src-производна, порядок фиксирован; ревью-1 CONFIRMED.)
|
||
3. **Eager-build клиентов:** множество моделей известно из `Pipeline.Stages[].Model` ∪ `EscalateTo` до старта →
|
||
построить ВСЕ `llm.LLMClient` в W0 (`BuildClient`, `clients.go:15`), заполнить `r.clients` ДО любой горутины.
|
||
Закрывает гонку `runner.go:171-181` без лока (карта только читается в волнах; `r.client()` вызывается ровно в одном
|
||
месте `stagerun.go:343` с `model∈{st.Model, EscalateTo}` — перечисление ПОЛНОЕ). **Защита от будущей 3-й модель-оси**
|
||
(channel B / annotator, `stagerun.go:476-478`): в волновом режиме `client()` делается READ-ONLY (panic/error на miss),
|
||
чтобы не-перечисленная модель не пере-открыла гонку тихо. Прочие разделяемые хендлы:
|
||
`templates` (построена раз в `loadTemplates`, read-only в волнах — safe), `memory *MemoryBank` (материализован
|
||
раз, immutable — safe), `Store` (single-writer сериализует записи — safe), `Log` (slog thread-safe).
|
||
|
||
**W1 (∥):** N воркеров тянут draft-чанки из очереди; каждый — `runStage(draft-стадия)` под `snapshot_W1`. Деньги:
|
||
`Reserve`→`Complete`→`SettleWithCheckpoint` (`stagerun.go`) — сериализуются через single-writer store-пул
|
||
(`store.go:71` `MaxOpenConns=1`, BEGIN IMMEDIATE). Ретрай чанка `i` изолирован: его вход — чистая функция
|
||
`(source_i, frozen-bank, snapshot_W1)`, независим от чанка `j` (свойство волн — нет разделяемого мутабельного входа).
|
||
|
||
**W1.5 (стоп-граница, $0 к провайдерам кроме опц. облачной Z1-адъюдикации):** банк-майнинг из W1-черновиков
|
||
(WS3) → алиас-кластеризация ярус-1 → канон-предложения (draft) → карта подписи (сайдкар) → **подпись владельца**
|
||
(approve/правка/draft/расклеить) → эмиссия сид-дельты → reseed → `snapshot_W2`. Механика стопа (см. (в)).
|
||
|
||
**W2 (∥):** N воркеров тянут edit-единицы (главы, WS2); каждый — `runStage(edit-стадия)` под `snapshot_W2`, читая
|
||
draft из W1-чекпоинта (`prev` = draft-текст единицы). W1-чекпоинты под `snapshot_W1` НИКОГДА не пере-гоняются →
|
||
W1 не пере-оплачивается. **Инъекция редактора W2 (ревью-2 F3, специфицировано):** edit-стадия единицы получает
|
||
СВЕЖИЙ `memory.Select` по тексту ВСЕЙ единицы (глава) над ОБОГАЩЁННЫМ банком (sticky-окно на уровне глав вырождено:
|
||
единица = глава); констрейнт-блок `renderEditorConstraintBlock` = CONFIRMED-only, формат src→dst (решение WS2 §2(б)).
|
||
**Явный запрет: НЕ реюзить per-чанк `memSel` из W0** (`chunkrun.go:107-114`) — тот посчитан над BASE-банком, W2 поехала
|
||
бы БЕЗ майненого банк-энфорса. Это НЕ противоречит инварианту секвенирования (в): свежий Select кормит ТОЛЬКО
|
||
edit-стадию (CONFIRMED-only enriched-банк), draft-стадия по-прежнему НЕ пере-рендерится/не пере-хешируется. Пин — (д):
|
||
инъекция W2 содержит подписанные на W1.5 mined-термы.
|
||
|
||
**Пер-модельный rate-guard (ревью-2 F4, НЕСУЩЕЕ для ∥):** пер-ВЫЗОВНЫЙ 429/`Retry-After` УЖЕ есть в адаптере
|
||
(`httpllm.go:27-29,138-140`, читается+уважается, кап `maxRetryAfterWait=5мин` `:76`; тест
|
||
`TestRetryOn429HonoursRetryAfter` `httpllm_test.go:168`) — до WS1 раннер БЫЛ последователен, проблема
|
||
N-параллельности НЕ возникала. Гэп именно N-конкуренция. Волновой диспетчер добавляет **пер-модельный семафор
|
||
конкуренции** (+опц. пейсинг `min_interval`) из `models.yaml` + телеметрию 429-плотности. Rate-guard **НЕ снапшот-ось**
|
||
(транспорт, wire-байты не трогает). ⚠ Известный лимитер: `mistral-large-latest` ~48% retry-fails @1.3s интервала,
|
||
max lat 64.7s (судейский eval-риг exp15 §7.6 REV.2; grok 0%); расширение 1.3→2.6s эффекта НЕ дало (49.5→48.2%) →
|
||
похоже на токен-бакет/конкуренцию, тир-зависимо → **mistral-арм НЕ идёт через прод-путь до rate-guard** (WS6
|
||
пред-условие). Заготовка-блок для `00-provider-quirks.md` — §12 (вносит оркестратор при лендинге, зона полигона).
|
||
|
||
**Money под параллелизмом (доказано верификацией):** потолок проверяется ВНУТРИ `Reserve` immediate-транзакции
|
||
(`ledger.go:56-72`: `committed+reserved+estimate ≤ ceiling`) → конкурентные резервы N воркеров сериализуются
|
||
single-writer'ом, overshoot ≤ одной макс-резервации. Урок D12 (гонка `Runner.clients` + commit-terms-on-boundary):
|
||
клиенты предвычислены (закрыто); commit-терминов на границе джобы в этой архитектуре не применяется (банк
|
||
консолидируется в W1.5, не на границе чанка).
|
||
|
||
### (в) Конфиг + снапшот-механика — **ПЕР-ВОЛНОВОЙ снапшот (несущее)**
|
||
|
||
Сегодня `snapshotID()` — book-global, фолдится в КАЖДЫЙ `request_hash` (`stagerun.go:268-269`: `snapID` — прямой
|
||
вход). Правка `snapID` = all-or-nothing re-bill (`snapshot.go:26-34`); content-addressed reuse (`msgsContentHash`)
|
||
гейтится НЕ-изменённым снапшотом → через resnapshot не срабатывает (D15.2 — не построен). **Проблема:** банк входит
|
||
в `snapshotID` через `MemoryVersion` (`snapshot.go:191,229`); наивный resnapshot после W1.5 сдвинул бы `snapID` для
|
||
ВСЕХ стадий, включая W1 → пере-оплата W1 → «две переоплаты».
|
||
|
||
**⚠ Коррекция после адверсариал-ревью-1 (несущее): «переоплата ОДНА» держит НЕ снапшот, а ВОЛНОВОЙ ИНВАРИАНТ
|
||
СЕКВЕНИРОВАНИЯ.** `request_hash` фолдит рендер `msgs` НАПРЯМУЮ (`stagerun.go:268-269`), не только через `snapID`;
|
||
resume-fast-path отдельно сверяет `cs.ContentHash == msgsContentHash(msgs)` (`stagerun.go:65,79`). W1-инъекция
|
||
переводчика (`renderGlossaryBlock`, `memory.go:480,484-487`) эмитит ВСЕ строки с непустым dst, ВКЛЮЧАЯ AMBIGUOUS
|
||
(auto/draft, помечены `⟨проверить⟩`) — а WS3-майнинг добавляет до 21 draft-строки с dst. ⇒ если W2-проход когда-либо
|
||
ПЕРЕ-рендерит/пере-хеширует draft-стадию над обогащённым банком, её `msgs→contentHash→request_hash` меняются → miss →
|
||
re-bill W1, даже при byte-identical `snapshot_W1`. **Несущий инвариант: W2-проход НИКОГДА не трогает рендер/хеш
|
||
draft-стадии; редактор получает черновик из W1-ЧЕКПОИНТА (`final_hash→response_text`), не из свежего draft-рендера над
|
||
обогащённым банком.** Это ПРЯМО противоречит текущему `translateChunk`, который считает `memSel` ОДИН раз и рендерит
|
||
инъекции ОБЕИХ стадий из него (`chunkrun.go:107-114`) — наивный волновой сплит, пере-считывающий `memSel` в W2 для
|
||
content-verification, пере-выведет draft-инъекцию над обогащённым банком и споткнётся ровно тут. Волновой раннер обязан
|
||
разнести: W2-проход рендерит ТОЛЬКО edit-стадию, черновик читает по `final_hash`.
|
||
|
||
**Роль пер-волнового снапшота (уточнено):** он НЕ предотвращает re-bill (это делает инвариант выше) — он **избегает
|
||
громкого resnapshot-СТОПА** (`stagerun.go:45-49`): на резюме-после-W1.5, если владелец промоутнул майненые строки в
|
||
approved (это ДВИГАЕТ `MemoryVersion`, `memory.go:264-282`), book-global снапшот сделал бы `snapshot_id` уже-готовых
|
||
draft-джоб ≠ пере-вычисленному глобальному → hard-стоп. Пер-волновой снапшот держит W1-джобы на `snapshot_W1` (стабилен)
|
||
→ стопа нет. `snapshotID` вычисляется **пер-волна**, фолдя ТОЛЬКО стадии этой волны + состояние банка на момент волны.
|
||
Хранение уже пер-стадийное — `jobs` UNIQUE(book_id, chapter, stage) (`migrate.go:37`), каждая джоба несёт свой
|
||
`snapshot_id`. **Под-специфицировано (реальная ре-архитектура, не кноб — бэкенду построить):** сегодня `snapshotID()`
|
||
фолдит ВСЕ стадии + ОДИН book-global `MemoryVersion` в ОДИН хеш (`snapshot.go:229`), `TranslateBook` апсертит РОВНО один
|
||
снапшот (`bookrun.go:117-123`). План требует: раннер вычисляет ДВА `MemoryVersion` (base vs enriched, разбивка по
|
||
`Source` ниже), апсертит ДВА снапшота (W1/W2), пинит стадии волны к своему. Сейчас все стадии получают ОДИН `snapID`;
|
||
план делает `MemoryVersion` (и stage-plan) компонентом волны:
|
||
- `snapshot_W1 = f(brief, chunkerVersion, draft-stage-plan, base-bank-version, coverage/sanitizer/classifier/…)`.
|
||
- `snapshot_W2 = f(brief, chunkerVersion, edit-stage-plan, enriched-bank-version, …)`.
|
||
W1.5-обогащение банка двигает ТОЛЬКО `enriched-bank-version` → ТОЛЬКО `snapshot_W2`. W1 стабилен.
|
||
|
||
**Механизм стабильности W1 на РЕЗЮМЕ (несущее, закрывает re-bill-дыру):** после W1.5 сид ОБОГАЩЁН (дельта влита) →
|
||
наивный пересчёт `snapshot_W1` из ТЕКУЩЕГО (обогащённого) банка дал бы enriched-memory-version → mismatch с замороженным
|
||
в W1-джобах `snapshot_id` → resnapshot-стоп → re-bill W1. Фикс использует поле **`Source`** (`glossary.go:36`,
|
||
`seed|ruby|auto` + новое `mined` WS3): **`base-bank-version` = хеш approved-строк с `Source∈{seed,ruby}` (БЕЗ mined);
|
||
`enriched-bank-version` = хеш ВСЕХ approved-строк (вкл. `Source:mined`).** Майненые строки исключены из W1-фолда →
|
||
`computeMemoryVersion`-вариант для W1 пере-вычисляется из НЕ-майненых строк, стабилен через W1.5-обогащение (майнинг
|
||
только ДОБАВЛЯЕТ mined-строки, не трогает seed/ruby) → `snapshot_W1` воспроизводится идентично на резюме → W1-чекпоинты
|
||
ХИТ, не пере-оплачиваются. Детерминировано (фильтр по `Source` + сортировка `GlossaryForBook`). Пиновый тест — (д).
|
||
|
||
**⚠ Скоуп подписи W1.5 = ТОЛЬКО `Source:mined` (ревью-2 F2, инвариант — прямое следствие фикса выше):** mid-run
|
||
подпись владельца на W1.5-границе трогает ИСКЛЮЧИТЕЛЬНО `Source:mined`-строки (промоут draft→approved, правка dst
|
||
майненого терма). Правка/промоут **APPROVED** `Source∈{seed,ruby}`-строки ДВИГАЕТ `base-bank-version` → mismatch с
|
||
замороженным в W1-джобах `snapshot_W1` → resnapshot-СТОП / re-bill W1 — поэтому разрешена ТОЛЬКО как ОТДЕЛЬНОЕ
|
||
resnapshot-событие ВНЕ прогона (пред-прогонный reseed §8), НЕ на W1.5-границе. (Уточнение precision: DRAFT-status
|
||
seed/ruby-строка НЕ фолдится в `base-bank-version` [gate off, `memory.go:264-266`], но W1-инъектится через
|
||
`renderGlossaryBlock` → её правка = ТИХИЙ per-чанк re-bill через contentHash-путь `stagerun.go:72-79`, не громкий стоп;
|
||
реалистично seed/ruby = approved, пин (д) это разделяет.)
|
||
- **Write-path `Source:mined` (ревью-2 пост-верифай, НЕСУЩЕЕ — закрывает грунт-гэп критика):** `loadGlossarySeed`
|
||
БЕЗУСЛОВНО штампует `Source:"seed"` (`memseed.go:131`) — наивный reseed W1.5-дельты через него проштамповал бы
|
||
майненые термы `Source:seed` → они попали бы в `base-bank-version` → сдвинули `snapshot_W1` → сломали «переоплата
|
||
ОДНА». ⇒ **персист майненой дельты после подписи идёт ОТДЕЛЬНЫМ mined-write-путём** (штамп `Source:mined`, зеркало
|
||
`rubyToCandidates`'s `Source:"ruby"` `memseed.go:352`) — НЕ через немодифицированный `loadGlossarySeed` (хардкодит
|
||
`Source:"seed"` `:131`) и НЕ расширением `seedTerm`-схемы (та остаётся БЕЗ новых полей — §3(б); Source-класс живёт в
|
||
сайдкар-карте подписи). Пин — WS3 (д).
|
||
- **Промоут `甲乙丙丁`/`四代族长` (DC-7):** майнер СЮРФЕЙСИТ их как `Source:mined` draft (флаг-для-видимости §3(б)); но их
|
||
промоут в approved-канон = **ЭЛЕВАЦИЯ в `Source:seed`** (канон грейд/титул = base-seed-класс, не run-time mined) →
|
||
поэтому строго в пред-прогонный reseed (§8, `MemoryVersion` двигается), НЕ в W1.5-подпись.
|
||
Пин-тест — (д): правка approved seed-строки после W1 → ГРОМКИЙ resnapshot-стоп, не тихий re-bill.
|
||
|
||
**Механика W1.5 для ОБОИХ состояний гейта (доказуемо «переоплата ОДНА»):**
|
||
- **`PostcheckGate=false` (текущий дефолт):** `computeMemoryVersion(rows, gateOn=false)` фолдит ТОЛЬКО approved-строки
|
||
(`memory.go:264-266`). Майненые auto/draft НЕ двигают снапшот; их вливание меняет лишь инъекцию стадий, которые их
|
||
инъектят. На момент W1 банк = base (майнинг идёт ПОСЛЕ W1) → W1-инъекция = base. В W1.5 подпись владельца
|
||
промоутит часть в approved → `enriched-bank-version` меняется → `snapshot_W2` двигается ОДИН раз. Auto/draft
|
||
(AMBIGUOUS) в редакторский блок (`renderEditorConstraintBlock`, CONFIRMED-only, `memory.go:515`) НЕ входят.
|
||
- **`PostcheckGate=true` (hard-gate, висит за пере-замером D24.4/D28.1):** `computeMemoryVersion(rows, gateOn=true)`
|
||
фолдит ВСЕ строки вкл. auto/draft + `gate:`-флаг (`memory.go:251-266`, `snapshot.go:86-93`). Но на момент W1
|
||
майненых строк ещё НЕТ → `base-bank-version` реально base. В W2 банк обогащён → `enriched-bank-version` включает
|
||
все майненые строки. Пер-волновой снапшот держит «одну переоплату» и здесь: W1 под base, W2 под enriched.
|
||
|
||
**UX-решение (стоп посреди книги) — владельцу** (§10 вопрос W1.5-UX; §E-5 research/20). Дефолт плана: W1.5 — **явная
|
||
стоп-граница** (не mid-run-append): раннер завершает W1, пишет карту подписи, ОСТАНАВЛИВАЕТСЯ; владелец подписывает;
|
||
`tmctl` возобновляет с W2 под `snapshot_W2` (`--resnapshot` принимает сдвиг). Sticky/scene-инерция precompute'ится в
|
||
W0 (src-производна) — не ломается параллелизмом.
|
||
|
||
**Scheduler-aware диспетчер:** ценовые окна = **конфиг провайдера** (`providers.json`/`models.yaml`), не хардкод.
|
||
Вендор-чеки ($0, разрешены):
|
||
- **(а) DeepSeek пик/офф-пик — РАЗРЕШЁН (флаг D39.10-6):** два механизма из разных эр, НЕ конфликт. Легаси off-peak
|
||
СКИДКА `16:30–00:30 UTC −50%/−75%` — только **V3/R1**, НЕ переносить на v4. Актуально для v4: **PEAK-надбавка ×2** в
|
||
**UTC 01:00–04:00 ∪ 06:00–10:00** (пики Пекин 09–12 & 14–18); офф-пик = baseline (доп. скидки НЕТ).
|
||
⚠ **×2 подтверждён ТОЛЬКО вторичкой** (TechNode/explainx/KuCoin); офиц. `api-docs.deepseek.com/quick_start/pricing`
|
||
на 2026-07-19 — ФЛЭТ, без peak/off-peak. Правило двух направлений: **держать ×2 как РИСК-ПИН**, ре-чек у катовера
|
||
24.07. Раннер: платные DeepSeek-джобы вне пик-окон; нельзя — закладывать ×2, не блокировать. (URL: docs §157–167.)
|
||
- **(б) ZAI/GLM префикс-кэш — РАЗРЕШЁН (§E.8-бис):** implicit префикс-кэш подтверждён на `glm-5`
|
||
(`docs.z.ai/guides/capabilities/cache`); cache-hit = **$0.20/1M (−80% от input $1.00)**, НЕ 50% из иллюстрации доки;
|
||
хранение бесплатно (limited-time); TTL официально НЕ документирован (агрегаторные «5мин/512ток» НЕ подтверждены).
|
||
Warm-then-fan оправдан: warming-вызов платит полный input, фан-аут-соседи — cache-hit. Инвариант байт-идентичного
|
||
ПРЕФИКСА (`[система+мандаты]+[глоссарий сорт-ключи]→[волатильный чанк в хвост]`, research/19:506): любой timestamp/
|
||
счётчик-ретрая/«почему упало» — только в ХВОСТ (`:213`). Бэкенд УЖЕ читает `cached_tokens`
|
||
(`httpllm.go:232-255`); реальную долю cache-hit верифицировать в ledger (эмпирика бьёт веру, TTL-риск).
|
||
- **(в) Слаги DeepSeek 24.07 — РАЗРЕШЁН:** `deepseek-chat`/`deepseek-reasoner` депрекация **2026-07-24 15:59 UTC** →
|
||
оба на v4-flash (chat=non-thinking, reasoner=thinking). Наш прод `deepseek-v4-flash`/`deepseek-v4-pro` — НЕ задет.
|
||
**Действие бэкенду:** grep `configs/models.yaml` + eval-скриптов на legacy-слаги + live `GET /models`. (research/19
|
||
§E.8: eval-скрипты несут legacy-слаги — `exp15/preflight_models.py:32`, `local_bench.py`, `editor_bench.py:36` —
|
||
это eval-долг, не прод.)
|
||
|
||
### (г) Верификация ДО стройки ($0) — `ws1_wave_cogs.py`, РЕЗУЛЬТАТ
|
||
- **Money-инвариант (mock, моделирует single-writer admission-ось `ledger.go`; НЕ полное зеркало — см. каветы):
|
||
ALL PASS** — `committed==SUM($0.448)`, `reserved=0`, **kill-9 без двойной оплаты** (идемпотентный settle
|
||
`ledger.go:143` ON CONFLICT DO NOTHING). ⚠ **Границы — ПАРАЛЛЕЛЬНЫЕ, не последовательные** (адверсариал-ревью-1):
|
||
(1) kill-9 теряет **≤N in-flight вызовов** (`recoverReservations` обнуляет ВСЕ `reserved_usd`, `store.go:219`),
|
||
каждый пере-оплачен ОДИН раз — не «≤1»; (2) overshoot: реальный `Reserve` ОТКЛОНЯЕТ при `bookTotal+estimate>ceiling`
|
||
(`ledger.go:67-71`) → reserved потолок не пробивает; единственный overshoot-источник = settle бронирует `cost` при
|
||
`cost>estimate` (pricier `modelActual` `PriceForResponse` `stagerun.go:420`; reasoning-overflow) → под N резервами
|
||
bound = `Σ(cost_i−est_i)`. Mock это НЕ проверяет (`cost=0.008<est=0.01` захардкожен) → закрепляет Go-тест в (д).
|
||
Каветы неверности mock: проверяет ОДИН потолок (реальный book И day `ledger.go:67-71`); settle НЕ идемпотентен
|
||
(реальный да, `ledger.go:151-160`) — обе оси в Go-тест (д). Реальную durability пинит Go+SQLite `-race`+kill-9
|
||
**с N живыми резервами** в (д).
|
||
- **Wall-clock (mock-латентности, LPT bin-pack):** ВНУТРИ-ВОЛНОВАЯ compute-параллелизация sequential-compute **1896s**
|
||
→ волны 8-воркеров **258s ≈ 7.3×** (W1 121s + W2 138s). ⚠ **End-to-end доминирован W1.5 человек-стопом** (подпись
|
||
владельца между волнами — неограниченное ожидание, в 7.3× НЕ входит); mock — единый `LAT_PER_KTOK` для thinking-ON
|
||
черновика и редактора (разные профили). ⚠ **7.3× НЕ учитывает rate-limit-столлы** (ревью-2 F4): пер-модельный
|
||
семафор + 429-бэкофф сериализуют вызовы к лимитированной модели (mistral ~48% retry-fails) → реальный wall-clock
|
||
волны ниже compute-идеала. Порядок-величины; точные латентности — прод-телеметрия.
|
||
- Структура: 25 глав → **56 draft-чанков** (target_out 1797) + **25 edit-единиц**. COGS — WS6 (г).
|
||
|
||
### (д) Тест-спека ПОСЛЕ стройки
|
||
- `go test -race ./...` над волновым раннером: N-воркер прогон, детектор гонок чист (клиенты/store/templates/memory).
|
||
- kill-9-тест **с N живыми резервами**: убить процесс между `Reserve` и `SettleWithCheckpoint` для N чанков → рестарт:
|
||
`recoverReservations` обнуляет резервы, ретрай оплачивает ≤N вызовов ОДИН раз каждый; `committed==SUM(checkpoints.cost)`
|
||
(порт `store/kill9_test.go` на волны). + overshoot-тест `cost>estimate` (pricier modelActual): overshoot ≤ Σ shortfall.
|
||
- Golden: **инъекц-байты W0-precompute sticky ≡ байтам текущего последовательного раннера** над НОВЫМ чанк-сетом WS2
|
||
(fresh↔resume; sticky не двигает request_hash над base-банком).
|
||
- **НЕСУЩИЙ пин (ревью-1 F1): draft `request_hash`/`contentHash` БАЙТ-СТАБИЛЕН под ОБОГАЩЁННЫМ банком** — W2-проход не
|
||
пере-рендерит draft-стадию; редактор читает черновик по `final_hash`. (Не просто «`snapshot_W2` двигается».)
|
||
- Пер-волновой снапшот: промоут майненых→approved двигает ТОЛЬКО `snapshot_W2` (W1-джобы не ловят resnapshot-стоп);
|
||
`base-bank-version`=хеш `Source∈{seed,ruby}`-строк стабилен через W1.5.
|
||
- **Пин скоупа подписи W1.5 (ревью-2 F2):** правка/промоут `Source∈{seed,ruby}`-строки ПОСЛЕ W1 → ГРОМКИЙ
|
||
resnapshot-стоп (не тихий re-bill W1); правка ТОЛЬКО `Source:mined`-строки → двигает лишь `snapshot_W2`, W1 стабилен.
|
||
- Race-тест `Runner.clients` (D12-урок): `client()` read-only в волнах, panic на miss не-перечисленной модели.
|
||
|
||
### (е) Открытое / маршрутизация
|
||
- **Соседи-черновики как контекст W2 — НЕ ратифицированы** (Q3a null + гипотеза CJK-протечки V2-брака §7.9: src-
|
||
carryover → больше исходника → выше протечка). **Дефолт: без них.** Если бэкенд захочет — обоснуй + дешёвый гейт.
|
||
- **Lookahead (Q3b) — парковка** (не тестировано). Не в дефолт.
|
||
- **W1.5-UX (стоп посреди книги vs автопродолжение)** — вопрос владельцу (§10).
|
||
- Пик-надбавка DeepSeek ×2 — риск-пин, ре-чек 24.07 (§10).
|
||
|
||
---
|
||
|
||
## §2. WS2 — Чанкер-бюджет + крупная edit-единица (слой 1)
|
||
|
||
### (а) Что меняем (file:line)
|
||
- **`chunker.go`** — бюджет из `const targetChunkTokens = 1500` (`:47`, единица `estTokensFrom=cjk+other/3` `:173-181`)
|
||
→ **конфиг per-pair в ВЫХОДНЫХ токенах через фертильность**; `Chunk{Chapter,ChunkIdx,Text}` (`:32-36`) расширяется
|
||
аддитивно (`EstOut float64`, `OversizedSentence bool`, `EditUnitID int`). Мега-ПРЕДЛОЖЕНИЕ (`packSentences:129-152`:
|
||
своё оверсайз-под-чанком БЕЗ клауза-сплита и БЕЗ флага) — решить (см. (б)).
|
||
- **`config/pipeline.go`** — снести мёртвые `STMDepth`/`OverlapTokens` (`:47-48`, carryover не строим); добавить
|
||
`Segmentation{DraftBudgetOut int, EditCeilingOut int, Fertility{CJK,Other float64}}` (per-pair, снапшот-folded).
|
||
- **`coverage.go`** — инвариант floor: draft-бюджет держит чанки над `Gates.Coverage.MinChunkChars` (`pipeline.go:159`,
|
||
дефолт 500); связь-инвариант, не жёсткий (хвосты глав легально < floor — документ. граница `chunker.go:42-45`).
|
||
- **`snapshot.go`** — `contextSnap` (`:15-21`) теряет STMDepth/OverlapTokens; добавляется `segmentationSnap`
|
||
(бюджет+фертильность+edit-ceiling, фолд как `coverageSnap`).
|
||
- **новый `slojpjat`-омиссия-бэкстоп** в слое 5 (см. WS5/(б)) — компенсатор зоны деградации.
|
||
|
||
### (б) Алгоритм
|
||
- **Draft-чанк = мелкая единица (COGS/coverage/выравнивание):** greedy-упаковка абзацев (как сейчас,
|
||
`appendChapterChunks`), но бюджет = `est_out(chunk) = 1.1978·cjk + 0.3852·other` (ВЫХОДНЫЕ токены) вместо
|
||
input-est. Оверсайз-абзац → `packSentences`; НИКОГДА не резать предложение. (WS2 (г): на zh смена единицы
|
||
near-нейтральна — тот же СЧЁТ 56 чанков при target_out=1797, НО **4 из 56 чанков ре-сегментируются (2 реальных
|
||
абзац-сдвига** на границе накопления, где est_out other-вес 0.3852 vs input-est integer other/3 расходятся) → НЕ
|
||
byte-identical → законный `chunkerVersion` bump §8. Ни один target_out не даёт 0 diff.) `strategy`-ось (`greedy|logical`) —
|
||
заложить как СЕАМ (аддитивное поле), но наполнение `logical` НЕ строить (Q1 «граница не рычаг», Q1a 0/7). DP §B1.5
|
||
(штрафы B0:0/B1:1/B2:3/B3:6/B4:10, веса w_size=3/w_bound=60/w_dialog=200) — справочно в research/19, НЕ реализуем.
|
||
- **Мега-предложение (решение плана):** `packSentences` пропускает мега-ПРЕДЛОЖЕНИЕ оверсайз-под-чанком без флага.
|
||
**Решение: passthrough + флаг `OversizedSentence=true`** (не аварийный клауза-сплит ;:,、 из §B1.4). Обоснование:
|
||
клауза-сплит = граничная машинерия (анти-скоуп); «деградация не молчит» удовлетворяется ФЛАГОМ (наблюдаемость).
|
||
Мега-абзац уже покрыт (`packSentences`). Стихи/паратекст — как обычный текст (§0.1: не спец-кейсить структуру
|
||
книги); стих-РЕНДЕР — пак-политика WS5-DC5.
|
||
- **Edit-единица = глава** — ДЕКАПЛИНГ draft/edit ратифицирован (D39 п.4, exp14 претензия-1: редактору нужна КРУПНАЯ
|
||
единица для меж-чанковой когезии). Глава = естественная дискурс-граница; глава > `EditCeilingOut` → деление по
|
||
АБЗАЦНЫМ границам greedy до потолка (never-split-paragraph). На 25-гл книге при **дефолте 3200: 11 глав делятся →
|
||
37 edit-единиц** (при гейтнутом 8000-арме — 25 цельных глав, 0 > 8000, max 6528, все в 2k–8k; ревью-2 F1 — детали
|
||
(г)). ⚠ **РАЗМЕР единицы ГЕЙТИТСЯ (ревью-1 F1, не «безопасно»):** span-омиссия Q2a НЕ
|
||
гонялась; omission-бэкстоп WS5 — сеть ENTITY-уровня (сущность есть где-угодно), СТРУКТУРНО СЛЕП к пропуску
|
||
клауза/сцены внутри 6.5k-единицы, чьи сущности повторяются (сам `reflow_omission.py:205-212`: «NOT evidence big
|
||
chunks omission-safe… needs SPAN-JUDGES; Q2b cannot ratify edit=chapter, only Q2a»). **Решение:** глава-единица —
|
||
ЦЕЛЬ; для пере-прогона `EditCeilingOut` — **консервативный дефолт ≤3200 out** (край нижней зоны деградации, а не
|
||
6.5k), большая-глава-арм ГЕЙТИТСЯ платными Q2a span-судьями (прогон-протокол WS6/(д)) + чтением владельца (2-претензии
|
||
ловят span-омиссию). Owner-развилка §10. Единица маппится на чекпоинты: **деньги/resume per-СТАДИЯ-волна**, НЕ
|
||
per-микро-чанк — против инварианта №1: чекпоинт = единица оплаты стадии, волна = последовательность.
|
||
- **Сайзинг edit-единицы (ревью-2 F8, ИСПРАВЛЕНО пост-верифай):** unit-awareness сайзинга УЖЕ автоматическая —
|
||
`stagerun.go:87-90` (D2.5) сайзит `max_tokens` от `sizingText=prev` (для стадии >0 = ЧЕРНОВИК всей единицы, НЕ
|
||
источник): `EstimateTokens(prev)·MaxOutputRatio` + пер-модельный флор D24.3 (`applyModelFloor`); `Reserve` тоже
|
||
text-proportional по msgs. ⚠ **НЕ сайзить от `est_out` единицы** (первичная формулировка F8 «от est_out» НЕВЕРНА):
|
||
`est_out=1.20·cjk+0.39·other` ИСТОЧНИКО-производна и в glm-4.6 output-token-пространстве (≠ эвристика `EstimateTokens`
|
||
cjk+other/3), а D2.5 прямо сайзит редактора от ЧЕРНОВИКА (~1.9× источника) — сайзинг от источника недо-бюджетит и
|
||
ложно-триггерит length-ретрай. ⇒ единственное требование: edit-единица передаёт СВОЙ ПОЛНЫЙ черновик как `prev`
|
||
(волновой дизайн W2 это и делает, §1(б)); НОВОЙ формулы сайзинга НЕТ → строки манифеста §8 F8 не требует. **Инъекция
|
||
единицы (ревью-2 F3, детали §1(б)):** свежий `memory.Select` по тексту ВСЕЙ единицы над ОБОГАЩЁННЫМ банком (НЕ реюз
|
||
per-чанк W0-`memSel` над base); формат src→dst, CONFIRMED-only.
|
||
- **Формат банк-констрейнтов редактора (открытый вопрос D30.1, `memory.go:505-511` — решается ЗДЕСЬ, парковка
|
||
запрещена):** сегодня `renderEditorConstraintBlock` (`:515`) даёт ГОЛЫЕ dst-формы (`- «dst»`, CONFIRMED-only,
|
||
дедуп по dst). **Решение: перейти на src→dst-мэппинг** (`- 源термин → «dst»`), как у переводчика. Обоснование
|
||
(единственное несущее — ревью-1 F4 снял два ложных): **редактор БИЛИНГВ (D30.1, `editor.md:1` видит источник) —
|
||
привязка канона к src-терму устраняет неоднозначность при ОМОНИМИЧНЫХ dst** (одна ru-поверхность на две сущности).
|
||
⚠ Отвергнутые обоснования: «AMBIGUOUS-строк станет больше» — НЕ-секвитур (блок CONFIRMED-only `memory.go:519`, майненые
|
||
AMBIGUOUS сюда НЕ входят); «инвариант кэш-префикса» — нет (блок из per-chunk `memSel.injected` = волатильный ХВОСТ, не
|
||
стабильный префикс). Мех-безопасность: `RequestHash` хеширует `msgs` вкл. блок → формат-правка меняет request_hash,
|
||
тихого false-hit нет; CONFIRMED-only СОХРАНЯЕТСЯ; дедуп по (src,dst) лишь РАСШИРЯЕТ список (безвредно). **Снапшот-фолд
|
||
ЯВНЫЙ:** формат рендера `renderEditorConstraintBlock` НЕ схватывается `memoryMatchVersion` (тот = нормализатор/матчер) —
|
||
добавить версию формата рендера как folded-компонент снапшота (иначе loudness держится дисциплиной, не механизмом).
|
||
|
||
### (в) Конфиг + снапшот
|
||
- Фертильность `{cjk:1.1978, other:0.3852}` — конфиг слоя 2 (per-pair), снапшот-folded; **пересчёт = громкий
|
||
resnapshot** (D30.9). Go грузит ТОЛЬКО коэффициенты (не токенайзер).
|
||
- `DraftBudgetOut` дефолт **1797** (тот же СЧЁТ 56 чанков, что текущий input-est=1500 на zh; 4 чанка ре-сегментируются,
|
||
2 абзац-сдвига — НЕ byte-identical, WS2 (г)) — «tunable, ревизия по пере-прогону».
|
||
- `EditCeilingOut` дефолт **3200 out** (ревью-2 F1: приведено к WS2(б)/§7/§10-13/§11 — прежнее «8000» ЗДЕСЬ
|
||
противоречило консервативному дефолту; 3200 = край нижней зоны деградации) — tunable. **8000 out = потолок
|
||
ГЕЙТНУТОГО крупно-главного арма** (верх зоны деградации research/19 §A.1.1), открывается ТОЛЬКО по платным Q2a
|
||
span-судьям (§10-13), НЕ дефолт.
|
||
- Снос STMDepth/OverlapTokens меняет `contextSnap`-структуру → **строка манифеста resnapshot §8** (снапшот двигается).
|
||
- ⚠ **Классификатор CJK (WS2 (г) находка §1.6):** `fertility_calib.is_cjk` = ord-диапазоны БЕЗ Hangul;
|
||
`EstimateTokens` (`render.go`) = `\p{Han}\p{Hiragana}\p{Katakana}\p{Hangul}`. На ЭТОМ zh-корпусе — **0 сдвиг
|
||
коэффициентов** (verified — но КОРПУС-СПЕЦИФИЧНО: корпус не содержит спорных символов `々/〇`/CJK-радикалов, kana-марок
|
||
`・ー`). ⚠ **ws2_fertility_verify классификатор B — НЕ верный Go-прокси** (ревью-1 F3: исключает `々/〇`/радикалы,
|
||
что `unicode.Han` включает; включает `・ー`, что `unicode.Katakana` исключает) → скрипт НЕ доказывает ja/ko-общность.
|
||
**Решение: Go-порт использует РЕАЛЬНЫЕ `unicode.RangeTable` `EstimateTokens`** (для общности §0.1); инвариантность
|
||
задокументирована для ДАННОГО zh-корпуса, не как свойство классификатора; ja/ko-паритет — верифицировать Go-таблицами
|
||
(после стройки). Коэффициенты не менять (impact на текущий zh = 0 подтверждён).
|
||
|
||
### (г) Верификация ДО стройки ($0) — `ws2_fertility_verify.py` + `ws2_chunk_sim.py`, РЕЗУЛЬТАТ
|
||
- **Независимый пере-вывод фертильности** (НЕ доверяя `fertility_calib.json`): `f_cjk=1.1978, f_other=0.3852,
|
||
R²=0.9633, MAPE 4.25%, n=52` — Δ vs артефакт `< 3e-5`. Классиф.-mismatch impact на zh = **0.0%**.
|
||
- **Симуляция нарезки 25 глав:** гистограммы est_out; `target_out=1797` → **56 чанков** (mean 1408.8, max 1795) — тот
|
||
же СЧЁТ, что текущий input-est=1500, но **4 из 56 чанков ре-сегментируются (2 реальных абзац-сдвига**; проверено
|
||
прямым diff чанк-сетов: чанк 1 = 1777 vs 1778 симв, чанки 11↔12 и 54↔55 — абзац переезжает; ни один target_out не
|
||
даёт 0 diff). Смена единицы near-нейтральна на zh, НЕ no-op/byte-identical. Floor: 4 чанка < 500 симв (хвосты).
|
||
Edit-единица — **ДВА конфига симулированы (ревью-2 F1, пере-сим at 3200, `ws2_chunk_sim.py` ceiling∈{8000,3200}):**
|
||
**(i) ГЕЙТНУТЫЙ 8000-арм** — 25/25 глав-единиц в зоне 2k–8k out (0 глав > 8000, max 6528, hist: 14×[2k–3.2k]/10×[3.2k–5k]/
|
||
1×[5k–8k]); **(ii) РАТИФИЦИРОВАННЫЙ дефолт 3200** — 25 глав → **37 edit-единиц** (11 глав > 3200 делятся абзацно на 23
|
||
под-единицы; hist out: 26×[2k–3.2k], 10×[0–1k] split-хвосты (< нижней зоны деградации — покрыты omission-бэкстопом),
|
||
1×[1k–2k]). ⟶ «25/25 в 2k–8k» описывал 8000-арм, НЕ дефолт; при 3200 единицы МЕНЬШЕ (безопаснее для span-омиссии —
|
||
цель F1) ценой 10 мелких split-хвостов. **omission-бэкстоп (слой 5) = СЕТЬ, НЕ доказательство безопасности** (Q2a
|
||
span-омиссия НЕ гонялась; бэкстоп entity-уровня слеп к span-пропуску → размер edit-единицы гейтится, см. (б)/(е)).
|
||
- COGS-прогноз (no-cache upper bound): $0.403/25-гл; с кэшем — WS6.
|
||
|
||
### (д) Тест-спека ПОСЛЕ стройки
|
||
- Пин: `est_out`-бюджет на zh даёт СЧЁТ 56 чанков (не byte-identical к input-est) + fresh↔resume детерминизм.
|
||
- Пин: мега-предложение → `OversizedSentence=true` флаг (синтетика).
|
||
- Пин: глава > `EditCeilingOut` → абзацный сплит (never-split-paragraph, tiling lossless).
|
||
- Пин (ревью-2 F8, испр.): `max_tokens`/`Reserve` edit-единицы сайзятся от ПОЛНОГО ЧЕРНОВИКА единицы (`prev`,
|
||
`EstimateTokens(prev)·MaxOutputRatio` + флор D24.3, D2.5) — НЕ от источника/`est_out`; синтетика: крупная глава,
|
||
переданная целиком как `prev`, получает unit-масштабный `max_tokens` без ложного length-ретрая.
|
||
- Golden re-capture: снос STMDepth/OverlapTokens + фертильность-бюджет = маскированный дифф старого↔нового снапшота
|
||
(только хеши/версии + новые поля).
|
||
|
||
### (е) Открытое / маршрутизация
|
||
- `logical`-стратегия — СЕАМ, наполнение парковано (Q1). `DraftBudgetOut`/`EditCeilingOut` — tunable, ревизия по
|
||
пере-прогону. src→dst редакторский мэппинг — решён здесь (в план), не хвост.
|
||
- **Бюджет whole-chapter `Select` для W2-инъекции редактора (ревью-2 пост-верифай, открытый):** свежий Select по ВСЕЙ
|
||
единице над enriched-банком (§1(б)/F3) не имеет пиннутого token-бюджета; per-чанк `GlossaryTokenBudget` на всю главу
|
||
(много больше матчей) может вытеснить approved-канон и разбавить enriched-энфорс. Бэкенду: per-глава бюджет ИЛИ
|
||
unbounded для констрейнт-блока редактора (решить в пак-2).
|
||
|
||
---
|
||
|
||
## §3. WS3 — Банк-машинерия W1.5 в Go (слой 4)
|
||
|
||
Go-порт детектора V-C (WHICH) + алиас-ярус-1 + консолидация §C2 + эмиссия сид-дельты. **WHAT (dst) = НЕ ко-оккуренция**
|
||
(canon-recovery 0.20–0.68 < 70%) → dst через банкноту (WS4) + Палладий (имена) + облако (термы Z1/Z3).
|
||
|
||
### (а) Что меняем (file:line)
|
||
- **новый `backend/internal/pipeline/miner*.go`** — детектор V-A→V-B→V-C (авторитет = exp16 `arms.py` FROZEN, НЕ
|
||
пересказ research/20 §B); алиас-ярус-1 (`alias.py` R1–R4); консолидация (`canon.py` §C2); эмиссия сид-дельты.
|
||
- **`memseed.go`** — `loadGlossarySeed` (`:64-186`) читает BASE-сид + сухую валидацию дельты (штампует `Source:"seed"`
|
||
`:131`); **но ПЕРСИСТ майненой дельты после подписи — ОТДЕЛЬНЫМ mined-write-путём** (штамп `Source:mined`, зеркало
|
||
`rubyToCandidates` `:314-360`), НЕ через `loadGlossarySeed` (F2, §1(в) — иначе `Source:seed` двигает `snapshot_W1`);
|
||
**новый `tmctl seed-lint`** (сухой прогон фейл-лаудов по дельте: `:87` src, `:94-98` dup, `:104-108` status,
|
||
`:113-115` draft/approved-dst, `:161-181` спойлер-оверлап, `:201-237` shared-key).
|
||
- **`store/glossary.go`** — `GlossaryEntry.Source` (`:36`, сейчас `seed|ruby|auto`) += **`mined`**; единая схема
|
||
кандидата ruby↔mined (research/20 §E-бэкенд-5).
|
||
- **`store/ruby.go`-паттерн** — прецедент `rubyToCandidates` (`memseed.go:314-360`: Source:ruby, status:auto, no dst,
|
||
Confidence=occ) зеркалится для mined-канала.
|
||
- **артефакты детектора** — контраст-словарь (jieba SHA `7197c321…`, вне git, воспроизводим из jieba 0.42.1
|
||
`dict.txt`), паттерн-инвентари (`PACK_VERSION="zh-universal-v1"`), Палладий-таблица (~400 слогов, генерируемая).
|
||
|
||
### (б) Алгоритм (frozen miner-v1 = exp16 §1.2 арм A3; ТОЧНЫЕ пороги)
|
||
**Детерминизм-контракт:** все ранкинги сорт `key=(-score, -freq, src)`; occurrence-count перекрывающийся (`pos=i+1`),
|
||
**suppress-free** (D24.2 — subsume чистит ТОЛЬКО ранжирование); norm = `normalizeSourceKey` (memnorm.go, trad2simp→
|
||
NFKC→lowercase); Contrast-коллизия → MAX freq; Laplace `(cf+1)/(total_char+|distinct|)` идентичен в char_indep_rel и
|
||
detect_formants; Палладий-сегментация жадная longest-first, ъ отбрасывается.
|
||
|
||
- **V-A:** кандидаты = Han-n-граммы **1–6** (БЕЗ сегментации); `freq_floor=3`; c-value nested-дисконт с
|
||
**`g(L)=log₂(L+1)`** (НЕ `log₂(L)` — иначе 蛊/转 зануляются, катастроф-скрин FAIL, 蛊 rank 4753); weirdness =
|
||
`p_book/max(word_rel, char_indep_rel, 1e-9)`; `score = max(cval,0)·termhood^1.0`, `termhood=log1p(weirdness)`;
|
||
subsumption `α=0.80` (дроп a если ∃ длиннее b, a⊂b, f(b)≥α·f(a)).
|
||
- **V-B:** + spread (Dice ко-оккуренция ru-лемм, pymorphy3) `score·(1+λ·spread)`, `λ=0.0` на инъект-черновиках
|
||
(spread ВРЕДИТ, конфаунд §D1), свип >0 только на cold-start; `spread_freq_min=5`; dst_variants `top=4, min_dice=0.05,
|
||
co-salience need=max(2, round(0.30·|chunks|))`.
|
||
- **V-C:** + паттерн-каналы (`patterns.py`): (1) 百家姓-якорь (SURNAMES_SINGLE после `.discard(凝)` + SURNAMES_COMPOUND
|
||
16 вкл. 古月; окно 1–2 Han справа → name); (2) титул-суффиксы (TITLE_SUFFIX 26, ≤3 Han слева → title) + (2b)
|
||
ordinal_title (ORDINAL 15 + suffix → 四代族长); (2c) rank/grade (GRADE_PREFIX 甲…癸 / NUMERAL / RANK_WORD 等转阶级重
|
||
品段层 → title, ловит 等/转 форманто-невидимые); (3) топо-суффиксы (TOPO_SUFFIX 26 → place); (4) авто-формант
|
||
(`detect_formants`: символ c продуктивен если ≥`min_partners=3` различных морфем-партнёров И
|
||
`over_rep=p_book/p_gen≥15.0` — над-представленность, НЕ редкость; изолирует 蛊/窍/虫, отвергает 师/花/等); (5)
|
||
Палладий ru-канал (`is_palladius_token` + кап-лемма-гейт `is_name_lemma` → блок «найти»=най+ти; бонус +56.0).
|
||
Бонусы `{name/place:140, title:120, term:80}`×pattern_source_weight `{surname:1.0, ordinal_title:1.0,
|
||
rank_grade:1.0, title_suffix:0.9, topo_suffix:0.9, palladius:0.8, formant_suffix:0.6, formant_prefix:0.5,
|
||
title_bare:0.4, default:0.3}` (pw = МАКС по evidence); sub-floor `score=bonus+40.0·f·pw`. `top_k=90` операционная точка.
|
||
- **Алиас-ярус-1 (R1–R4, `alias.py`, precision-safe, R4 hard-blocks ПЕРВЫМИ):** R4-ii (разный пол, кроме hidden) →
|
||
R4-iii/v (разный approved dst → разные сущности ДАЖЕ при containment: блок `族长⊂四代族长` [D38 §3], `古月⊂古月方源`) →
|
||
R1 containment (|X|≥2 → extension; **компози-гард**: long=short+Y, Y∈{title,place,term}∩gt → ФРАЗА не алиас, блок
|
||
`古月+族长`, сохрани `古月+方源`) → R2 фамильный якорь → family (не identity; R4-i разные имена) → R3 общий ru-рендеринг
|
||
→ identity (**кап-лемма-гейт**: Палладий-токен И name-lemma min_syl=2). R4-iv `cooccur_same_sentence`. Кластеризация
|
||
union-find по identity-рёбрам, `sorted`. Метрика — **B³ (entity-level), НЕ MUC**.
|
||
- **Консолидация §C2 (`canon.py`):** канон по ВСЕМ вхождениям (НЕ first-wins, анти-LTCR) × Палладий-конформность
|
||
(name/place) × полнота падежной леммы. `canon_recovery cover_frac=0.5`. **Майнер по построению НЕ пишет approved**
|
||
(канон-предложение = draft). Пол = 他/她-счётчики evidence, вердикт владельца (D19.3, hidden невыводим). since_ch =
|
||
первая глава вхождения (авто); until_ch — только человек.
|
||
- **Эмиссия сид-дельты §C2-7:** YAML в схеме `seedTerm` (`memseed.go:30-57`, БЕЗ новых полей): non-seed кандидат с
|
||
banknote/canon dst → `status:draft` (dst, ⟨проверить⟩); WHICH-only без dst → `status:auto` (инертен). Алиасы —
|
||
поверхностями терма. Evidence/Source-класс/зоны Z1–Z5 — в сайдкар-карту подписи (прецедент
|
||
`diag/glossary_v2_signoff.md`), НЕ в схему сида. Пре-валидация против фейл-лаудов loadGlossarySeed = часть карты.
|
||
**Эмиттер обязан реюзить subsumption+fragment-фильтры** (`emit_owner_sheets.build_precision30`: тип∈{name,place,
|
||
title}, freq≥5, src∉subsumed, len≥2, не фрагмент по PARTICLE-сету), а НЕ сырой 13618-дамп (WS3 (г) находка: сырой
|
||
дамп несёт §B2-фрагмент-шум).
|
||
- **Плагин-сеамы P1–P6 (§B5):** данные/конфиг per язык/пара (идиом промпт-паков `PromptPathFor`), НЕ ветки кода.
|
||
Наполнение — zh(-ru) инстансы + существующий ruby-канал ja. Политика: **degrade-with-flag** (P2–P6, потеря recall
|
||
видима в карте подписи), **fail-loud ТОЛЬКО P1** (нет генератора кандидатов → майнинг для языка не заявляется).
|
||
P5 = лемматизатор цели (см. ru-лемматизация ниже). P4 = таблица транслитерации по ПАРЕ (Палладий zh→ru).
|
||
- **ru-лемматизация (§B5 P5) — Go-прод-путь W1.5 (ИСПРАВЛЕНО ревью-1 F2, прежняя формулировка «λ=0 → лемматизатор не
|
||
нужен» ОПРОВЕРГНУТА):** `λ=0` глушит spread-МНОЖИТЕЛЬ, НО `dst_variants` считается БЕЗУСЛОВНО λ (`arms.py:103`
|
||
`_dst_of` при `freq≥5`), а Палладий-канал V-C потребляет `dst_variants[:2]` + `is_name_lemma` (`arms.py:124-131`) —
|
||
обе pymorphy3-backed (`spread.py:45-60,117-143`). ⇒ **Палладий-подканал V-C НУЖДАЕТСЯ в лемматизации даже при λ=0.**
|
||
Три варианта (owner/бэкенд-развилка §10): **(A) faithful pymorphy3-порт** (dst_variants + is_name_lemma) → Go
|
||
воспроизводит golden ТОЧНО, вкл. Палладий-бонус +56.0 → `古月:21`; цена — нетривиальный порт лемматизатора; **(B)
|
||
дропнуть Палладий-подканал в Go-дефолте** → `古月` теряет +56.0, ранг **21→22** (катастроф-СКРИН ∈top-50 ВСЁ ЕЩЁ PASS,
|
||
но exact-ранг не воспроизводится); **(C) surface-аппроксимация** (cap-предоминантность по поверхности + стеммер для
|
||
dst_variants) — грубее, паритет НЕ exact. **Рекомендация (обновлено ревью-2 к ратифицированному §10-14 дефолту):
|
||
дефолт (B)** — дроп Палладий-подканала с явным пере-пином фикстур (`古月:21→22`, скрин PASS; dst доставляет банкнота,
|
||
exact-ранг НЕ продуктовая ценность); (A) faithful pymorphy3-порт — ТОЛЬКО при готовой поддерживаемой Go-морфологии.
|
||
omission-бэкстоп слоя 5 (WS2/WS5) — отдельно: substring-
|
||
матч по `decl.forms`+dst + лёгкий Snowball/Porter-ru-стеммер (Go-либа, детерминирован), pymorphy3 НЕ требуется там.
|
||
|
||
### (в) Конфиг + снапшот
|
||
- Пороги miner-v1 = **СТАРТОВЫЙ версионируемый конфиг** `mining-v1` (свип ±50% инвариантен — A3@f≥3=1.0 держится по
|
||
floor/over_rep/subsume/partners). `PACK_VERSION="zh-universal-v1"`.
|
||
- Майненые auto/draft строки: при `PostcheckGate=false` НЕ двигают `MemoryVersion` (`memory.go:264-266`); подписанные
|
||
approved → двигают `snapshot_W2` (§1 (в)). Строка манифеста §8.
|
||
- `Source:"mined"` — новое значение enum (аддитивно, миграция store).
|
||
|
||
### (г) Верификация ДО стройки ($0, несущая) — `ws3_miner_verify.py` + `ws3_seeddelta.py`, РЕЗУЛЬТАТ
|
||
- **(г) до-стройки:** Python miner-v1 на запинённых входах exp16 (§1.10 SHA: 8 код-файлов ✅, jieba `7197c321`, сид
|
||
`175a67ad`, records `3de49eaf`) воспроизводит golden: катастроф-ранги `{方源:0,蛊:1,蛊师:2,古月:21}` EXACT, **13618
|
||
кандидатов** EXACT, recall@proposed full **0.9649**≈0.965, test-half **0.9318**≈0.932, top-1 方源 score 6640.9.
|
||
⚠ **Паритет-фикстура РАСЩЕПЛЕНА (ревью-1 F1) — нельзя пинить `古月:21` exact И дропать pymorphy3:** (i) **Палладий-
|
||
ИНВАРИАНТНЫЕ гарантии** (Go-порт обязан воспроизвести при ЛЮБОМ ru-лемм-решении): recall@proposed 0.965/0.932,
|
||
13618-кандидат-СЕТ (членство), катастроф-СКРИН ∈top-50; (ii) **Палладий-ЗАВИСИМЫЕ ранги/скоры** (古月 rank/score,
|
||
прочие +56.0-кандидаты): пинить exact ТОЛЬКО при варианте (A) faithful pymorphy3-порт; при (B)-дропе — пере-пин
|
||
(古月→22, скрин PASS). `方源/蛊/蛊师` (ранги 0/1/2) Палладий НЕ трогает → инвариантны.
|
||
- **Юнит-фикстуры алиас-правил** (exp16 §3.2): 族长≠四代族长 блок, кап-лемма-гейт «найти», компози-гард — в `alias.py`
|
||
(recall известных 2/2). Прогон против Python-реализации — часть фикстур порта.
|
||
- **Эмиссия сид-дельты §C2-7** (exp16 её НЕ эмитил — только сайдкары): **61 терм** (21 draft+banknote-dst / 40
|
||
auto-без-dst); **сухой линт против фейл-лаудов memseed = 0 проблем** (loadable). Артефакт
|
||
`books/gu-zhenren/design11/ws3_seed_delta.yaml`. Находка: draft-кандидаты флагают ТОЧНЫЙ D38-дефект
|
||
(`古月族长→старейшина`, `甲/丙`-грейд) как `draft ⟨проверить⟩` для подписи — дисциплина «майнер не пишет approved»
|
||
РАБОТАЕТ; auto-кандидаты несут §B2-фрагмент-шум → эмиттер обязан реюзить subsumption+fragment-фильтры.
|
||
- **(д) исполнение самого паритета Go↔Python** закрепляет бэкенд после стройки (метод mem_select.py в обратную
|
||
сторону: Python = референс; при расхождении чинить Go-порт).
|
||
|
||
### (д) Тест-спека ПОСЛЕ стройки
|
||
- **Байт/значение-паритет Go↔Python miner-v1:** Go-порт воспроизводит Палладий-ИНВАРИАНТНЫЕ гарантии (13618-СЕТ, recall
|
||
0.965/0.932, катастроф-СКРИН ∈top-50) — фикстуры (г). Палладий-ЗАВИСИМЫЕ exact-ранги (古月:21) — только при варианте
|
||
(A) pymorphy3-порт; при (B) — пере-пин. Начать с `normalizeSourceKey` (реюз `memnorm.go`, уже байт-верифицирован
|
||
через `mem_select.py`).
|
||
- Юнит-тесты алиас-правил (5 R4-блоков + компози-гард + кап-лемма-гейт).
|
||
- `tmctl seed-lint`: прогон эмитированной дельты через РЕАЛЬНЫЙ `loadGlossarySeed` (не Python-зеркало) → 0 фейл-лаудов.
|
||
- **Пин `Source:mined` (ревью-2 F2):** reseed W1.5-дельты штампует `Source:mined` (НЕ `seed` — `loadGlossarySeed`
|
||
хардкодит `Source:"seed"` `memseed.go:131`); проверить `base-bank-version` = хеш `Source∈{seed,ruby}` СТАБИЛЕН после
|
||
вливания mined-дельты (иначе `snapshot_W1` двигается → «переоплата ОДНА» сломана).
|
||
- Детерминизм: повтор Go-майнера байт-в-байт (без time/rand).
|
||
|
||
### (е) Открытое / маршрутизация
|
||
- `λ`-режим (spread-коэф): дефолт 0 (инъект); свип на реальных не-инъект черновиках пере-прогона (§10).
|
||
- ru-лемматизатор P5 — полный pymorphy3-паритет парковано; дефолт-майнер обходится (см. (б)).
|
||
- Мини-голд алиасов владельца (§E-1) — recall кластеризации; без него ярус-1 только по precision (§10).
|
||
- precision@30 non-seed A3 — адъюдикация владельца (§10).
|
||
- Z1-адъюдикация → ОБЛАКО (локальная 9B wrong-catch 0.333, принимает 族长→«старейшина»), НЕ локаль. Локальный
|
||
9B-споттер НЕ строим (код 0.965 ≥ локаль 0.895).
|
||
|
||
---
|
||
|
||
## §4. WS4 — Банкнота: dst-канал (слой 4, wire-инвариант)
|
||
|
||
Спека banknote-v1 = research/20 §B3 / exp16 `banknote.py`: разделитель `⟦TM-BANK-v1⟧`, ≤`MAX_LINES=12` строк
|
||
`src<TAB>dst<TAB>type` (type∈{name,place,title,term}, парсер +nickname), «только НОВОЕ» (нет новых → нет разделителя).
|
||
Строить канал ТОЛЬКО если §D-правило «сноска оправдана» сработало. **РАТИФИЦИРОВАНО D39.10** как dst-канал: parse_fail
|
||
0% (<5% ✓); ниша = **ПРЯМАЯ доставка dst** (переводчик эмитит 蛊→гу, non-seed 龙公→Лун Гун — ровно то, что ко-оккуренция
|
||
извлечь НЕ смогла), НЕ recall (маржин f<3 +1 терм ~10 п.п. — на пороге; код сильнее: f<3 8/10 vs банкнота 5/10);
|
||
Δкачества mean 0.935 под шум-полом 0.261 → уверенной деградации нет. Цена ~$0.01–0.1/ранобэ.
|
||
|
||
### (а) Что меняем + 12 интеграционных точек (file:line, HEAD, каждая с тест-спекой в (д))
|
||
1. **Санитайзер (`sanitizer.go` v6):** на draft-стадии НЕ гоняется (isFinal-only, `chunkrun.go:48`). ⚠ Существующий
|
||
`trailingNoteRE` (`:240`) НЕ ловит `⟦TM-BANK-v1⟧`/`src<TAB>dst`-строки (только «Примечание/Сноска»-заголовки), а
|
||
CJK-leak (`:76-84`) фаерит только на голых Han-ранах — смешанная банкнот-строка «蛊 гу term» может НЕ сработать
|
||
(ревью-1 F3: НЕ полагаться на trailing-note как бэкстоп). **ПЕРВЫЙ и единственный надёжный рубеж — телеметрия п.10
|
||
`banknote_parse_fail` ДО редактуры.** Если нужен финал-бэкстоп — добавить ЯВНОЕ версионируемое `⟦TM-BANK-v1⟧`-правило
|
||
санитайзера (не переиспользовать trailing-note).
|
||
2. **Санитайзер cjk_leak (v6):** src-колонка = Han по построению → срез ДО санитайзера снимает ложное срабатывание;
|
||
gloss-whitelist v6 НЕ трогаем.
|
||
3. **classify/echo-детект** (`disposition.go`, `const cjkEchoThreshold=0.15`): считать по ОЧИЩЕННОМУ тексту (срез →
|
||
classify(stripped)). Порядок ЖЁСТКИЙ.
|
||
4. **Coverage-гейт** (`coverage.go`, translator-only `chunkrun.go:73`): `len_ratio` числитель по очищенному (сноска
|
||
≠ перевод).
|
||
5. **max_tokens-сайзинг** (`stagerun.go:87-100`): += бюджет блока (≤12 строк × ~12 ток). Перевод ПЕРВЫМ, блок хвостом
|
||
→ трункация бьёт по блоку; парсер fail-tolerant на последней строке + флаг `banknote_truncated`.
|
||
6. **request_hash/снапшот** (`render.go` RequestHash, `snapshot.go`): ⚠ **(ревью-1 F2) `PromptSHA256` (`:238`) фолдит
|
||
ТОЛЬКО файл промпта** — если инструкция сноски = config-флаг, аппендящий её при рендере (как `few_shot`), PromptSHA256
|
||
не двигается, wire тихо расходится (`snapshot.go:110-116`-класс). **Решение (а): запечь инструкцию в ФАЙЛ промпта**
|
||
(тогда PromptSHA256 реально двигается) ИЛИ явный stage-флаг-фолд. **(б) Версия ПАРСЕРА/среза банкноты — verdict-ось**
|
||
(управляет resolved-выходом черновика + derived-hash, как `ClassifierVersion` `:173` / `sanitizerSnap` `:66-77`):
|
||
добавить `banknoteSnap{enabled, parser_version}` в `snapshotID()` (единое имя поля, ревью-2 F9-унификация; json-тег в
|
||
Go — как `sanitizerSnap.version`, решает бэкенд) — иначе bump парсера без правки промпта оставляет снапшот
|
||
тем же (свежие чанки режут новым парсером, резюмнутые отдают старый derived → тихая внутри-книжная дивергенция).
|
||
Включение канала = громкий `--resnapshot`.
|
||
7. **Чекпоинт/резюм** (`stagerun.go:66-80`): resume передоказывает derived-артефакт из сырого чекпоинта бесплатно
|
||
(content-addressed hash → тот же id).
|
||
8. **«Редактор её не видит» (НЕСУЩАЯ, главная правка кода):** свежий прогон — редактор читает `prev=sr.Text`
|
||
(`chunkrun.go:162`), хук подменяет на очищенный. НО на резюме OK-путь берёт текст по `final_hash`, который сегодня =
|
||
СЫРОЙ attempt (`stagerun.go:168-169`: `if disposition==DispOK { finalHash=last.reqHash }`); re-point на derived
|
||
существует ТОЛЬКО для flagged (`:170-185`). **ТРЕБОВАНИЕ: final_hash OK-стадии draft ПЕРЕНАПРАВИТЬ на
|
||
`tm-banknote-v1` derived-чекпоинт** (расширение прецедента flagged→ok). Без этого резюм отдаёт редактору сырой блок.
|
||
⚠ **Эскалационный путь (ревью-1 F1): draft-стадия ЭСКАЛИРУЕТ** (`pipeline-c1.yaml:53` `escalate_to: deepseek-v4-pro` —
|
||
живое, не гипотеза; `pipeline.go:374` разрешает escalate_to только translator). На эскалированном OK-черновике
|
||
`last=esc.fb` (`stagerun.go:159`), `finalHash=last.reqHash` = СЫРОЙ эскалированный чекпоинт, `sr.Text=last.text`
|
||
кормит редактора СЫРЬЁМ. **Срез+derived-commit+`sr.Text`=stripped+re-point ДОЛЖНЫ стоять ПОСЛЕ резолва эскалации
|
||
(`stagerun.go:163`) и потреблять `last.stripped`** — тогда эскалированный черновик тоже очищен. (`resume.go:32-52`
|
||
читает `GetCheckpoint(final_hash)` прозрачно → правка resume.go НЕ нужна.)
|
||
9. **Пост-чек глоссария** (`mempostcheck.go`, по финалу редактора): не влияет; но `renderGlossaryBlock` (`memory.go:477`)
|
||
идёт в промпте ДО инструкции сноски («новые = не из этого списка»).
|
||
10. **Телеметрия (лауд):** per-chunk `n_banknote_lines`, `banknote_parse_fail`, `banknote_truncated` (в retrieval_state-
|
||
стиле).
|
||
11. **Провайдер-квирки:** DeepSeek thinking-ON НЕ трогать (`models.go` `echoMineViolation`, `LoadModels` fail-fast).
|
||
§D-арм меряет дельту качества черновика с/без инструкции (гейт канала; exp16: mean 0.935, под шум-полом 0.261 →
|
||
уверенной деградации нет, но пере-замерить на пере-прогоне).
|
||
12. **Экспорт/полигон:** `tmctl export` отдаёт final без сноски автоматически (срез раньше); кандидаты — из
|
||
артефакт-файла, не текста.
|
||
|
||
### (б) Алгоритм
|
||
- **Срез (`split_banknote`):** `idx=output.find(SEP)`; <0 → `(output.rstrip(), "")`; иначе `clean=output[:idx].rstrip()`,
|
||
`block=output[idx+len(SEP):].strip("\n")`. Срез ПЕРЕД `classifyOutput` (`chunkrun.go:32`) на сыром draft-output.
|
||
- **Парс (`parse_banknote`):** строки `block.split("\n")` непустые; толерантный field-split `\t| {2,}|\s*\|\s*`; <2
|
||
полей → если последняя строка И `truncated_generation` → `banknote_truncated`, иначе `bad+=1`; `typ=parts[2].lower()`
|
||
(≥3 полей) иначе `term`, не-`_TYPE_OK`→`term`; **src ДОЛЖЕН содержать Han** `[㐀-鿿]` иначе bad; `parse_fail=(bad>0)`.
|
||
- **finish=stop-only гейт (обязателен, errata exp16 §6):** генерация банкноты принимается ТОЛЬКО при `finish=="stop"`
|
||
(не «≠length» — DeepSeek peak-overload даёт `insufficient_system_resource`). При stop-only truncation-толерантность
|
||
парсера в проде НЕДОСТИЖИМА (гейт отклоняет не-stop) — но держать в парсере для устойчивости.
|
||
- **derived-checkpoint (ТОЧНАЯ формула прецедента `commitSanitizedExport`, `stagerun.go:230-232`):**
|
||
`sha256("tm-banknote-v1\x00" + reqHash + "\x00" + stripped)`, id-префикс `"tm-banknote-v1:"`, через
|
||
`PutDerivedCheckpoint` (`ledger.go:182`, cost=0, escalation=0, idempotent), `UsageJSON:"{}"`,
|
||
`FinishReason:"banknote_export"`. (НЕ упрощённая формула доки без NULL-байтов.)
|
||
- Распарсенные кандидаты → отдельный артефакт-файл (evidence для W1.5 §C), НЕ в store до подписи.
|
||
|
||
### (в) Конфиг + снапшот
|
||
- Включение канала: инструкция запечена в ФАЙЛ промпта (→ `PromptSHA256` двигается) ИЛИ stage-флаг-фолд; ПЛЮС новый
|
||
**`banknoteSnap{enabled, parser_version}`** в `snapshotID()` (verdict-ось, зеркалит `sanitizerSnap`) — не полагаться на
|
||
`PromptSHA256` (ревью-1 F2). Смена парсера/среза = громкий `--resnapshot`. Строка манифеста §8.
|
||
- derived-hash неймспейсит версию канала → смена версии = новый id (не коллизия).
|
||
|
||
### (г) Верификация ДО стройки ($0) — `ws4_banknote_verify.py`, РЕЗУЛЬТАТ
|
||
- **Пере-парс 95 строк** (14 сохранённых сырых выходов exp16): 95 строк / 65 distinct_src / **0 parse_fail / 0
|
||
truncated** — EXACT golden (parse_fail 0% воспроизведён).
|
||
- **Синтетическая трункация:** под `truncated_generation=True` → 2 годные строки + `banknote_truncated` (не bad); под
|
||
`False` → `banknote_parse_fail` (корректно).
|
||
- **fresh↔resume эквивалент-тест (спека):** `tm-banknote-v1:` id = content-addressed (формула с NULL-байтами) → fresh
|
||
и resume дают ИДЕНТИЧНЫЙ id; смена stripped → другой id. **Re-point OK-пути final_hash resume-стабилен конструкцией.**
|
||
- **Инварианты парсера:** SEP не note-слово; non-Han src=bad; no-SEP→всё clean; толерантный сплит (таб/≥2проб/pipe) —
|
||
все PASS.
|
||
|
||
### (д) Тест-спека ПОСЛЕ стройки
|
||
- Каждая из 12 точек — пиновый тест (срез ДО classify; cjk_leak/coverage/echo по очищенному; max_tokens+блок;
|
||
derived-hash формула; **re-point OK-пути final_hash → derived** [fresh↔resume эквивалент]; телеметрия 3 метрики;
|
||
thinking-ON нетронут).
|
||
- Пин: parse_fail 0% на 95 строках; truncation-толерантность (синтетика); SEP не встречается в чистом тексте.
|
||
- Пин: включение канала = снапшот-сдвиг (промпт-SHA + константа).
|
||
|
||
### (е) Открытое / маршрутизация
|
||
- Дельта качества перевода от форматного констрейнта — пере-замер на пере-прогоне (§11-провайдер §D-арм).
|
||
- Ниша канала = ДОСТАВКА dst, НЕ recall (код f<3: 8/10 vs банкнота 5/10). Z2-дрейф банкнотного dst (转→«оборот» vs
|
||
approved «ранг») — ловится подписью владельца (draft, не approved).
|
||
|
||
---
|
||
|
||
## §5. WS5 — Дефект-класс чекеры + данные пакета пары (слои 5 + 2-данные)
|
||
|
||
Дефект-класс-леджер D39.8 (все пак/банк/гейт-уровня, НЕ нарезка). Действие при срабатывании: **флаг / констрейнт-
|
||
инъекция — НЕ тихая правка текста** (диспозиция D2 цела). Гейты — ДЕТЕРМИНИРОВАННЫЕ ($0): судьи слишком шумны
|
||
(пол 0.126 когезия / 0.261 смысл — судьи только НОМИНИРУЮТ).
|
||
|
||
### (а) Что меняем (file:line) — по классу: где живёт правило (данные пакета vs код гейта)
|
||
- **`cheapgates.go`** — расширяется дефект-классами DC1/DC2/DC7 (детерм. флаггеры на финале, `chunkrun.go:199-207`
|
||
реюз `runCheapGates`, target-gated `isRuTarget`, наблюдаемость не гейт по дефолту).
|
||
- **новый omission-бэкстоп** (слой 5, компенсатор зоны деградации WS2) — reflow-инвариантный лемма-матч.
|
||
- **данные пакета пары zh-ru** (слой 2, версионируемый) — таблицы конверсии единиц (DC1), негатив-лист регистра (DC6),
|
||
verse-локусы (DC5).
|
||
- **`memory.go`/`renderEditorConstraintBlock`** — gender-инъекция (DC3) из поля сида `Gender` (`glossary.go:26`,
|
||
`memseed.go:35`, folded в F1 `memory.go:273`).
|
||
|
||
### (б) Алгоритм + верифицированный статус ланд-абельности
|
||
- **DC-1 时辰/меры (данные пакета + детерм. чекер):** таблица конверсии `时辰=2ч`, `万/億`-порядок, `里/斤/суй-1`;
|
||
извлечь числовое время из src (`N个时辰`), сверить рендер (`三个时辰≈6ч`, НЕ «три часа»). Рефайн: флагать ТОЛЬКО явный
|
||
mismatch (рендер счёта как часов), не «часы не найдены». ⚠ **(ревью-1 A1) сработка на 25-гл — ОДНА (n=1, ch1/chunk4),
|
||
РЕАЛЬНЫЙ дефект (`3个时辰→3 часов`) на КОРПУСЕ-ОТКРЫТИЯ этого дефекта → «true FP≈0» преждевременно (n=1 ≠ rate).
|
||
Landing ГЕЙТИТСЯ §5(д)-FP на СВЕЖЕМ пере-прогоне** (не текущий rerun). Конверсия детерминирована → низкий-FP ожидаем.
|
||
- **DC-2 масштабы `千万/数十万` (b1-класс):** `千万=10⁷`, `数十万=неск.×10⁵`; + word↔word alignment (`四成四=44%`,
|
||
`三成=30%`, `十二分之一=1/12` — реюз `q4a_traps.rule_b1/rule_b2` + LOCATOR). Это то, что `regressionguard.go` НЕ
|
||
умеет (арабские цифры только, `L5-regressionguard` слеп к word↔word). ⚠ **(ревью-1 A4) `千万` — стоковая ГИПЕРБОЛА
|
||
(«несметно/тьма»), «тысячи» — in-register литературный рендер, НЕ жёсткая ошибка как DC1/DC6.** НЕ bundle с DC1/DC6
|
||
как «true FP≈0»; магнитуд-чекер — самый hyperbole-exposed → замерить FP ОТДЕЛЬНО в §5(д). Landing ГЕЙТИТСЯ §5(д).
|
||
- **DC-3 gender — РАЗВЕСТИ инъекцию и чекер (ревью-2 F6):**
|
||
**(1) Инъекция из поля сида `Gender` в констрейнт-блок редактора — ЛЕНДИТСЯ для ВСЕХ ТРЁХ состояний, ВКЛЮЧАЯ
|
||
hidden-мандат:** male/female ⇒ жёсткие родовые формы; hidden ⇒ мандат БЕЗРОДОВЫХ конструкций / surface-`他` (→ «он»)
|
||
ДО `until_ch` (D19.3, `白凝冰`) — ЭТО и есть фикс класса Бай Нинбин: инъекция НАПРАВЛЯЕТ редактора, кореференция НЕ
|
||
нужна. **(2) Чекер (наблюдаемость на финале):** male/female-чекер ЛЕНДИТСЯ с FP-гейтом §5(д), паратекст-чанки
|
||
(foreword/синопсис) исключены. **hidden-ЧЕКЕР НЕ лендится** — ⚠ (ревью-1 A3, УТОЧНЕНО пост-верифай по records.json):
|
||
FP 3.5% (2 сработки) НЕ обе паратекстные: `ch1/chunk0` = паратекст-книга-референс («её»→«эту книгу»), НО `ch1/chunk5`
|
||
(«Бай Нинбин… её дар просто пугает», сцена совета старейшин, НЕ паратекст) = РЕАЛЬНАЯ narrative-coref-неоднозначность
|
||
женской формы на HIDDEN-персонаже — это СИЛЬНЕЕ довод к Ф2, не слабее. Паратекст-исключение снимает ТОЛЬКО chunk0;
|
||
chunk5 остаётся → нужна РЕАЛЬНАЯ кореференция (→ Ф2). until_ch/sentence-scope НЕ фиксит. ⟶ Не лендится ТОЛЬКО
|
||
hidden-ЧЕКЕР (инъекция всех трёх — лендится); прежняя формулировка «лендится только male/female энфорс» смешивала —
|
||
бэкенд не построил бы hidden-инъекцию.
|
||
- **DC-4 род говорящего в диалоге:** Ф2-annotator (дискурс-уровень, НЕ поле сида — говорящий может быть не в
|
||
глоссарии). Трап «я мечтал»→«мечтала». **Вне детерм.-скоупа слоя 5 → Ф2** (диспозиция §9).
|
||
- **DC-5 стих/аллюзии — ⚠ НЕ ЛЕНДИТСЯ детерм. (верификация):** loose line-profile детектор ловит трап но **FP 73.7%**;
|
||
strict (регулярный метр + поэт-лексема) → FP 42.1% НО теряет позитив. ⚠ **(ревью-1 A5)** ДВЕ протестированные профили
|
||
не лендятся (best = 42% FP + потеря позитива; 排比↔стих-неоднозначность трудна); универсального «детекция неспособна»
|
||
из n=2 не утверждаем. **Решение (консервативный дефолт): DC-5 = пак-локусы** (владелец курирует известные verse/
|
||
allusion src-строки) + **рендер-мандат «не сплющивать» + слот сноски** + опц. LLM-НОМИНАЦИЯ (не гейт). Продукт-решения
|
||
(рендер-политика, сноски) — **владельцу** (§10).
|
||
- **DC-6 регистр-лексикон (негатив-лист данных пакета):** `{терем-класс}` — сказочно-русский/канцелярский слой,
|
||
ломающий жанр. Чекер вхождений на финале + замены. Сработка на 25-гл — ОДНА (ch1/chunk4), РЕАЛЬНЫЙ дефект («терем» в
|
||
сянься — жёсткая регистр-ошибка). ⚠ (ревью-1 A1) n=1 ≠ FP-rate; **Landing ГЕЙТИТСЯ §5(д)-FP на свежем прогоне**
|
||
(негатив-лист по построению низкий-FP). Негатив-лист — данные пакета (расширяемо владельцем).
|
||
- **DC-7 editor-инверсии grade/role (сверка на ВЫХОДЕ редактора):** канон-грейд `甲乙丙丁→«класс А/Б/В/Г»` (не Б/2/A),
|
||
титул `族长→«глава клана»` (не «старейшина»). Точный канон-матч против editor-output → низкий FP ожидаем. ⚠ **(ревью-1
|
||
A2) DC-7 НЕ имеет $0-верификации** (ws5-скрипт не тестирует его) → **landing UNVERIFIED, FP только в §5(д)** — не
|
||
утверждать «ЛЕНДИТСЯ» до замера. Корень (D38 §3): promote `甲乙丙丁`+`四代族长` **draft→approved** + reseed (owner-only) —
|
||
иначе `renderEditorConstraintBlock` (CONFIRMED-only) не инъектит, `suppressContained` съедает верный `族长`.
|
||
- **Omission-бэкстоп (слой 5, WS2-компенсатор):** reflow-инвариантный лемма-матч (`reflow_omission.py`): per-source
|
||
ENTITY присутствует ли ГДЕ-УГОДНО в target (position-independent → reflow-safe); verdict-каскад skip→present→partial
|
||
→omitted; `inflection_gap` FLAG (лемма совпала, surface вне pinned decl.forms — НЕ omission, иначе ~7-8% ложных);
|
||
content-floor `ratio=len(tgt)/(1.3·len(src))<0.5` крайний backstop. Правило: entity-omission≈0 = «INSTRUMENT
|
||
CEILING» НЕ «size safe» (D32.4). Go-путь БЕЗ pymorphy3: substring-матч по `{dst, decl.forms, aliases}` (детерм.),
|
||
флаг при отсутствии; inflection-толерантность через лёгкий стеммер (см. WS3 (б) P5-решение). `RegressionGuard`/
|
||
coverage тут смещены (editor легально мержит — research/19 §B0-4).
|
||
|
||
### (в) Конфиг + снапшот
|
||
- Данные пакета пары (таблицы единиц, негатив-лист, verse-локусы) — версионируемый пакет zh-ru, снапшот-folded
|
||
(правка = громкий resnapshot, как `chunkerVersion`). Строка манифеста §8.
|
||
- gender-инъекция (ревью-2 реконсиляция): ДАННЫЕ пола (`Gender` seed-поле) фолдятся через `MemoryVersion` (правка пола
|
||
персонажа → снапшот); РЕНДЕР-ЛОГИКА (пол→констрейнт-текст в `renderEditorConstraintBlock`) фолдится тем же
|
||
**выделенным `render-format-version`-компонентом**, что и src→dst-блок (НЕ `memoryMatchVersion` — §2(в)/§8).
|
||
- Дефект-чекеры (cheapgates) версионируются `StyleCheckVersion` (`snapshot.go:207`, наблюдаемость → resnapshot при
|
||
правке правила).
|
||
- DC-7 promote `甲乙丙丁`+`四代族长` draft→approved = reseed → `MemoryVersion` двигается (снапшот).
|
||
|
||
### (г) Верификация ДО стройки ($0) — `ws5_checkers_verify.py`, РЕЗУЛЬТАТ
|
||
- **(а) Позитивы: 6/6 пойманы** (синтетика exp15 §7.9/§2: `三个时辰→«три часа»`, `千万→«тысячи»`, `数十万→«десятки
|
||
тысяч»`, «терем», стих[loose], gender-hidden). Точные zh-трап-строки (exp14b §2 таблица a1..d2 + 时辰/千万) — фикстуры.
|
||
⚠ **DC-7 (grade/role) НЕ покрыт $0-скриптом** (ревью-1 A2) → его landing verifies только §5(д).
|
||
- **(б) FP-fire на 25-гл финале** (корпус records.json final; §5(д)-замер = `tmctl export` после стройки — rerun-store
|
||
схема v7 < HEAD v8, read-only не мигрирует; exportNormalize косметичен, не меняет слова чекеров): **DC1/DC2/DC6 = по
|
||
1 сработке (n=1, все на ch1/chunk4 — реальные дефекты, но n=1 ≠ FP-rate, ревью-1 A1)** · **DC3 3.5% (2 — 1 паратекст
|
||
book-ref + 1 narrative-coref на hidden-персонаже, A3-уточ; male/female-чекер $0-неверифицирован как DC-7 → §5(д))** ·
|
||
**DC5 loose 73.7% / strict 42.1% → НЕ детерм.-гейт**. ⟶ Разделение: DC5 НЕ лендится
|
||
(эскалация владельцу); DC1/DC2/DC6/DC7 landing ГЕЙТИТСЯ §5(д)-FP на СВЕЖЕМ прогоне (текущий n=1 — недостаточно);
|
||
DC3 — только male/female seed-field.
|
||
|
||
### (д) Тест-спека ПОСЛЕ стройки
|
||
- **FP-замер через `tmctl export`** (инвариант №8) на СВЕЖЕМ пере-прогонном 25-гл финале (не records.json): каждый
|
||
чекер (DC1/2/3/6/7) — измеренный FP-rate в отчёте; чекер с заметной долей ложных не лендится. ⚠ **Пред-условие
|
||
(ревью-1 A6): DC1/DC2 нужен SOURCE-столбец** (для `时辰`/`千万` сверки src↔target); `tmctl export --pairs` на HEAD
|
||
НЕ существует (research/20 §E-бэкенд-3) → построить `--pairs` (source-join в Export уже есть) ДО §5(д)-замера DC1/DC2.
|
||
- Позитивы из эмпирики (exp15 §7.9 / exp14b / exp16) обязаны ловиться (регресс-фикстуры).
|
||
- Sentence-scoping обязателен (q4a_traps F4: скорить ОДНО предложение, эндеры `.!?…\n` — иначе raw-draft и merged-glm-
|
||
абзац несопоставимы). Три исхода fix/fail/«?»; «?» ИСКЛЮЧАЕТСЯ из rates, никогда тихий pass.
|
||
|
||
### (е) Открытое / маршрутизация — ВЛАДЕЛЬЦУ (§10)
|
||
- **DC-5 рендер-политика стиха + слот сноски** (детерм. детекция не работает — эмпирика): продукт-решение владельца.
|
||
- **DC-4 род говорящего** = Ф2-annotator (диспозиция §9: Ф2-очередь).
|
||
- Промоут `甲乙丙丁`/`四代族长` draft→approved — owner-only (approved-инвариант).
|
||
|
||
---
|
||
|
||
## §6. WS6 — Свап-арм редактора + готовность пере-прогона
|
||
|
||
### (а) Что меняем (file:line)
|
||
- **`configs/pipeline-*.yaml` / `models.yaml`** — армы = КОНФИГ, не код: editor-стадия `model: glm-5` (базлайн) /
|
||
`mistral-large-latest` / `deepseek-v4-pro` + `few_shot` тумблер (`pipeline.go:103` `FewShot *bool`); снапшот per-арм
|
||
(разный editor-model → разный `stageSnap.Model` → разный `snapshot_W2`).
|
||
- **`export.go`/`quality.go`** — атрибуция арма в export/report (editor-model уже в chunk_status/checkpoint).
|
||
- Инвариант: editor pinned (D12, `pipeline.go:373`: escalate_to только на translator) — свап = смена editor-модели
|
||
конфигом, НЕ эскалация. Пинится `echo_mine_test.go` (сейчас требует glm-5 обоих пайплайнов; тест обновляется под
|
||
арм-варианты).
|
||
|
||
### (б) Алгоритм (прогон-протокол — предпосылки для будущего полигон/монитор-промта)
|
||
- Армы идут ЧЕРЕЗ прод-путь со ВСЕМИ гейтами (урок V2-брака §7.9: eval-риг без прод-гейтов [санитайзер v6 поймал бы
|
||
待遇/一步登天] дискредитировал арм).
|
||
- **Пред-условие mistral-арма (ревью-2 F4):** `mistral-large-latest` НЕ идёт через прод-путь до пер-модельного
|
||
rate-guard (§1(б)) — ~48% retry-fails @1.3s без него исказят и латентность, и денежную телеметрию арма. glm-5/
|
||
deepseek-pro-армы (grok-семейство 0% retry-fails) rate-guard не блокирует, но семафор общий по конфигу.
|
||
- Инструмент-фиксы слепых пакетов (D39.8 п.3): авто-QA до человека (CJK-в-ru / битые формы / род-консистентность);
|
||
обрезка ВСЕХ версий по общему финальному предложению; 2-way для тонких контрастов; **тир-структура претензий**
|
||
(критические/смысловые/редакторские) вместо плоского «≤2». Планка — 2 претензии (интерим, не пилот Ф2.5).
|
||
- Любое судимое сравнение наследует ратифицированный риг-стандарт (D39.7): per-vote персист, полно-evidence окна
|
||
(HEAD_CHARS-класс запрещён), оба порядка, floor-гейт маргиналов, DET-primary > судьи где возможен (валидирован
|
||
D39.9); генерации — только `finish=stop`.
|
||
- ⚠ **Полы `0.126`/`0.261` — ИСТОРИЧЕСКИЕ калибровки, НЕ переносимые константы (ревью-2 F5, замечание владельца):**
|
||
измерены в glm/flash-условиях на S2′/exp14-материале. Каждый СУДИМЫЙ арм-контраст пере-прогона меряет СВОЙ пол
|
||
A0↔A0′-блоком (~$1/арм) на материале ЭТОГО прогона ДО интерпретации маргиналов — per-editor-model И per-материал.
|
||
Смягчающее: **главные оси floor-иммунны** — DET-чекеры (WS5) + слепое чтение владельца (WS6/(д)); судьи только
|
||
НОМИНИРУЮТ. Внести в предпосылки будущего полигон-промта.
|
||
|
||
### (в) Конфиг + снапшот
|
||
- Каждый арм = отдельный `snapshot_W2` (editor-model в `stageSnap`). Пере-прогон армов = отдельные джобы (не
|
||
конфликтуют). `few_shot:false` для reasoning-редактора (deepseek-thinking) — фолдится (`snapshot.go:110-116`, только
|
||
где есть `---FEWSHOT---` блок).
|
||
|
||
### (г) Верификация ДО стройки ($0) — `ws1_wave_cogs.py` (реюз WS1-расчёта), РЕЗУЛЬТАТ
|
||
- **COGS per-арм (фертильность × цены providers.json × реальная структура 25-гл, warm-cache/valley):**
|
||
**glm-5 $0.335 · mistral $0.205 · deepseek-v4-pro $0.117.** Свап-арм editor'ов ДЕШЕВЛЕ базлайна (out $1.5/$0.87 vs
|
||
glm-5 $3.2) — COGS-win + D38 качество-фикс. Пик-надбавка ×2 (риск-пин) удваивает ТОЛЬКО deepseek-pro-editor до
|
||
$0.234 → scheduler-aware критичен только для deepseek-арма. Кэш экономит ~17% на editor-input.
|
||
- Качественная сторона свап-арма — эскейп-хатч (эскалация): **точная спека «верификация полигоном ПОСЛЕ стройки» в
|
||
прогон-протоколе** (это (д); платная — отдельной полигон-сессией по ратифицированному плану).
|
||
|
||
### (д) Тест-спека ПОСЛЕ стройки
|
||
- Полигон-прогон армов {glm-5, mistral, deepseek-pro} через прод-путь + слепое чтение владельца (тир-структура) —
|
||
ОТДЕЛЬНЫЙ полигон/монитор-промт по этому плану. Наследует риг-стандарт D39.7.
|
||
- Пин: editor-swap = конфиг (не код); снапшот per-арм; атрибуция в export/report.
|
||
|
||
### (е) Открытое / маршрутизация
|
||
- Качественная ратификация свап-арма — платный полигон после стройки (деньги-развилка §10; кандидат — пере-прогон
|
||
3–10 глав, планка 2 претензии).
|
||
|
||
---
|
||
|
||
## §7. Порядок стройки и нарезка на пакеты
|
||
|
||
Зависимости: WS3/WS4 (банк W1.5) требуют W1.5-стоп-границы из WS1. WS2 (единицы) требуется WS1 (что гонят волны).
|
||
WS5-omission-бэкстоп компенсирует WS2-зону деградации. Рекомендуемая нарезка:
|
||
|
||
- **Бэкенд-пак-2 (слой 1 оркестровка + чанкер):** WS1 (волновой раннер: W0-precompute, eager-clients, пер-волновой
|
||
снапшот + wave-sequencing-инвариант, money-под-∥, scheduler-aware) + WS2 (чанкер-бюджет в output-токенах, edit-единица
|
||
с КОНСЕРВАТИВНЫМ `EditCeilingOut≤3200` до Q2a, src→dst редактор, снос мёртвых кнобов). Разблокирует всё (волны —
|
||
несущий каркас). ⚠ omission-бэкстоп в пак-4 → пока его нет, edit-ceiling держать консервативным (ревью-1 WS2-F1).
|
||
- **Бэкенд-пак-3 (слой 4 банк):** WS3 (Go-майнер V-C + алиас + консолидация + сид-дельта + `tmctl seed-lint` +
|
||
`Source:mined`) + WS4 (банкнота 12 точек). Гейтится W1.5-стоп из пак-2. WS3-паритет Go↔Python — исполнение в (д).
|
||
- **Бэкенд-пак-4 (слой 5 + данные слоя 2):** WS5 (DC1/2/3/6/7 чекеры + omission-бэкстоп + данные пакета zh-ru +
|
||
gender-инъекция) + **`tmctl export --pairs`** (ревью-2 F7: пред-условие §5(д)-FP-замера DC1/DC2 — source-столбец).
|
||
DC-5/DC-4 — эскалация владельцу/Ф2 (не в пак).
|
||
- **Конфиг-пак (WS6):** армы редактора = yaml/models (не отдельный бэкенд-пак; часть пере-прогонного конфига).
|
||
|
||
**Гейт:** каждый пак — мандат самопроверки исполнением (свой код + запросы + результаты); адверсариальный бэкенд-ревью
|
||
после кода. Затем единый resnapshot (§8) → пере-прогон 3–10 глав → чтение владельца.
|
||
|
||
---
|
||
|
||
## §8. Манифест единого resnapshot (D30.9 — одна переоплата)
|
||
|
||
Все правки этого плана + уже висящие трек-A компоненты обязаны схлопнуться в ОДИН `--resnapshot` (одна переоплата
|
||
книги). Всё, что двигает `snapshotID` (`snapshot.go:101-279`):
|
||
|
||
**Уже висящие (трек A залендён, но текущий снапшот книги их не несёт — resnapshot был отложен D38.5/D39.2/39.5):**
|
||
- `memmatch-v4` (trust-gated suppressor, `memory.go:47`) → `MemoryVersion`.
|
||
- `sanitizer-v6` (fold-first детекция) → `Sanitizer` (когда enabled).
|
||
- reseed-сид `eb409f2` (промоут 5 термов) → `MemoryVersion`/`BriefHash`.
|
||
- editor-v3 `0ac5f7a` (дискурс+чэнъюй, few_shot-тумблер) → `PromptSHA256`/`FewShot`.
|
||
|
||
**Новое из этого плана:**
|
||
- WS2: снос `STMDepth`/`OverlapTokens` (`contextSnap` меняется) + `segmentationSnap` (бюджет-output-токены +
|
||
фертильность + edit-ceiling) + `chunkerVersion` bump → снапшот.
|
||
- WS2: src→dst редакторский блок (`renderEditorConstraintBlock` ФОРМАТ меняется) → **выделенный `render-format-version`
|
||
folded-компонент** (ревью-2 реконсиляция: НЕ `memoryMatchVersion` — тот const скоуп-матчер/алгоритм `memory.go:33-47`,
|
||
формат рендера НЕ ловит автоматически; механизм пинится в §2(в)) → снапшот.
|
||
- WS3: майненые approved-строки (подпись W1.5) → `MemoryVersion` (только `snapshot_W2`, §1 (в)); `Source:mined` enum
|
||
(аддитивно, миграция store — НЕ снапшот, если не меняет folded content).
|
||
- WS4: включение банкнота-канала = промпт-SHA (инструкция) + константа `banknote-v1` → `PromptSHA256` (draft-стадия);
|
||
**+ `banknoteSnap{enabled, parser_version}`** (ревью-2 F9, verdict-ось из WS4(в) — управляет resolved-выходом
|
||
черновика + derived-hash, зеркалит `sanitizerSnap`; §8 прежде нёс ТОЛЬКО промпт-SHA) → `snapshotID()`.
|
||
- WS5: данные пакета пары (единицы/регистр/verse-локусы) — версионируемый пакет → снапшот; gender-инъекция: ДАННЫЕ
|
||
(`Gender` seed-поле) → `MemoryVersion`, РЕНДЕР-ЛОГИКА → `render-format-version` (ревью-2 реконсиляция, НЕ
|
||
`memoryMatchVersion`; §5(в)/§2(в)); DC-чекеры → `StyleCheckVersion`; promote 甲乙丙丁/四代族长 → `MemoryVersion`.
|
||
- WS6: editor-model per-арм → `stageSnap.Model` (разные армы = разные снапшоты, но это РАЗНЫЕ прогоны, не переоплата
|
||
одного).
|
||
- **Структурное (ревью-2 F9):** сама пер-волновая реструктуризация `snapshotID()` (два `MemoryVersion` base/enriched
|
||
+ два снапшота W1/W2 вместо одного book-global, §1(в)) = снапшот-инвалидация — ОЖИДАЕМАЯ строка golden re-capture
|
||
(структура хеша меняется даже при идентичном контенте).
|
||
|
||
**Доказательство «переоплата ОДНА»:** пере-прогон = ОДИН fresh-translate под финальным конфигом (W1 под `snapshot_W1`
|
||
+ W2 под `snapshot_W2`); ВСЕ вышеперечисленное фолдится в эти два пер-волновых снапшота ДО старта прогона. W1.5-
|
||
обогащение банка двигает ТОЛЬКО `snapshot_W2` (пер-волновой скоуп, §1 (в)) — W1 не пере-оплачивается. Итог: один draft-
|
||
проход + один edit-проход = стоимость книги ×1 (не ×N от множественных resnapshot). Golden re-capture: маскированный
|
||
структурный дифф старого↔нового снапшота = только хеши/версии + новые поля.
|
||
|
||
---
|
||
|
||
## §9. Диспозиции хвостов
|
||
|
||
**Свип дорожек L1–L8 аудита 08 (полнота; приоритет L1/L2/L3/L5):**
|
||
- **L1 (контракт t/e):** editor-4-мандата-full-regen → **WS6 свап-арм** (near-term: слабое звено = редактор, D38/D39.9);
|
||
translator-structure-arm (H3) → **ЗАКРЫТ D39.9** (flash-черновик уже верен 25/0/27; pro не ратифицирован; «верность у
|
||
переводчика» закрыта); diff-editing (H4/E.7) → **парковка Q4b** (не тестировано; EM 0.68–0.95 на КОДЕ); fidelity-no-
|
||
owner → **WS5 DC-2/DC-7 детерм. чекеры** (полярность/число/грейд/ранг) + omission-бэкстоп.
|
||
- **L2 (сегментация):** ВЕСЬ трек → **WS2** (бюджет-output-токены, edit-единица, снос STMDepth/OverlapTokens, мега-
|
||
предложение-флаг); фантомный «D35.7» формализован D39 как цель слоя 1 (`05-log:563`), реализуется здесь.
|
||
- **L3 (память):** код-корень терм-дрейфа **ЗАКРЫТ треком A** (`d3f6b34` trust-gated suppressor `memory.go:684`,
|
||
громкий trustGateEvent) — **НЕ переоткрываем**; src→dst редактор (D30.1) → **WS2 (решён)**; майнинг ПОВЕРХ → WS3.
|
||
- **L5 (экспорт):** нормализация **ЗАКРЫТА треком A** (`exportNormalize`, fold-first санитайзер v6, CJK-gloss
|
||
whitelist owner-решение) — **НЕ переоткрываем**; L5-legit-cjk-gloss-stripped (D38.3 §4б owner-q) → **РАЗРЕШЁН**
|
||
(whitelist сохраняет глоссы `sanitizer.go:662`, WS4-банкнота = dst-канал); резидуалы L5-broken-word (retract) /
|
||
L5-diacritics (NFC-pass в export) / L5-regressionguard-40% (калибровка) — мелкие долги ниже.
|
||
- **L4 (пер-язык промпты; L4-convention-pack-layer NEVER_CLOSED/HIGH):** сеам **ЗАЛЕНДЁН треком A** (`prompts:{zh-ru}`
|
||
fail-loud); полный versioned convention-pack ЛАЙЕР + язык-промпта → **промпт-тема `10-prompt-architecture.md`**, гейт
|
||
exp15+research/18 §D-3 (форма пакета). **Субстанция пакета РЕАЛИЗУЕТСЯ здесь:** данные пакета пары zh-ru (единицы DC1/
|
||
регистр DC6/verse DC5) = WS5-слой-2-данные; плагины P1–P6 = WS3. Форма versioned-layer — за промпт-темой.
|
||
- **H5 (no-in-loop-quality-signal, NEVER_CLOSED/HIGH):** частично ЗАКРЫТ треком A (`quality.go` QualityReport = claim-1
|
||
структурный KPI); span-citing судья claim-2 нет. **Субстанция слоя-5 сигнала = WS5** (DET-чекеры DC1/2/3/6/7 +
|
||
omission-бэкстоп = в-контуре измеримость); семантический span-судья — Ф2 (ресёрч-зависим).
|
||
- **L6 (дискурс-reflow):** Ван Цуй 5 техник + чэнъюй-атом верны; резидуалы (L6-overclaim `editor.md:14`, deliteralize↔
|
||
chengyu tension, chengyu-atom untested) → **промпт-тема / измерить в пере-прогоне** (мелкие долги ниже). confirm-only.
|
||
- **L7 (NEVER_CLOSED владельческие идеи):** H6–H19 — каждой явная диспозиция ниже.
|
||
- **L8 (чистота кода):** role-registry / target-гейты / gatesEnabled-снос **ЗАКРЫТЫ треком A**; остаток (strip-smear
|
||
5-файлов, foldModelWire-extract, prompt-orphans) — **закрыты пак-1/1.5** (аудит датирован ДО них); confirm-only.
|
||
|
||
**Ledger-очередь D39.4/39.5 (LOW/NOTE — в пак по надобности, не блокеры):** golden-глосс-ячейка, escalated+stripped
|
||
тест, Retries-снапшот pre-existing, пунктуационные огрызки, trustGateEvent первый-отказ, pair-fail-loud-до-store,
|
||
капы `maxGlossCJKRunes=6`/`maxGlossLatinTokenRunes=24` (tunable, ревизия по пере-прогону), F6-rename (CJK-сплит).
|
||
|
||
**§E research/19 (E.5–E.8-бис):** E.5 аддитивный `Chunk` → WS2 (реализовано). E.6 кнобы когезии → СНЕСЕНЫ (carryover
|
||
не строим). E.7 дифф-apply после Q4b → **парковка** (Q4b не гонялся; diff-XYZ EM 0.68–0.95, aider 91–98% на КОДЕ,
|
||
ru-проза — гипотеза). E.8 DeepSeek-слаги → WS1 (в)-(в) (grep). E.8-бис ZAI-кэш → WS1 (в)-(б) (разрешён).
|
||
|
||
**Парковки (НЕ тестировано — консервативный дефолт, НЕ строим, НЕ хоронить как «доказано»; ревизия по пере-прогону):**
|
||
lookahead (Q3b) → WS1 (е). diff-редактор §C2 (Q4b) → E.7 выше. **Q4c reflow-отдельным-пассом · Q2c широкое-окно/
|
||
узкая-эмиссия · Q5 W2.5-швейный-пасс — все три НЕ гонялись, парк, не в дефолт** (§0-скоуп: рычаги сцеплены, но эти
|
||
конкретные армы вне ратифицированной матрицы; ревизия только если пере-прогон/чтение владельца укажут дефицит).
|
||
|
||
**§E research/20 (E-бэкенд-1…6):** E-1 `Source:mined`+`tmctl seed-lint` → WS3. E-2 канал сноски → WS4. E-3
|
||
`tmctl export --pairs` (НЕ существует на HEAD, `main.go`) → **ОБЯЗАТЕЛЬСТВО пак-4** (ревью-2 F7: НЕ «слот по
|
||
надобности» — §5(д) требует source-столбец ДО FP-замера DC1/DC2): source-join в Export уже есть (`export.go`
|
||
bookChunks); флаг `--pairs` строится как ПРЕД-УСЛОВИЕ §5(д)-замера DC1/DC2. E-4 транспорт gender → WS5-DC3.
|
||
E-5 ruby↔mined схема → WS3. E-6 src→dst редактор (D30.1, `memory.go:505-511`) → **WS2 (решён в план, не хвост)**.
|
||
|
||
**Дефекты D39.9 (finish=length-гейты в eval-харнесах):** `exp14_common.call` НЕ отклоняет `finish=length` — это
|
||
EVAL-риг-долг (полигон), НЕ прод (прод classify обрабатывает length, `stagerun.go:455`). Прод-инвариант WS4: генерации
|
||
только `finish=stop`. Диспозиция: eval-риги будущих полигон-сессий чинят (в промт-стандарт D39.7), прод чист.
|
||
|
||
**NEVER_CLOSED владельческие идеи дорожки L7 аудита 08 (каждой — явная диспозиция, требование `09:165`):**
|
||
- **H7 input-size-limit** (лимит входных токенов книги, отдельно от money-ceiling): **НЕТ кода/диспозиции.**
|
||
Диспозиция: **preflight-чек в W0** (est-токены книги vs конфиг-лимит `max_book_tokens`, fail-loud ДО трат) — дешёвый,
|
||
в пак-2 (W0 уже считает est_out). Владельцу: значение лимита (§10).
|
||
- **H8 abuse/misuse pre-screen** (дешёвый high-precision скрин prompt-injection/non-translation): **НЕТ кода/дисп.**
|
||
Диспозиция: **паркуется в Ф3** (trust-boundary + injection-probe → eval-очередь, `05-log:311` «не срочно»); дешёвый
|
||
non-translation pre-screen — записка владельцу (§10: строить сейчас дёшево или Ф3?).
|
||
- **H10 user-stop/cancel** (+ non-resumable для abuse-джобов): **НЕТ кода/дисп.** Диспозиция: **Ф2/Ф3** (resume.go +
|
||
ceiling/outage-пауза есть; user-facing stop в `tmctl` — дешёвый follow-up, но не гейтит пере-прогон). Записка (§10).
|
||
- **H16 self-improvement harness** (само-улучшение без дорогого human-review): **НЕТ кода/дисп.** Диспозиция:
|
||
**предпосылка = слой 5 quality-сигнал (WS5) + banknote/bank-auto-build (WS3)**; сам A/B-loop = **Ф3** (frontier-meta-
|
||
reviewer убит владельцем V4-п2, базовая идея — после того как слой 5 даёт измеримость каждой правки).
|
||
- **H17 frontier-meta-reviewer** (фронтир-модель ревьюит правки пайплайна): **ЗАКРЫТ владельцем (V4-п2)** — НЕ
|
||
переоткрываем (ревью-2 F10: без этой строки клейм «H6–H19 каждой диспозиция» формально ложен). Базовая измеримость
|
||
правки = слой 5 (WS5); сам meta-review-loop = Ф3 (см. H16).
|
||
- **H6 running-summary** (DelTA-class near-term рычаг): **carryover НЕ строим** (D39.7/8 — метрики под полом 0.126 И
|
||
читатель). Диспозиция: **ретайр для книг этого класса** (не хоронить как «доказано» — ревизия на структуро-разнообразном
|
||
корпусе; §0.1). Не в пак.
|
||
- **H9 parallelism** («главная V4-идея»): **ПОДХВАЧЕНО WS1** (волновой раннер = safe-parallel дизайн; не наивный —
|
||
клиенты предвычислены, деньги сериализованы, sticky precompute'нут). Диспозиция: **строится (пак-2)**.
|
||
- **H15 glossary-auto-build** (V4-п4): **ПОДХВАЧЕНО WS3** (банк-майнинг W1.5 = query-time context + детектор). Диспозиция:
|
||
**строится (пак-3)**; broad web-fetch auto-populate = Ф3.
|
||
- **H11 backend-render-questions** (§D-7 neighbor-reference): PROD-MINOR (`MessagesWithInjection` принимает произвольную
|
||
инъекцию); ±1-reference SHELVED (exp14 A-ref null). Диспозиция: **закрыто SHELVED** (соседи-черновики не в дефолт, §1 (е)).
|
||
- **H12 cross-boundary trap-set** на вебновелл-домене: не построен; «cross-boundary не доминирует» предварительно (PD-
|
||
classic). Диспозиция: **чистовик на вне-претрейн новелле** (после пере-прогона, §0.1).
|
||
- **H13 broken-draft-joins** (битые склейки без детектора): Диспозиция: **omission-бэкстоп WS5 частично покрывает**
|
||
(content-floor); специфичный join-детектор — ledger-хвост LOW.
|
||
- **H14 inversion-guard** (полярность/ранг/эмоция, D37 §2г): **editor-swap = near-term защита** (WS6) + **DC-7 grade/role
|
||
чекер + DC-2 полярность-числа** (WS5) частично реализуют. Диспозиция: **WS5-DC частично + WS6 свап**; полный
|
||
полярность-guard — ревизия по пере-прогону.
|
||
- **H18 findings-ledger process** (концерн-5, стоящий процесс): Диспозиция: **оркестратор-процесс** (completeness-critic
|
||
на границе фаз — этот план = экземпляр; не бэкенд-код).
|
||
- **H19 merge↔completeness collision** (`editor.md:8` сливай vs `:9` полнота, без omission-guard): Диспозиция:
|
||
**omission-бэкстоп WS5** = измеримость коллизии (лемма-присутствие после мержа).
|
||
|
||
**L5/L6 мелкие долги (аудит 08 §8 п.9):** L5-broken-word-class (fix-or-retract — D-лог рекламирует несуществующую
|
||
способность; **retract** в контракте, класс отложен Ф2-морфология) · L5-diacritics-class (NFC-pass дёшев — **в
|
||
export-слой**, zero-FP) · L5-regressionguard-40% (калибровать по реальному draft→final распределению — ledger-хвост) ·
|
||
L6-overclaim (`editor.md:14` «КОНВЕНЦИЯ русского» → техника-vs-норма split — промпт-тема) · L6-deliteralize↔chengyu
|
||
(эксплицитная граница — промпт-тема) · L6-chengyu-atom (измерить в пере-прогоне, не считать закрытым).
|
||
|
||
---
|
||
|
||
## §10. Реестр вопросов владельцу (консолидированный, с дефолтами плана)
|
||
|
||
| # | Вопрос | Дефолт плана | Развилка |
|
||
|---|---|---|---|
|
||
| 1 | **W1.5-UX:** стоп посреди книги для подписи vs автопродолжение? | Явная стоп-граница (раннер стоп → подпись → resume W2) | UX-решение |
|
||
| 2 | **DC-5 стих:** рендер-политика (не сплющивать) + слот сноски? Детерм. детекция НЕ работает (FP 74%/42%) | Пак-локусы (владелец курирует src-строки) + рендер-мандат + сноска; LLM-номинация не гейт. **Рекомендация оркестратора (ревью-2):** дефолт плана поддержан | Продукт-решение |
|
||
| 3 | **DC-3 gender:** промоут `甲乙丙丁`/`四代族长` draft→approved + подпись пола `人祖=male, 古月=n-a, 白凝冰=hidden` | Промоут + reseed (owner-only, approved-инвариант) | Подпись |
|
||
| 4 | **H7 input-limit:** значение `max_book_tokens`? | Preflight-чек в W0, лимит tunable | Настройка |
|
||
| 5 | **H8 misuse-prescreen:** строить дешёвый non-translation скрин сейчас или Ф3? | Ф3 (не срочно) | Скоуп |
|
||
| 6 | **H10 user-stop:** user-facing stop/cancel в tmctl сейчас или Ф2/Ф3? | Ф2/Ф3 (ceiling/outage-пауза есть) | Скоуп |
|
||
| 7 | **Мини-голд алиасов** (~20–30 мин): нужен для recall кластеризации ярус-1 | Без него — только precision | Тачпойнт |
|
||
| 8 | **precision@30 non-seed A3:** адъюдикация T/F/? | Сайдкар готов (`precision_at30.md`) | Тачпойнт |
|
||
| 9 | **DeepSeek пик ×2:** риск-пин (вторичка, не офиц.); ре-чек 24.07 у катовера слагов. **Провенанс (ревью-2 F11):** клейм D39.7 «официально» имел провенанс «через владельца» (URL/цитата НЕ пинились); свежий чек 19.07 офиц. прайса = ФЛЭТ → label остаётся РИСК-ПИН до ре-чека 24.07 (там запинить URL+цитату); историч. запись D39.7 НЕ переписывать (D23.3) | scheduler-aware вне пик-окон + ×2-бюджет-фолбэк | Вендор-чек |
|
||
| 10 | **Свап-арм качество:** платный полигон-прогон армов после стройки (планка 2 претензии)? | Пере-прогон 3–10 глав через прод-путь | Деньги-развилка |
|
||
| 11 | **ja→ru реплика** (P1=ruby-канал) как тест общности §0.1 после zh→ru | Отдельный мини-фриз след-за-стройкой | Скоуп/деньги |
|
||
| 12 | **PostcheckGate флип** (hard-gate) — висит за пере-замером D24.4/D28.1 | Дефолт-флаггер (false); пер-волновой снапшот держит обе механики | Пере-замер |
|
||
| 13 | **Edit-ceiling размер** (ревью-1 WS2-F1): глава-единица до 6.5k out span-омиссия НЕ доказана безопасной (только Q2a) | Консервативный `EditCeilingOut≤3200` до Q2a; большая-глава-арм — платный Q2a span-судья. **Рекомендация оркестратора (ревью-2):** дефолт 3200 + платный Q2a-гейт поддержан; Q2a ОБЪЕДИНИТЬ с полигон-прогоном свап-армов (Q10) | Деньги/качество |
|
||
| 14 | **WS3 ru-лемматизатор** (ревью-1 WS3-F2): Палладий-подканал V-C нужен pymorphy3 (dst_variants+is_name_lemma) | (A) faithful pymorphy3-порт → golden exact; или (B) дроп Палладий → `古月:21→22`, скрин PASS, пере-пин. **Рекомендация оркестратора (ревью-2):** дефолт **(B)** — дроп подканала с пере-пином (dst доставляет банкнота, exact-rank НЕ продуктовая ценность); (A) только при готовой поддерживаемой Go-морфологии | Порт-цена/точность |
|
||
|
||
---
|
||
|
||
## §11. Мандат самопроверки (исполнено) + приёмка
|
||
|
||
**Ревью исполнением:** каждый верификационный скрипт (`eval/design11/ws{1,2,3,4,5}*.py`) ПРОГНАН, результат
|
||
воспроизводим (детерминизм: без time/rand в money-инварианте; фикс-mock-латентности); каждое несущее `file:line`
|
||
сверено с ЖИВЫМ кодом HEAD `766a60e` (не worktree-память отчётов). Находки верификации, изменившие план: (1) WS2
|
||
классиф.-mismatch = 0 на zh (не realign, документировать); (2) WS3 сид-дельта флагает D38-дефект как draft
|
||
(дисциплина работает) + фрагмент-шум (эмиттер реюзит фильтры); (3) WS5 DC-5 стих НЕ лендится детерм. (74%/42% FP) →
|
||
эскалация владельцу; (4) WS1 W1.5-re-bill-форк → пер-волновой снапшот.
|
||
|
||
**Адверсариальный селф-ревью несущих алгоритмов — ИСПОЛНЕН (раунд-1, 5-агентный refute-by-default воркфлоу, author≠
|
||
reviewer; каждый агент пере-исполнил верификации + сверил file:line на HEAD).** Все скрипты воспроизвелись байт-в-байт.
|
||
Несущие расхождения ВПИТАНЫ в план (помечены «ревью-1» in-line):
|
||
- **WS1-F1 (несущее):** «переоплата ОДНА» держит НЕ снапшот, а **волновой инвариант секвенирования** (W2 не пере-рендерит
|
||
draft; редактор читает черновик из W1-чекпоинта) — `renderGlossaryBlock` инъектит майненые draft-строки, так что
|
||
наивный пере-рендер draft над обогащённым банком пере-оплатил бы W1. Снапшот избегает resnapshot-СТОПА. → §1(в) переписан.
|
||
- **WS1-F3/F4/F5:** money-границы ПАРАЛЛЕЛЬНЫ (≤N in-flight, overshoot ≤ Σ(cost−est)); mock ≠ полное зеркало (day-ceiling/
|
||
идемпотентность в Go-тест); wall-clock = compute-only, end-to-end + W1.5-стоп. WS1-F6/F8: client() read-only в волнах;
|
||
`waves.workers` (не fanout).
|
||
- **WS2-F1 (риск):** edit=глава при 6.5k out НЕ доказана span-безопасной (backstop entity-уровня слеп; только Q2a) →
|
||
`EditCeilingOut≤3200` консервативно + Q2a-гейт (§10-13). **WS2-F2:** 1797 не byte-identical (4 чанка, 2 абзац-сдвига).
|
||
**WS2-F3:** классиф-инвариантность корпус-специфична (не ja/ko). **WS2-F4:** src→dst — одно несущее обоснование
|
||
(омонимы), явный снапшот-фолд формата.
|
||
- **WS3-F1/F2:** паритет-фикстура расщеплена (Палладий-инвариант vs -зависимый `古月:21`); «λ=0 → лемматизатор не нужен»
|
||
ОПРОВЕРГНУТ (dst_variants безусловен λ) → развилка A/B/C (§10-14).
|
||
- **WS4-F1/F2/F3:** point 8 + эскалационный путь (draft эскалирует в prod); парсер-версия = verdict-ось снапшота (не
|
||
PromptSHA256); trailing-note НЕ бэкстоп банкноты.
|
||
- **WS5-A1..A6:** DC1/2/6 сработки = n=1 на корпусе-открытия (НЕ FP-rate) → landing гейтится §5(д); DC2=гипербола-exposed;
|
||
DC3-fires = паратекст-кореф (не hidden; только male/female лендится); DC5 «две профили не лендятся» (не «неспособна»);
|
||
DC7 без $0-верификации; §5(д) нужен source-столбец (`tmctl export --pairs`).
|
||
- **Completeness:** Q4c/Q2c/Q5 явные §9-строки; H5/L4-pack/L5-gloss названы. CONFIRMED без правок: eager-build race-фикс,
|
||
Select-детерминизм, derived-hash формула, strip-ordering, records.json-FP-суррогат легитимен.
|
||
|
||
**Ревью-2 оркестратора (19.07) — ВПИТАН (in-line маркер «ревью-2»; провенанс: соло-проход оркестратора [полное чтение
|
||
+ спот-чеки file:line по HEAD исполнением; мульти-агентный рубеж НЕ запускался — лимиты владельца] + 2 замечания
|
||
владельца F4/F5).** Вердикт: план РАТИФИЦИРУЕМ после фикс-листа. Ни одна находка НЕ пересматривает алгоритмы или шесть
|
||
$0-верификаций — все правки ТЕКСТОВЫЕ (скрипты не пере-гонялись; ни одна (г)-цифра не изменилась). Фиксы:
|
||
- **F1 (MAJOR):** `EditCeilingOut` дефолт приведён к **3200** (было противоречие «8000» в §2(в) vs ≤3200 везде);
|
||
8000 = потолок ГЕЙТНУТОГО крупно-главного арма за Q2a. → §2(в).
|
||
- **F2 (MAJOR):** явный инвариант — mid-run подпись W1.5 трогает ТОЛЬКО `Source:mined`; правка seed/ruby = ОТДЕЛЬНОЕ
|
||
пред-прогонное resnapshot-событие (§8), НЕ W1.5; промоут 甲乙丙丁/四代族长 — в reseed. Пин в (д). → §1(в)/(д).
|
||
- **F3 (MAJOR):** инъекция W2 специфицирована — СВЕЖИЙ `Select` по ВСЕЙ единице над enriched-банком, запрет реюза
|
||
per-чанк W0-`memSel` (base). → §1(б)/§2(б)/(д).
|
||
- **F4 (MAJOR, владелец):** пер-модельный rate-guard в волновом диспетчере (пер-вызовный 429 УЖЕ есть
|
||
`httpllm.go:27-29`, гэп = N-∥); `models.yaml`-конфиг, НЕ снапшот-ось; mistral-арм — за rate-guard; заготовка
|
||
quirks → §12; каветка wall-clock. → §1(а)/(б)/(г), §6(б).
|
||
- **F5 (MINOR, владелец):** полы 0.126/0.261 — ИСТОРИЧЕСКИЕ, per-editor-model + per-материал; каждый арм меряет свой
|
||
A0↔A0′ (~$1); главные оси floor-иммунны (DET + слепое чтение). → §6(б).
|
||
- **F6 (MINOR):** DC-3 развести инъекцию (ЛЕНДИТСЯ все три вкл. hidden-мандат) от hidden-ЧЕКЕРА (не лендится, Ф2-кореф). → §5(б).
|
||
- **F7 (MINOR):** `tmctl export --pairs` = обязательство пак-4 (пред-условие §5(д)), не «слот». → §7/§9.
|
||
- **F8 (MINOR):** сайзинг edit-единицы (`max_tokens`+`Reserve`) unit-aware (МЕХАНИЗМ исправлен пост-верифай: «от ЧЕРНОВИКА `prev`, не est_out» — блок ниже). → §2(б)/(д).
|
||
- **F9 (MINOR):** §8 += `banknoteSnap{enabled,parser_version}` verdict-ось + строка «пер-волновая реструктуризация =
|
||
снапшот-инвалидация». → §8.
|
||
- **F10 (MINOR):** H17-frontier-meta-reviewer добавлен в §9-свип (ЗАКРЫТ V4-п2 — иначе «H6–H19 каждой» ложен). → §9.
|
||
- **F11 (микро):** §10-9 нота провенанса Q9 (D39.7 «официально» = через владельца; риск-пин до 24.07, D39.7 не переписывать). → §10.
|
||
- **§10 рекомендации оркестратора** вписаны: Q13 (3200+Q2a, объединить с Q10), Q14 (дефолт **B**), Q2 (дефолт поддержан).
|
||
|
||
**Пост-фикс адверсариал-воркфлоу (7-агентный, 19.07 — тот мульти-агентный рубеж, что ревью-2 не гонял; $0 к
|
||
провайдерам, все 6 $0-скриптов воспроизведены под `eval/.venv` [зависимости `regex`/`jieba`/`pymorphy3` — НЕ system
|
||
python]).** Вердикт критика: **РАТИФИЦИРУЕМ, все 11 фиксов на месте, F1 MAJOR полностью снят, MAJOR-противоречий нет;
|
||
6/6 golden воспроизведены байт-в-байт.** Несущие находки ВПИТАНЫ (маркеры «пост-верифай»/«испр.»):
|
||
- **F8 ПЕРЕПИСАН (был неверен):** «сайзить от `est_out` единицы» — ошибка; `stagerun.go:87-90` (D2.5) уже сайзит
|
||
редактора от ЧЕРНОВИКА (`prev`, ~1.9× источника), а `est_out` источнико-производна + чужое токен-пространство → НОВОЙ
|
||
формулы нет, §8-строки F8 не требует. → §2(б)/(д).
|
||
- **F1 ПЕРЕ-СИМУЛИРОВАН at 3200:** ратиф. дефолт = 25 глав → **37 edit-единиц** (11 делятся, 10 split-хвостов <1k out);
|
||
«25/25 в 2k–8k» был 8000-арм. → §2(б)/(г), `ws2_chunk_sim.py` ceiling∈{8000,3200}.
|
||
- **F2 write-path (грунт-гэп критика):** `loadGlossarySeed` хардкодит `Source:"seed"` (`memseed.go:131`) → reseed
|
||
mined-дельты ОБЯЗАН нести `Source`-столбец, иначе `snapshot_W1` двигается; 甲乙丙丁/四代族长 промоут = элевация в
|
||
`Source:seed` (base) → pre-run. → §1(в), WS3 (д).
|
||
- **Реконсиляция снапшот-loudness:** src→dst-блок + gender-рендер фолдятся ВЫДЕЛЕННЫМ `render-format-version`, НЕ
|
||
`memoryMatchVersion` (const скоуп-алгоритм `memory.go:33-47`) — §8/§5(в) приведены к §2(в).
|
||
- **F6 уточнён по records.json:** 2-я DC3-сработка (`ch1/chunk5`, «её дар» на Бай Нинбин, сцена совета) = narrative-coref
|
||
на HIDDEN-персонаже, НЕ паратекст — СИЛЬНЕЕ довод к Ф2. → §5(б)/(г).
|
||
- Мелкое: `banknoteSnap` имя поля унифицировано (`parser_version`); §3(б)/§0-сводка приведены к дефолту B; whole-chapter
|
||
Select-бюджет — открытый пункт (§2(е)).
|
||
|
||
**Подтверждающий пас (3-агентный, 19.07 — верификация 6 корректировок на НОВЫЕ противоречия) — ИСПОЛНЕН.** Поймал ДВА
|
||
F1-класс-резидуала (моя реконсиляция сиблингов оставила одну строку устаревшей) — ОБА пофикшены: (1) **MAJOR** —
|
||
§8-WS5 `gender-инъекция → memoryMatchVersion` не был приведён (сиблинги §5(в)/§8-WS2/§2(в) были) → реконсилирован к
|
||
`render-format-version`; (2) **MINOR** — §1(в) предлагал «расширить `seedTerm`-схему», что противоречит §3(б) «без новых
|
||
полей» → пиннут ЕДИНЫЙ путь: отдельный mined-write-путь (штамп `Source:mined`), §3(а)/§3(б)/§1(в) согласованы.
|
||
Корректировки 1/2/5/6 подтверждены ЧИСТЫМИ (F8 grounded `stagerun.go:87-90`; 37-единиц воспроизведён байт-в-байт;
|
||
F6 по records.json; имена/дефолт-B). После фикса резидуалов — MAJOR-противоречий не осталось.
|
||
|
||
**Приёмка (оркестратор):** пере-исполнение симуляций; спот-чек file:line; refute-воркфлоу по несущим алгоритмам;
|
||
сверка полноты против скоуп-листа D39.11. Мин-планка ратификации: все WS с исполненной (г) — **все шесть исполнены и
|
||
PASS** ($0-верификации воспроизводимы, детерминированы); манифест resnapshot полон (§8); реестр владельцу
|
||
консолидирован (§10). **Гейтнутые армы (ратифицируемы как ГЕЙТНУТЫЕ, стройка сердцевины не ждёт, но арм не стартует до
|
||
верификации):** (1) **WS2 КРУПНАЯ edit-единица** (>~3200 out) — гейтится платными Q2a span-судьями (сердцевина строит с
|
||
консервативным `EditCeilingOut≤3200`); (2) **WS6 качество свап-арма** — гейтится платным полигон-прогоном после стройки
|
||
(COGS-сторона (г) исполнена; эскейп-хатч (а)/(б) D39.11); (3) **WS5 DC-чекеры landing** — гейтится $0-FP-замером §5(д)
|
||
на СВЕЖЕМ прогоне (текущий n=1 недостаточен — не платный гейт, build-time тест); (4) **WS6 mistral-арм через прод-путь**
|
||
— гейтится пер-модельным rate-guard (ревью-2 F4: ~48% retry-fails без него искажают латентность+биллинг). Эти четыре —
|
||
развилки в §10 (13/10/9/…), маршрутизированы явно, не тихо. Эмпирика exp15/16 — предварительна до вне-претрейн новеллы: несущие
|
||
пороги «tunable, ревизия по пере-прогону».
|
||
|
||
---
|
||
|
||
## §12. Заготовка для `00-provider-quirks.md` (ревью-2 F4 — вносит ОРКЕСТРАТОР при лендинге, зона полигона)
|
||
|
||
> ⚠ Этот блок — НЕ часть плана-контракта; это черновик записи для `docs/experiments/00-provider-quirks.md` (зона
|
||
> полигона). Дизайн-синтез-сессия НЕ пишет в `docs/experiments/`; оркестратор переносит текст ниже в quirks-файл при
|
||
> лендинге плана и там же пинит URL/цитату при пере-замере на прод-тире.
|
||
|
||
**`mistral-large-latest` — агрессивный rate-limiter (тир-зависим, пере-замерить на прод-тире):**
|
||
- Судейский eval-риг (exp15 §7.6 REV.2, N-параллельные вызовы): **~48% retry-fails @1.3s интервала**, max latency
|
||
**64.7s**; `grok-*` в том же риге — **0%**.
|
||
- Расширение интервала **1.3→2.6s эффекта НЕ дало** (49.5→48.2%) → лимитер похож на **токен-бакет / конкуренц-кап**,
|
||
НЕ per-request-пейсинг; тир-зависим.
|
||
- **Действие бэкенда (WS1(б)):** пер-модельный семафор конкуренции + 429/`Retry-After`-бэкофф (пер-вызовный уже есть,
|
||
`httpllm.go:27-29,138-140`, кап `maxRetryAfterWait=5мин`). Правило двух направлений: цифры из eval-рига, НЕ офиц.
|
||
доки — при переносе в quirks запинить прод-тир-замер + вендор-страницу rate-limits.
|
||
- **Пред-условие:** mistral-editor-арм не идёт через прод-путь до этого guard (§6(б)).
|