49 lines
7.6 KiB
Markdown
49 lines
7.6 KiB
Markdown
# §4.8 — ожидаемый исход КАЖДОГО дёрганья, ЗАПИСАННЫЙ ДО НЕГО
|
||
|
||
Все формы идут на $0-РУКЕ (заглушка на 11434, рендер пайплайна на провайдера `kind: local`).
|
||
Довод — §4.8 промта: дёрганье на измеряемом прогоне САМО производит число, которое потом
|
||
предъявляется как свойство движка (резюм и второй старт — ровно то, что меряет числитель-2 §4.3).
|
||
|
||
| # | Форма | Ожидание, написанное ДО |
|
||
|---|---|---|
|
||
| 1 | `GET /v0/capabilities` без сессии | **401** `unauthenticated`, и `export_formats` при этом НЕИЗВЕСТЕН, а не пуст |
|
||
| 2 | Заказ в ЗНАКАХ (`characters`) вместо глав | 202; `ordered_units` непусто ЛИБО `ordered_chapters` рассчитано из знаков — это ДРУГАЯ ветка контракта и другой счётчик |
|
||
| 3 | Повтор старта с тем же `Idempotency-Key` | тот же `id` прогона, БЕЗ второго прогона и без второго холда; счёт строк `runs` не растёт |
|
||
| 4 | Повтор старта БЕЗ ключа при идущем прогоне | отказ (409-класс): книга уже в работе |
|
||
| 5 | Старт на НЕСУЩЕСТВУЮЩЕЙ книге | 404, машинный `code`, `request_id` непустой |
|
||
| 6 | Курсор-мусор на страничном чтении | 400-класс с машинным `code`, НЕ 500 и НЕ тихий первый лист |
|
||
| 7 | Заказ выгрузки в НЕСМОНТИРОВАННОМ формате (`pdf`) | 400/422-класс: формат не из `export_formats` |
|
||
| 8 | Условное чтение: повтор `GET` с `If-None-Match` от прошлого ответа | **304**, тело пустое |
|
||
| 9 | Правка банка на НЕСУЩЕСТВУЮЩЕМ `src` | 200 с пустым `accepted` ЛИБО 4xx — но НИКОГДА не «применено» |
|
||
| 10 | Нехватка баланса: вторая учётка без гранта | отказ ДО спавна, `blocked` непусто в `run-options`, старт отказан |
|
||
| 11 | `POST /v0/runs/{id}/stop` на идущем прогоне | 202; НАМЕРЕНИЕ стопа в Postgres ДО сигнала (иначе стоп и авария — один и тот же выход) |
|
||
| 12 | Резюм ДВАЖДЫ подряд (идемпотентность резюма) | второй — отказ либо тот же attempt, НЕ третья попытка |
|
||
|
||
⚠ Что делает эту таблицу проверкой, а не экскурсией: любой ответ двери задним числом выглядит
|
||
правильным. Строки ниже дописываются ФАКТОМ после исполнения, и расхождение НАЗЫВАЕТСЯ.
|
||
|
||
## ИСХОД КАЖДОЙ ФОРМЫ (дописано ПОСЛЕ исполнения; ожидания выше не правлены)
|
||
|
||
| # | Форма | ФАКТ | Сошлось |
|
||
|---|---|---|---|
|
||
| 1 | `capabilities` без сессии | **401** `unauthenticated`; прибор напечатал «export_formats НЕИЗВЕСТЕН, не пуст» | ✅ |
|
||
| 1б | `capabilities` с сессией | 200, `export_formats: ["txt","epub"]`, `contract_version 0.15.0`, `bank_corrections_enabled: true` | ✅ обязательный пин ДО фриза |
|
||
| 2 | заказ в ЗНАКАХ (`characters: 300`) | **202**, `ordered_chapters: null`, **`ordered_units: 2`** — другая ветка, другой счётчик | ✅ |
|
||
| 3 | идемпотентность старта (один `Idempotency-Key` дважды) | тот же `id` прогона обоими ответами; строк `runs` у книги **+1, не +2**; `idempotency_keys` 1 строка | ✅ |
|
||
| 4 | второй старт при ИДУЩЕМ прогоне | **409 `run_in_flight`** | ✅ ⚠ с ОГОВОРКОЙ, см. ниже |
|
||
| 5 | старт на несуществующей книге | **404 `not_found`**, `request_id` непустой | ✅ |
|
||
| 6 | курсор-мусор | **расщеплено тремя пробами**: `cursor=not-a-real-cursor` → **400 `cursor_invalid`**; `cursor=%zz` → **200 и первая страница**; без курсора → тот же 200 | ⛔ частично: механизм жив, но битый процент-эскейп молча выбрасывается `r.URL.Query()` |
|
||
| 7 | выгрузка в несмонтированном формате | **400 `invalid_request`** + `{"pointer":"/format","code":"unknown"}` | ⚠ ожидание было 422 — **неверно было МОЁ ожидание**, дверь права и отвечает машинно |
|
||
| 8 | условное чтение `If-None-Match` | **304**, тело пустое | ✅ |
|
||
| 9 | правка банка на несуществующем `src` | **200**, `accepted[0].state: applied` в ПРЕВЬЮ | ⚠ дверь принимает правку термина, которого банк не предлагал; по коду это ДОБАВЛЕНИЕ, а не ошибка — но в ответе неотличимо от подтверждения предложенного |
|
||
| 10 | нехватка баланса ($0.05 при бонде $2.00) | **200** `verdict: covers_all`, `affordable_chapters: 4`, **`blocked: null`**, но `term_consistency_funded` перевернулся в `false` и холд упал 2 004 553 → **4 553**; старт **ПРИНЯТ, 202**; цена в обоих случаях ОДНА (`expected_micro_usd` 2324) | ⛔ находка, см. отчёт |
|
||
| 11 | стоп идущего прогона | **202**, `stop_requested: true`; через 15 с `runs.status=stopped`, `stop_requested_at` записан, **`exit_code = 5`** — стоп отличим от аварии | ✅ |
|
||
| 12 | резюм ТЕРМИНАЛЬНОГО прогона (дважды) | **409 `run_not_resumable`** оба раза; попыток по-прежнему 2 | ✅ |
|
||
| 12б | резюм ОСТАНОВЛЕННОГО, дважды подряд | первый **202**, второй **202** с тем же состоянием; `run_attempts` = **2, третья попытка НЕ создана** | ⚠ ожидание 409 было МОИМ приором; дверь идемпотентна ПО ЭФФЕКТУ, и это законно |
|
||
|
||
⛔ **ОГОВОРКА К СТРОКАМ 4 и 11, и она про МОЙ ПРИБОР, а не про дверь.** Первая попытка этих двух проб
|
||
дала «⛔ не как ожидалось»: второй старт вернул 202, стоп вернул 409. Разбор показал, что я спросила
|
||
ПОСЛЕ того, как прогон уже кончился — $0-заглушка проходит четырёхюнитную книгу за ~15 секунд, а между
|
||
моими вызовами было больше. Пере-снято залпом без пауз (три вызова за 0.27 с) — обе двери ответили
|
||
ровно как обещано. **Аномалия была о приборе, а не о предмете**, и если бы я её не пере-сняла, в отчёт
|
||
уехали бы две несуществующие находки.
|