textmachine/backend
2026-07-19 18:03:57 +03:00
..
cmd/tmctl Land backend pack-11 continuation: Go miner with exact parity, banknote 12-point integration, DC checkers with export --pairs, editor arm configs, and additive wave snapshot; clear the rubezh-2 debt with a three-item fix list 2026-07-19 15:24:48 +03:00
configs Land the language-data isolation arch pass (D39.16): move miner zh/Palladius data to internal/lang and configs/langpacks byte-exactly, land FL-1/2/3, ratify the three press-tested divergences, archive the worked prompt 2026-07-19 17:47:14 +03:00
docs Actualize the polygon README and the D15.2 spec status: tmctl export extraction rule, superseded editor caveat, judge EOL residual, deferred-implementation banner 2026-07-17 03:20:53 +03:00
example Land track-A pack-1.5 with fix-list F1-F9: tmctl export surface with manifest and drift guards, fold-first sanitizer detection, bounded CJK-gloss whitelist, runnable zh-ru example 2026-07-17 02:16:48 +03:00
internal Land the language-data isolation arch pass (D39.16): move miner zh/Palladius data to internal/lang and configs/langpacks byte-exactly, land FL-1/2/3, ratify the three press-tested divergences, archive the worked prompt 2026-07-19 17:47:14 +03:00
prompts Ratify D39.1: land research/19 as the track-B design of record with the wave architecture and pre-registered empirics, review waived by the owner 2026-07-16 21:52:17 +03:00
.env.example Drop Anthropic from the model stack per owner decision: remove provider and Claude models, repoint escalation and C2 judge to non-Anthropic 2026-07-04 16:35:52 +03:00
go.mod Harden Phase 0 after self-review: snapshot coverage, response-price fallback, usage clamp, job-status lifecycle, config guards, source normalization, hash robustness 2026-07-04 14:49:43 +03:00
go.sum Harden Phase 0 after self-review: snapshot coverage, response-price fallback, usage clamp, job-status lifecycle, config guards, source normalization, hash robustness 2026-07-04 14:49:43 +03:00
README.md Actualize all documentation to post-D39.16: refresh current-state headers, status lines, D-log ranges, langpack realization notes, and zone README cross-references 2026-07-19 17:55:51 +03:00

backend/ — Go-бэкенд TextMachine

Зона сессии «Бэкенд». Контракт — docs/architecture/05-decisions-log.md (D1D39.16); целевая архитектура арх-ресета (7 слоёв, инвариант общности §0.1 — любая книга/пара/структура) — docs/architecture/09-target-architecture.md; план реализации пере-прогонного стека — docs/architecture/11-implementation-plan.md (D39.12, ратифицирован); активный промт стройки — docs/BACKEND_PLAN11_SESSION_PROMPT.md (R1 драйвер-свитч); контракты Фазы 0 — 03-implementation-notes.md; квирки провайдеров — docs/experiments/00-provider-quirks.md. Язык-данные майнера — вне пайплайна: internal/lang+configs/langpacks/ (D39.16). .env не читать.

(Актуализировано оркестратором 17.07 по мандату владельца, факты сверены по коду; предыдущая ревизия была эры D23.)

Карта пакетов

