textmachine/platform/docs/p9/door-live-probe.md

9.6 KiB
Raw Permalink Blame History

P9 — транскрипт живого пробоя двери правок банка (27.08.2026)

Требование §4.2 промта пака: дверь пробита ЖИВЫМ стендом против НАСТОЯЩЕГО движка. Ниже — команды и СЫРЫЕ фрагменты их вывода из сессии, дословно (норма «заявление = команда»; вторая редакция — первая была пересказом, что приёмка справедливо назвала).

Стенд

Демон и движок собраны из дерева сессии; свои порты/БД/каталоги, чужой стенд не тронут:

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=<repo>/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 «по-настоящему» ждёт живого ключа.