@startuml components title TextMachine — компоненты бэкенда (v3 2026-07-09, синхронизировано с 05-decisions-log D1–D17)\nПометки: [OK] = построено · [Ф1*] = остаток Фазы 1 · [Ф2]/[Ф3] = планово skinparam componentStyle rectangle skinparam wrapWidth 200 actor "Владелец / редактор\n(очередь флагов, подтверждение\nтерминов, BWS-оценка пилота)" as HUMAN package "Интерфейсы" { component "CLI tmctl: translate / report [OK]\n+ status / redrive [Ф1*]" as CLI component "HTTP API (IDE) [Ф3]" as API } package "Оркестратор" { component "Проект книги [OK]\n(translation brief, brief_hash,\nконфиг ядра C0/C1/C2/C3)" as PROJ component "Импорт txt/epub [OK]\n(главы -> чанки, ruby-захват,\nspine-reconciliation fail-loud)" as IMP component "Durable jobs [OK]\n(чанк-чекпоинты, resume, kill-9-инвариант;\ncontent-addressed reuse — гейт онгоинга [Ф1.5])" as JOBS component "Пайплайн-раннер [OK]\n(циклы/ретраи/single-hop эскалация\nс РЕ-ГЕЙТОМ = код; состав стадий/модели/\nпороги = конфиг; disposition D2)" as RUNNER component "Экспорт txt/epub/TMX + отчёт\n(паспорт качества главы) [Ф1*]" as EXP } package "Агентные роли (промпт-конфиги)" { component "Translator: черновик [OK]\n(C2: N ГЕТЕРОГЕННЫХ кандидатов [Ф2])" as ROLE_TR component "Stylist/Editor [OK]\nмонолингвальный D1 (оспорен — пилот-арм D13.1),\ndst-констрейнты CONFIRMED" as ROLE_ED component "Analyst: book brief [Ф2]" as ROLE_AN component "Terminologist / автопопуляция\nглоссария [Ф1*/Ф2]\n(спот=локаль, рендер=облако — exp06)" as ROLE_TERM component "Annotator: пре-пасс [Ф2]\n(speaker-ID, регистр, чэнъюй-маски)" as ROLE_ANN component "Judge / Selector [Ф2]\n(билингвальный, судья-анкета MQM;\nsecond-opinion чужого семейства\nна эскалированных чанках)" as ROLE_JU component "Line/Continuity Editor [Ф2+]" as ROLE_LE } package "QA-гейты (без LLM)" { component "Intrinsic classify [OK]\n(refusal/CJK-echo ДО length, loop-детект)" as QA_CJK component "Coverage / excision [OK, opt-in]\n(sent_cov + len_ratio, порт оракула)" as QA_COV component "Глоссарный post-check [OK]\n(decl-aware, CONFIRMED-only;\nфлаггер по умолчанию, гейт opt-in)" as QA_GLOS component "Дешёвые гейты Ф1 [Ф1*]:\nтире-линтер, ёфикатор,\nтранслит-междометия, число-гейт" as QA_CHEAP component "Морфо-гейт рода + канцелярит\n+ T-index [Ф2] (Python-сайдкар)" as QA_MORPH component "Валидатор Палладия/Поливанова B6 [Ф2]\n(ruby-reading = ground truth)" as QA_TRANSLIT } package "pkg/llm" { component "Роутер роль -> модель [OK]" as LLM_RT component "Capability-слой [OK]\n(budget_field/temperature/reasoning;\nэхо-мина DeepSeek fail-fast)" as LLM_CAP component "NSFW-классификатор 0-3 [Ф2]\n(НЕ специфицирован — нужна метрика приёмки;\nуровень 3 = скип чанка + флаг)" as LLM_NSFW component "Failover [OK, НЕ подключён]\nтолько local->cloud для local-ролей (D4);\nоблачные draft/edit: пауза+resume, НЕ своп" as LLM_FO component "Адаптеры OpenAI-совместимые [OK]:\nDeepSeek / GLM / Kimi / xAI / OpenAI /\nllama-server; нативный Gemini [Ф2]" as LLM_AD component "Кэш-раскладка префикса [OK]\n+ Batch (только Gemini-судья/QA) [Ф2]" as LLM_BC } package "Банк памяти книги (SQLite на книгу) [OK: v2]" { component "Глоссарий v2 [OK]\n(sense, alias-граф, decl, gender=hidden,\ntranslit_policy, ревизии)" as MEM_GLOS component "Горячий путь [OK]: Aho-Corasick,\nнормализация NFKC/trad2simp/kana/ignorables,\nспойлер-окна since/until (hard-reject),\ndisposition CONFIRMED/AMBIGUOUS/REJECT,\nsticky; фиксы границ D16 [Ф1*]" as MEM_HOT component "Ruby-захват [OK] -> сид auto-кандидатов;\nreading как матч-поверхность [Ф1*, D16.4]" as MEM_RUBY component "retrieval_state per-chunk [OK]\n(наблюдаемость инъекции/вытеснений)" as MEM_RS component "Резюме глава->арка->книга [Ф2]\n+ гейт фактичности резюме (реестр D1)" as MEM_SUM component "Series bible: ты/вы-журнал, род [Ф2]" as MEM_SB component "Векторный слой [Ф2, low-trust A7]\n(bge-m3, только кандидаты на ревью)" as MEM_VEC } package "Деньги и наблюдаемость [OK]" { component "Ledger: reserve -> settle+checkpoint\nодной tx, потолки книга/день,\nescalation-бюджет" as OBS_LG component "Премиум-бюджет: budget_usd =\nclamp(price x (1-margin) - base, 0, cap)\n(D11; жёсткие $-гейты сняты)" as OBS_QB component "request_log + trace + retrieval_state" as OBS_TEL } package "Eval / Полигон (зона eval/)" { component "Пилот-харнесс Ф2.5\n(BWS, memory-eval M0-M3, судья-панель;\nчинится до прогона — D13.5)" as EV_PILOT component "Refusal/excision-бенчмарк\n(18+ часть ждёт explicit-корпус — critical)" as EV_RB } cloud "LLM-провайдеры" { component "DeepSeek V4 (draft; thinking ON —\nэхо-мина; для explicit ЗАПРЕЩЁН ToS, D14.1)" as P_DS component "xAI Grok 4.3 (редактор SFW, канал B,\nсудья 18+; AUP без запрета adult-текста)" as P_XA component "Gemini 3.1 Pro (апекс/судья [Ф2])" as P_GM component "GLM / Kimi / OpenAI\n(альтернативы/эскалация)" as P_OTH component "Mistral — кандидат-фолбэк\nканала B [проба, D14.2]" as P_MI component "llama-server (GPU 8GB: скрининг,\nabliterated канала B, эмбеддинги,\nСПОТ-экстракция)" as P_LL } database "SQLite" as DB CLI --> PROJ API --> PROJ PROJ --> IMP IMP --> JOBS JOBS --> RUNNER RUNNER --> EXP RUNNER --> ROLE_TR RUNNER --> ROLE_ED RUNNER --> ROLE_AN RUNNER --> ROLE_TERM RUNNER --> ROLE_ANN RUNNER --> ROLE_JU RUNNER --> ROLE_LE RUNNER --> QA_CJK RUNNER --> QA_COV RUNNER --> QA_GLOS RUNNER --> QA_CHEAP RUNNER --> QA_MORPH RUNNER --> QA_TRANSLIT ROLE_TR --> LLM_RT ROLE_ED --> LLM_RT ROLE_JU --> LLM_RT ROLE_AN --> LLM_RT ROLE_TERM --> LLM_RT LLM_RT --> LLM_CAP LLM_CAP --> LLM_AD LLM_NSFW ..> LLM_RT : выбор канала A/B [Ф2] LLM_FO ..> LLM_AD : только local-роли (D4) LLM_BC ..> LLM_AD LLM_AD --> P_DS LLM_AD --> P_XA LLM_AD --> P_GM LLM_AD --> P_OTH LLM_AD --> P_MI LLM_AD --> P_LL LLM_NSFW ..> P_LL : классификатор 0-3 [Ф2] RUNNER --> MEM_HOT MEM_HOT --> MEM_GLOS MEM_HOT --> MEM_RS IMP --> MEM_RUBY MEM_RUBY --> MEM_GLOS MEM_HOT ..> MEM_SUM : [Ф2] MEM_HOT ..> MEM_SB : [Ф2] MEM_HOT ..> MEM_VEC : [Ф2], не в горячем пути HUMAN --> CLI : запуск, флип гейтов (за подписью) HUMAN <-- EXP : отчёт, паспорт качества, флаги HUMAN --> MEM_GLOS : подтверждение терминов auto->approved\n(безлюдный режим = осознанный риск G1/G2) HUMAN <.. EV_PILOT : BWS-оценка (пилот Ф2.5) LLM_RT --> OBS_LG OBS_LG --> OBS_QB LLM_AD --> OBS_TEL RUNNER --> OBS_TEL JOBS --> DB MEM_GLOS --> DB MEM_RS --> DB OBS_TEL --> DB OBS_LG --> DB EV_PILOT ..> OBS_TEL : golden-set реплей [Ф2] EV_RB ..> LLM_NSFW : калибровка роутинга note bottom of HUMAN Петля человека — несущая опора safety (все защиты кончаются флагом): ёмкость G2 меряется пилотом (D13), flag-rate/главу — первый замер. end note @enduml