Пакет Что делает Ключевые файлы
cmd/tmctl CLI: translate / status (read-only N/M+паспорта глав+деньги, --json; работает ПРИ живом прогоне — store без flock) / report (request-log+леджер книги + per-run quality-report: структурный KPI предл./нарратив-абзац, тире, cosmetic-strip/echo-rates, глоссарий-промахи, trust-gated — наблюдаемость, НЕ гейт; D39.2-T4) / export (экспорт-поверхность для полигона: final_hash→checkpoint→exportNormalize, manifest-join c pending/ghost-учётом, ConfigDrift-поле, --plaintext; D39.5) / redrive (переатака флагнутых: --chapter/--chunk/--reason/--dry-run, D15.3). main — тонкая обвязка: разбор/exit-коды/.env/рендеры в тестируемых функциях main.go, invocation.go, render.go, dotenv.go
internal/llm OpenAI-совместимый транспорт + retry/backoff, capability-слой (budget_field/temperature/reasoning per-модель), failover (написан, НЕ подключён — D4: только local-роли), нативный Anthropic = DEPRECATED-референс httpllm.go, capability.go, failover.go
internal/ledger Цены по usage (вкл. reasoning/cache-поля), PriceForResponse по фактической модели pricing.go
internal/store SQLite (modernc, CGO-free), идемпотентные миграции v1v8 (v8 = trust-gate поля retrieval_state, D39.2-T1), reserve/settle+checkpoint, chunk_status, глоссарий, ruby, retrieval_state (стиль-флаги v7 + n_trust_gated_suppress/detail v8), request_log; OpenReadOnly — без flock/миграций/recovery для status/report/export ledger.go, migrate.go, glossary.go, store.go
internal/config fail-fast загрузка models/pipeline/book; эхо-мина-гейт echoMineViolation; CheckRunnable блокирует неисполнимое (C2/fanout/judge); pair-keyed промпт-слой (D39 слой 2): Stage.Prompts{«zh-ru»: path} + PromptPathForfail-loud на отсутствующую пару (ja-книга больше не едет молча через zh-промпт); legacy одиночный prompt: жив (XOR-валидация) models.go, pipeline.go
internal/pipeline Раннер по связным единицам: сетап runner.go → снапшот snapshot.go → сид seeding.go → цикл книги bookrun.go → петля чанка chunkrun.go → стадия stagerun.go → эскалация с ре-гейтом escalation.go → resume resume.go; чанкер v4 (⚠ бюджет = const 1500, логическая граница НЕ построена — слой 1 гейтится exp15); classify/coverage; банк памяти v2, memmatch-v4: Aho-Corasick, спойлер-окна, disposition, trust-gated longest-match (draft-длиннее НЕ съедает вложенный approved; отказ = громкая телеметрия — терм-дрейф закрыт в КОДЕ, D39.2-T1), post-check; санитайзер v6: fold-first детекция всех 6 классов (обход полноширинными сигнатурами закрыт, D39.5-F1) + CJK-глосс-whitelist «терм (漢字)» (bounded, D39.5-F2) + exportNormalize (export-contract слой 6: каждый FinalText нормализуется; санитайзер = чистый детектор); реестр roleInjectionRenderers (новая роль = данные+рендерер, не правка switch); readability-гейты за isRuTarget; export.go/quality.go — read-only проекции bookrun.go, stagerun.go, memory.go, sanitizer.go, export.go, quality.go, disposition.go
internal/obs trace_id, структурные логи (contextHandler несёт book/chapter/chunk/stage/role из ctx), safego

Инварианты — ЛОМАТЬ НЕЛЬЗЯ (каждый закреплён тестами)

  1. Деньги: reserve → call → settle+checkpoint одной транзакцией; committed == SUM(checkpoints) переживает kill -9 (kill9_test.go); цена — по фактически ответившей модели; потолки книга/день считают committed+reserved. Одно исключение — явный tmctl redrive (D15.3): после него committed ≥ SUM(checkpoints) — безопасное направление.
  2. Snapshot-дисциплина: всё, что влияет на wire-байты ИЛИ вердикты (capability, память content-hash + memoryMatchVersion, context-assembly, версии classify/coverage/chunker/maxtok/sanitizer (только при enabled), эскалационные оверрайды, биндинг пара→промпт через BriefHash+PromptSHA256), свёрнуто в snapshotID; правка = громкий --resnapshot = переоплата книги (D15).
  3. Эхо-мина DeepSeek: thinking НИКОГДА не отключать — reasoning:"off" там осознанный no-op; echoes_when_thinking_off + рекурсивный скан extra_body валят конфиг fail-fast. У grok off = ЯВНЫЙ reasoning_effort:"none".
  4. Порядок classify: refusal-blacklist / CJK-echo — ДО length/empty; retry-flagged только {length, empty} на той же модели; loop-чек ПЕРЕД удвоением max_tokens. Санитайзер — ТОЛЬКО на финальной стадии (isFinal) и только при ru-target.
  5. Эскалация: ровно 1 хоп, результат РЕ-гейтится, retry-бюджет не сбрасывается, editor pinned, канал adult — только permissive (fail-closed).
  6. Детерминизм: рендер — чистая функция snapshot; сортировки перед записью; никакого map-order в выводе; length-prefixed хэши; сорс-чанкер lossless (fuzz).
  7. Нейтральность адаптера: internal/llm не знает про перевод — контент-вердикты в раннере (disposition-слой, post-settle).
  8. Экспорт-контракт (D39 слой 6, D39.5): exportNormalize — эфемерная проекция (НЕ входит в request_hash/чекпоинты/деньги), применяется к КАЖДОМУ финальному тексту на всех выдающих поверхностях; любая внешняя экстракция (полигон!) обязана читать tmctl export, не сырые чекпоинты store — иначе видит ненормализованные байты и молча-неполную книгу (export делает manifest-join + drift-гард, сырое чтение — нет).

