Point the money-stop mutation at the guard the stop work reshaped, so the catalogue plants where it claims to.

This commit is contained in:
heaven 2026-09-11 02:04:43 +03:00
parent dbaa7d468d
commit f8a968e37b
2 changed files with 22 additions and 2 deletions

View file

@ -3930,7 +3930,7 @@
"edits": [
{
"file": "internal/pipeline/stagerun.go",
"find": "\t\tif ctx.Err() != nil {\n\t\t\tr.setJobStatus(ctx, job.ID, \"failed\")\n\t\t\treturn att, fmt.Errorf(\"pipeline: reserve $%.6f for %s/ch%d/chunk%d/%s: the run ended before the reservation was granted: %w\",\n\t\t\t\testimate, r.Book.BookID, ch.Chapter, ch.ChunkIdx, st.Name, ctx.Err())\n\t\t}\n",
"find": "\t\tif ctx.Err() != nil {\n\t\t\t// Same as the aborted wait above, and through the SAME contract: nothing was called and nothing\n\t\t\t// broke, so a cancelled run leaves this position resumable rather than recording it as a failure\n\t\t\t// (backlog row 389). It is ROUTED rather than simply omitted so the family can be counted: every\n\t\t\t// site that might write the word goes through one function, and a reader enumerating them finds\n\t\t\t// no exceptions to explain.\n\t\t\tr.noteJobFailed(ctx, job.ID, ctx.Err())\n\t\t\treturn att, fmt.Errorf(\"pipeline: reserve $%.6f for %s/ch%d/chunk%d/%s: the run ended before the reservation was granted: %w\",\n\t\t\t\testimate, r.Book.BookID, ch.Chapter, ch.ChunkIdx, st.Name, ctx.Err())\n\t\t}\n",
"replace": ""
}
]

View file

@ -381,7 +381,27 @@ commit survived SIGKILL and the ledger matches»;
`python3 docs/scripts/counts.py --check` → «Литералы сходятся с пере-счётом (8 проверок)», exit 0.
**Мутационный прогон:** `make mutations` идёт; число и состав впишу сюда же по окончании. В каталог
**Мутационный прогон:** `make mutations`**RED 151 · SURVIVED 0 · ROTTED 1**, `MAKE-EXIT=2`.
**Ноль переживших — и одна ПРОТУХШАЯ запись, и она моя.** `CUTCEILING-a-cancelled-run-reports-a-money-stop`
сажается удалением охранника `if ctx.Err() != nil {…}` в `stagerun.go` — того самого блока, который эта
доработка переписала, — и её якорь перестал совпадать («the anchor occurs 0 times … it must occur exactly
once»). **Три СВОИ записи я перед запуском сверила с деревом, а чужую, которую сломала своей же правкой,
— нет: знаменатель взяла из своих правок, а не из каталога.**
⭐ Прибор при этом сработал: `tmmutate` не зачёл это за успех, а назвал `rotted` и завалил гейт. Класс
«уехавший якорь молча разоружает проверку» закрыт в мутациях по построению (сверяется ЧИСЛО вхождений,
требуется ровно одно); он остаётся открытым там, где такого счётчика нет.
**Прогон при этом ПОЛНЫЙ, а не оборванный** — инструмент дошёл до конца и сам это печатает:
«**152 mutation(s) run, 1 unexpected outcome(s)**», «anchors swept: 1 of 363 entr(ies) rotten».
То есть покрытие снято по всему батарейному подмножеству, а единственный неожиданный исход — протухший
якорь, а не переживший мутант.
Починка: якорь пере-наведён на текущее тело блока (извлечён из файла ПРОГРАММНО, не перепечатан руками),
и четыре записи пере-проверены на СВЕЖЕЙ копии, защищённой построением (`test -f go.mod` + свой tmp + trap,
копия без `.env`): `RED × 4 · 0 unexpected · anchors swept: **0** of 363 entr(ies) rotten`.
**ЧЕГО НЕТ: подтверждающего сплошного перепрогона «152 RED одной строкой».** Он запускался ДВАЖДЫ и оба
раза убит сторожем памяти среды — на шестой и на пятой посадке, при том что сама машина показывала ~8,7 ГБ
свободных. Третьей попытки не делала: под окном лежат чужие сессии, а прогон косметический — он превратил
бы «151 RED + 1 протухшая, починенная и пере-проверенная отдельно» в «152 RED», не добавив ни одной новой
проверки. Названо здесь, а не выдано за зелёный гейт. В каталог
добавлены ТРИ записи под новые гарантии (`STOP-cut-does-not-blind-an-earlier-verdict` ·
`STOP-a-cut-by-a-person-is-not-a-failed-job` · `STOP-the-spend-line-closure-cannot-reach-the-emitter`),
все три в батарейном подмножестве; каталог 360 → 363, подмножество 149 → 152. ⚠ Одна из трёх после