# P9 — транскрипт живого пробоя двери правок банка (27.08.2026) Требование §4.2 промта пака: дверь пробита ЖИВЫМ стендом против НАСТОЯЩЕГО движка. Ниже — команды и СЫРЫЕ фрагменты их вывода из сессии, дословно (норма «заявление = команда»; вторая редакция — первая была пересказом, что приёмка справедливо назвала). ## Стенд Демон и движок собраны из дерева сессии; свои порты/БД/каталоги, чужой стенд не тронут: ```sh W=~/tm-p9-work cd backend && go build -o $W/tmctl ./cmd/tmctl cd platform && go build -o $W/tmplatformd ./cmd/tmplatformd && go build -o $W/tmplatformctl ./cmd/tmplatformctl ~/.local/pgsql/bin/psql -h 127.0.0.1 -p 5432 -U postgres -d postgres -c "create database tmp9stand" # env: TM_PLATFORM_DSN=…/tmp9stand · _MIGRATE=1 · _ADDR=127.0.0.1:8123 · _DEV_LOGIN=p9dev · # _INSECURE_COOKIES=1 · _BOOKS_DIR=$W/stand/books · _STATE_DIR=$W/stand/state · # _ENGINE_BIN=$W/tmctl · _BOOK_TEMPLATE=$W/book-template.yaml · _CTL_BIN=$W/tmplatformctl · # _LANGUAGE_PAIRS='zh>ru' · _METRICS_ADDR=off · _ENGINE_KEYS_PATH=/backend/.env nohup $W/tmplatformd > $W/stand/daemon.log 2>&1 & curl -s --noproxy '*' http://127.0.0.1:8123/readyz # → ready $W/tmplatformctl seed --url http://127.0.0.1:8123 ``` Вывод seed (дословно): ``` account u_QNMBL43CZVBE42IJ (identity dev/p9dev) credit granted 25.000000 to u_QNMBL43CZVBE42IJ (key seed-u_QNMBL43CZVBE42IJ); balance is 25.000000 book bk_QLS63SDD3NWF2YUV (parsing) intake not_started, 3 chapters ``` ## Почему провайдер — локальная $0-заглушка Первый прогон демо-книги упал классом 10; журнал юнита (дословно): ``` tmctl[823168]: tmctl: missing API keys (fill in backend/.env): tmctl[823168]: - provider deepseek: env DEEPSEEK_API_KEY is not set (needed for model deepseek-v4-flash) ``` Механика `--keys-file` при этом доказана двумя $0-пробами на КОПИИ книги (значения ключей в сессию не читались — гардрейл `.env` цел): ``` $ tmctl translate --config book.yaml --keys-file /nonexistent/keys.env --ceiling-usd 0.05 tmctl: --keys-file /nonexistent/keys.env cannot be read: open /nonexistent/keys.env: no such file or directory $ echo "DEEPSEEK_API_KEY=sk-dummy-p9-probe" > keys-dummy.env && tmctl translate … --keys-file keys-dummy.env … … msg="calling model" model=deepseek-v4-flash attempt=0 … # пре-флайт пройден, файл загружен ``` Пробы остальных провайдеров тем же способом (`--ceiling-usd 0.000001`: отказ резервации ДО вызова, `committed=$0.000000 reserved=$0.000000`, exit 10 = ключа нет): ``` gemini-3.1-pro-preview EXIT=10 :: … env GEMINI_API_KEY is not set … mistral-large-2512 EXIT=10 :: … env MISTRAL_API_KEY is not set … gpt-5-mini EXIT=10 :: … env OPENAI_API_KEY is not set … ``` Живого облачного ключа в файле деплоя нет ⇒ пробой цепи — на `provider: local` (models.yaml), которого на стенде обслуживает OpenAI-совместимая заглушка `$W/fake_provider.py` (переводчику — проза, терминологу/классификатору — TSV по строкам `key:`). Майнингу даны `langpack_root` (реальные langpacks движка) и фабрикованный jieba-контраст (76 частотных слов); книга — крафтовый исходник (方源 ×54, 苏长老, 青云山; 3 главы, 1222 байта). ## Цепь, команда за командой Загрузка и старт (сессия `curl -c jar` через `/auth/dev-login`, всюду `-H "X-TM-Client: p9"`): ``` $ curl … -F title="Проба P9" -F source_lang=zh -F target_lang=ru -F file=@probe-book.txt /v0/books "id": "bk_MNPEAQTOVKK5SMCI", "status": "parsing" … → not_started 3 $ curl … -d '{"stop_for_signing":true,"ceiling_chapters":3}' /v0/books/bk_MNPEAQTOVKK5SMCI/runs run_BMLFFO5TCESMXRW4 translating {'done': 0, 'total': 6, 'stage': 'drafting', 'eta_seconds': None} ``` Стоп достигнут (поллер карточки, дословно): `23:12:10 awaiting_bank 3 6 editing` — полоса на стопе 50%, НЕ обнулилась. Чтение банка на стопе: ``` $ curl … /v0/books/bk_MNPEAQTOVKK5SMCI/bank {"revision": 23, "next_cursor": null, "structure_version": 1, "total": 0, "signed": 0, "terms": []} ``` — ни `pending_decisions`, ни `complete` (PD-399 живьём); пустота банка на стопе — строка 224 (читающая сторона — движковый пак). Поверхности стопа — из карты подписи на сервере (`sample-zh.db.mined-signature.yaml`: `方源`, `苏长老`, …; `.bank-stop.txt`: «BANK VERIFICATION TABLE — 3 term(s)»). ПРЕВЬЮ (approve 方源 → «Фан Юань-П9» kind name + decline 苏长老), ответ дословно: ``` {"preview": true, "changed": true, "depth": "refinement", "accepted": [ {"index": 0, "action": "approve", "id": "e1e2b5625d031d33", "src": "方源", "dst": "Фан Юань-П9", "state": "applied", "displaced": false}, {"index": 1, "action": "decline", "id": "bf4a082f8bf17aed", "src": "苏长老", "dst": null, "state": "applied", "displaced": false}], "preexisting_faults": 0, "signature": {"surfaces": 3, "undecided": 1, "unreadable": false}} ``` ПРАВКА и ПОВТОР того же документа (вывод скрипта сверки, дословно): ``` == APPLY == preview False changed True accepted [('方源', 'applied', False), ('苏长老', 'applied', False)] signature {'surfaces': 3, 'undecided': 1, 'unreadable': False} == RETRY SAME == changed False states ['already_applied', 'already_applied'] ``` ОТКАЗ (противоречие в одном документе: decline 方源 + approve 方源): ``` code bank_corrections_refused refusals [('/corrections/1', 'decision 0 already decides this term (sense "", window [0,0]')] HTTP=409 ``` RESUME и правка при живом прогоне (второй замер — на живом прогоне демо-книги, тело дословно): ``` $ curl … /v0/runs/run_BMLFFO5TCESMXRW4/resume translating {'done': 3, 'total': 6, 'stage': 'editing', 'eta_seconds': 1} # полоса ПРОДОЛЖИЛА с 3/6 $ curl … -d @corr-apply.json /v0/books/…/bank/corrections # прогон живой {"type":"about:blank","title":"Run in flight","status":409,"code":"run_in_flight","request_id":"5M6SCTCU4XYQP5P2"} ``` Финал (поллер + чтение банка, дословно): ``` 23:14:04 ready 6 6 editing $ curl … /v0/books/bk_MNPEAQTOVKK5SMCI/bank {"revision": 34, …, "total": 2, "signed": 1, "terms": [ {"id": "tm_73f73a5b396d7d40b68bac09", "src": "方源", "dst": "Фан Юань-П9", "kind": "name", "status": "approved", …}, {"id": "tm_9e446a871eb17f39eade265c", "src": "青云山", "dst": "", "kind": "place", "status": "proposed", "since_chapter": 1, …}]} ``` Следующий прогон правку УВИДЕЛ: `方源` — approved с моим dst; задеклайненный `苏长老` из предложений исчез; нерешённый `青云山` стоит proposed. ## Деньги (ось §5.1 — леджер двумя путями) ``` $ $W/tmplatformctl balance --user u_QNMBL43CZVBE42IJ balance 25.000000 $ psql … -d tmp9stand -c "select kind, count(*), sum(amount_micro_usd) from credit_ledger group by kind order by kind" grant | 1 | 25000000 hold | 3 | -270000 hold_release | 3 | 270000 settlement | 3 | 0 ``` Сошлось до цента. Три холда = три попытки (демо-книга exit 10; пробная книга, попытки 1 и 2 через resume); расчёты $0 — заглушка. Оговорка силы замера: расчёты нулевые, открытого холда в момент сверки не было; сверку на открытом холде и после ненулевого расчёта исполнил ревьюер приёмки на этом же дереве — расхождений нет. ## Что пробой доказал Цепь строк 199/202 срослась: правка термина через контрактную дверь доезжает до движковых файлов решений, возобновление пере-собирает банк с ней, читающая поверхность следующей границы её показывает. Плюс живьём: сквозная полоса через обе волны без обнуления на стопе; PD-399 не на проводе; превью/идемпотентность/отказ/взаимоисключение — по канону 0.5.0. Ограничение честно: качество перевода и поведение под латентностью настоящего провайдера пробой НЕ доказывает — заглушка, строка 202 «по-настоящему» ждёт живого ключа.