Подготовка ja-книги (чек-лист сида)

  • Kana-написания имён = matchable. Ruby-чтения захватываются на инжесте и авто-подцепляются как alias ручной записи (D16.4, attachRubyAliasesToManual). Имя, встречающееся ТОЛЬКО каной, внеси в aliases: руками — иначе «тихо пусто».
  • Двойные чтения (強敵→とも) — под флагом: длинное двойное чтение может дать CONFIRMED-ложь — при подозрении убери из сида. Полная дизамбигуация — Ф2 (B6).
  • Kana-precision ≥4 не замерена (minKeyLenPhonetic=3): кана-ключи не проверяются на границу слова (нет сегментации) — задача полигона + токенизатор B6.
  • ja-книга требует ja-ru записи в prompts:-паке стадий — pair-сеам fail-loud'ится без неё (пример: закомментированный ja-блок в example/book.yaml). Контент пакета = данные под реальную книгу (инвариант общности §0.1), не сочинять.

Как гонять

go build ./... && go vet ./... && go test ./... -race        # всё зелёное = норма
go run ./cmd/tmctl translate --config example/book.yaml      # реальные вызовы — ключи в .env (пример: zh→ru)
go run ./cmd/tmctl status --config example/book.yaml --json  # $0, N/M+паспорта+деньги, живой прогон ок
go run ./cmd/tmctl report --config example/book.yaml         # $0, quality-report (KPI/rates)
go run ./cmd/tmctl export --config example/book.yaml         # $0, экспорт-JSON для полигона (--plaintext для человека)
# live-conformance (реальные провайдеры, платно, вне CI):
set -a; . ./.env; set +a; TM_LIVE=1 go test -tags live -run TestLive -v ./internal/pipeline/

Golden-гард детерминизма (golden_test.go + testdata/golden/): пинит бит-в-бит snapshotID, request_hash, wire-тела, вердикты и resume-байты. Красный golden = wire/вердикты изменились = --resnapshot = переоплата. Обновлять ТОЛЬКО на ратифицированной смене поведения: TM_UPDATE_GOLDEN=1 go test ./internal/pipeline/ -run TestGolden; при re-capture — маскированный структурный дифф (хеши/версии → плейсхолдер) обязан быть пустым, если смена версий не меняла вердиктов.

Финал каждой вехи — агентское адверсариальное селфревью (мандат CLAUDE.md 12.07); внешнее ревью — оркестратор.

Известный техдолг (не трогать молча — см. D-лог / ledger 08-sync-audit-ledger.md)

  • Слой 1 (нарезка) НЕ построен: targetChunkTokens=1500 — const в единице оценки исходника; логическая граница/декаплинг edit-единицы/когезия — гейтятся exp15 (research/19 §D). STMDepth/OverlapTokens — мёртвые заглушки (в конфиге+снапшоте, исполнение их НЕ читает) — оживают со слоем 1, не удалять и не «подключать» мимоходом.
  • D15.2: READ-половина tmctl export ПОСТРОЕНА (D39.5, минимальная форма); annotation/override-половина и content-addressed resume — отложены (v3.1-спека = дизайн-оф-рекорд, docs/D15.2-…spec.md).
  • Retries.RegenerateBeforeEscalate НЕ в снапшоте (pre-existing, D39.4-LOW): в крэш-окне пониженный ретрай-бюджет молча бросает оплаченные OK-чекпоинты. Дизайн-фикс при следующем заходе в stagerun.
  • F3 at-most-once (после D15.2); Escal.Chains — валидируемый мёртвый конфиг (раннер читает только escalate_to); флоры min_max_tokens = схема (D24.3).
  • prompts/editor-mono.md — референс-вариант D13.1 (не боевой, тестом закреплён); боевой = editor.md v3-discourse (БИЛИНГВ). Глосс-капы санитайзера (6 CJK / 24 лат-токен) — tunable-эвристики (D39.5), ревизия по чтению пере-прогона.
  • Хвост LOW/NOTE-находок адверсариала D39.4 — в ledger-очереди (golden-ячейка глосса, escalated+stripped тест, trustGateEvent первый-отказ и пр.).