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