docs(ночь): кусок 6 задача 10 — договор о стыках: блок после куска 6 по факту построенного, с честным списком того, чего ещё нет

This commit is contained in:
Дмитрий
2026-08-03 04:19:31 +03:00
parent f9a7b2f93d
commit b7df32dac0
@@ -430,6 +430,7 @@
| `SERVICE_WAIT_LIMIT_HOURS` | — (постоянная) | `2` — порог «служба не ответила», названный числом, а не спрятанный в коде | 1 |
| `serviceWaitHit(spans, hours)` | отрезки времени и порог | `{ extinguish, reason, waited_ms }`. 🔴 **Правило: два часа ПОДРЯД, а не сумма за ночь.** Считается по **последнему** отрезку списка (учётчик кладёт идущий сейчас последним) и только если он вида `waiting_service`. Работник, ждавший службу по десять минут восемь раз за ночь, не «прождал два часа»: он восемь раз получил ответ, и гасить его — неправда. Причина в ответе — дословно из бумаги: «служба не ответила». Заведена правкой куска 1: до неё **первой половины проверки 13 — самого гашения — не умел никто**, правило зеленело на проверках и не срабатывало ни разу | 1 (проверка 13) |
| `morningCutoff(worker, now)` | `{ status, runStartedAt }` и время | `{ extinguish, reason }` | 5 (проверки 32, 33) / кусок 1 (проверки 31, 34, 35) |
| 🆕 `resumeChecks({ seal, budget, disk })` | три ответа | `{ ok, counts_as_new_run, reason, summary_line }`; список ворот кнопки «продолжить» **закрыт** — только эти три, и девять ворот обычного запуска к ней не применяются вовсе. 🔴 **Порядок причин — не украшение: отпечаток → место → запас**; плохи двое или трое — названа первая по порядку (владелец читает ОДНУ строку и по ней решает, что чинить). 🔴 Годны только настоящие `true`/`false`: всё прочее (в том числе «не мерили») считается за **«нельзя»**, потому что строка «нет» в проверке на истинность прошла бы за разрешение. При `ok` прямо сказано словами, что это считается **новым прогоном**: восемь часов заново, запас тратится дальше | 6 (проверки 6, 7, 8, 9) |
| `checkSelfLimits({ billable_ms, hours_limit, budget, disk, worker, now, current_item })` | всё | `{ extinguish, wake_owner, reason, at_item }` | 2 (проверка 14) |
| `resumeChecks({ seal, budget, disk })` | три ответа | `{ ok, counts_as_new_run, reason, summary_line }`; список ворот **закрыт** — только эти три | 6 (проверки 6–10) |
@@ -624,7 +625,10 @@
|---|---|---|
| `resumePlan({ status, last_closed_item, work_after, paused_at_item })` | как кончил работник | `{ auto_resume, start_from, rollback, kept_aside, reason }`; `paused` откат **не** касается; без единого закрытого пункта `auto_resume: false` |
| 🆕 `statePath(workspaceRoot)` | **угол работника** (не каталог прогона!) | `<угол>/.night-worker/state.json`**единственная** дорога к состоянию. Заведена 01.08 вместо `memoryStatePath` куска 5 (раздел 5, п. 2) |
| 🆕 `resumePoint(workspaceRoot, { last_closed_item, known_items })` | **угол работника** и что известно | `{ from: 'state_file' \| 'last_closed_item', item, answers, assumption_spans, note }`; файла нет или порван`from: 'last_closed_item'`. **Сбой отличим от чистоты:** «файла нет» и «файл не читается» — разные вещи, второе идёт в сводку |
| 🆕 `resumePoint(workspaceRoot, { last_closed_item, known_items })` | **угол работника** и что известно | `{ from: 'state_file' \| 'last_closed_item', item, answers, assumption_spans, note, sboy }`; файла нет, порван **или неполон**`from: 'last_closed_item'`. **Сбой отличим от чистоты:** «файла нет» и «файл не читается» — разные вещи, второе идёт в сводку |
| 🆕 `rabotaPosleZachtennogo({ worktreeRoot, commit_sha, run })` | угол и коммит засчитанного пункта | `{ commits, files }` — что наработано **после** засчитанного пункта, **или `null`, если хранилище не ответило**. 🔴 `null`, а не пустой список: пустой означал бы «после пункта ничего не делали», и откат молча решил бы, что откатывать нечего, ровно в ту ночь, когда `git` упал |
| 🆕 `sledOtkata({ worktreeRoot, commit_sha, otkat, run })` | угол, коммит засчитанного пункта и **сам откатчик доводом** | `{ ok, reason, rollback_commit, otlozheno }` — обёртка вокруг общего `otkatDoKommita` куска 5. В ней остаётся то, чего у него нет: 🔴 «откатывать нечего» меряется **совпадением ДЕРЕВА** угла с деревом коммита пункта (по коммитам сверху мерить нельзя — там уже лежит сам коммит отката), грязный угол отката не получает, и 🔴 **успех откатчика проверяется появлением нового коммита** — на слово ему не верят |
| 🆕 `PRODOLZHAEMYE` | — (постоянная) | `['stalled', 'extinguished']` — список продолжаемых **закрыт**; `paused` и пять живых слов работника в него не входят |
🔴🔴 **ДВА РАЗНЫХ «КАТАЛОГА РАБОТНИКА» — не перепутать, это ловушка, на которой уже
споткнулись 01.08:**
@@ -701,7 +705,8 @@
| имя | принимает | отдаёт |
|---|---|---|
| `STOP_AND_ASK` | — | **семь** поводов остановиться и спросить владельца (дословный список в разделе 3) |
| `buildWorkerPrompt({ workerId, runId, planPath, item, branch, otherWorkersFiles, testCommand })` | всё про пункт | текст поручения по-русски; пункт без проверок — бросает ошибку |
| `buildWorkerPrompt({ workerId, runId, planPath, item, branch, otherWorkersFiles, testCommand, 🆕 resumeFrom, 🆕 assumptionLenta })` | всё про пункт | текст поручения по-русски; пункт без проверок — бросает ошибку. 🆕 Два **необязательных** довода куска 6: `resumeFrom` — ответ `resumePoint`, `assumptionLenta` — строки ленты `assumptions.jsonl` куска 5. Не поданы — текст прежний слово в слово |
| 🆕 `sverkaPometok({ pometki, otrezki })` | пометки «в расчёте на ответ» из записи работника и лента надзирателя | `{ zhivye, otkachennye, sverit_ne_s_chem, summary_line }`. 🔴 Находка СВ-13: надзиратель мог часть работы **откатить**, пока работник лежал; выдай откаченную пометку живой — и продолжающий построит следующий шаг на работе, которой в ветке уже нет. 🪤 Три случая не сводятся: ленты **нет** (`null`) — все живые + строка владельцу; лента **пуста** (`[]`) — сверка состоялась, тревоги нет; пометки нет в ленте — считается **живой** (неизвестность в безопасную сторону). Откаченным считается только **закрытый** отрезок с итогом отката |
| `buildSmokePrompt({ minutes, notesPath, branch })` | пробный прогон | короткий безобидный текст поручения |
### `run.mjs` — кусок 1 (точка входа), дописывают все
@@ -1132,12 +1137,66 @@ Windows (его заводит кусок 2 — до тех пор письмо
### После куска 6
Добавилось: продолжение вставшего с последнего закрытого пункта (`resumePlan`); кнопка
«продолжить» с **закрытым** списком из трёх ворот (`resumeChecks`); `cli.mjs run --resume`,
не берущий закрытые пункты заново; правило «пауза откатом не карается».
🔴 **Записано 03.08.2026 ПО ФАКТУ ПОСТРОЕННОГО, а не по плану.** Планы кусков 1–4 этот блок
не заполнили вовсе, и бумага отстала на четыре куска сразу; чтобы не повторять, здесь прямо
разделено: что **есть в коде** и что **ещё нет**. Пишущий куска 7 обязан читать оба списка.
Пишущий куска 7 **не заводит заново**: `resume.mjs`, `resumeChecks`, поведение `--resume`
в точке входа.
**Есть в коде (построено и под проверками):**
- дорога к состоянию работника — `statePath` (единственное место, где имя `state.json`
склеивается с каталогом) и `resumePoint`: запись — **подсказка, а не доказательство**.
Годной считается только запись со **всеми четырьмя** полями (`item`, `answers`,
`assumption_spans`, `saved_at`); недописанная, порванная, пустая, не-объект и запись
с пунктом не из плана — все ведут к продолжению **с последнего засчитанного пункта**,
и «файла нет» отличимо от «файл сломан» полем `sboy`;
- приговор о продолжении `resumePlan`: сбой хранилища (`work_after === null`) отказывает
**в самом правиле**, отметка паузы откат **не назначает**, без единого засчитанного пункта
`auto_resume: false` и наработки перечислены как **отложенные**;
- `rabotaPosleZachtennogo` и `sledOtkata` — что наработано после засчитанного пункта и след
отката: мерка деревом, грязный угол отката не получает, успех откатчика проверяется
**появлением нового коммита**;
- трое ворот кнопки «продолжить» — `resumeChecks` в `limits.mjs`, список закрыт,
порядок причин отпечаток → место → запас; внутри `checkSelfLimits` не переставлено ничего;
- блок про память в тексте поручения: дословные якоря «перед концом памяти» и «перечитай»,
имя `state.json` и имя ящика `.night-worker`, у продолжающего — «продолжаешь с пункта N»
цифрой (это **первый незасчитанный** пункт, а пункт записи идёт **справкой**), запомненные
ответы владельца по строке на ответ с номером вопроса, и `sverkaPometok` — откаченное
не выдаётся за живое.
**Ещё НЕТ — и это названо честно, а не пропущено:**
- 🔴 **задачи 7 нет вовсе: `cli.mjs run --resume` и `zavestiProdolzhenie` в `run.mjs`
не построены.** Следствие, которое обязан знать пишущий куска 7: **ни одно правило куска 6
в живой ночи никто не зовёт.** Замерено 03.08.2026 счётом зовов вне своих файлов
и вне проверок: `resumePoint` — 0, `resumePlan` — 0, `rabotaPosleZachtennogo` — 0,
`sledOtkata` — 0, `resumeChecks` — 0. Правила построены, проверены и **не подключены**;
подключает их задача 7. Пока её нет, продолжение как работа владельцу недоступно;
- задачи 6 нет: `vyborProdolzhaemogo` и поля `resumeRunId` / `resumeWorkerId`
в `razborDovodov` (`cli-parts.mjs`) не заведены;
- задачи 9а нет: правила `zabytayaPauzaHit` (решение владельца 127 — забытая пауза гаснет
через сутки), блока **6б** круга надзирателя и настройки `forgotten_pause_hours`
в коде **нет**. Порядок блоков в круге, о котором договорились, — **6 → 6а → 6б**,
где `6а` занял кусок 7 (конец задачи), а `6б` — куска 6; чужие блоки не перенумеровываются;
- у `sledOtkata` откатчик приезжает **доводом**, потому что общий `otkatDoKommita` куска 5
в `supervisor.mjs` ещё **не вывезен наружу**. Связывает их задача 7.
**Решения владельца 125–127, принятые 01.08:** 125 — об отказе кнопки «продолжить» владелец
узнаёт **из окна**, отдельного письма не строим (закрыл вопрос В-10); 126 — уборка углов
**не трогает** углы вставших и погашенных, пока владелец не решит их судьбу (закрыл В-8;
🔴 сама правка уборки — в чужом куске 1, не сделана, долг); 127 — забытая пауза гасится
через сутки **от минуты постановки на паузу** (закрыл В-3; 🔴 работа не сделана, см. выше).
**Клетка `vhodVorot` за куском 6 снята:** кнопка «продолжить» через `planRun` не ходит вовсе,
и ни одним доводом раскладку ответов по кормушкам ворот кусок 6 не трогает.
Пишущий куска 7 **не заводит заново**: `resume.mjs`, `resumeChecks`, `sverkaPometok`
и поведение `--resume` в точке входа.
🪤 **Долги, найденные куском 6 в чужом коде** (сам не правил): `supervisor.mjs` **вторым
местом** склеивает путь к `state.json` и читает запись двухответным `readJson` — порванная
запись там молча считается отсутствующей; у двух сторожей (`zhivoy-zapusk-v-proverkah`
и `nastoyashchee-hozyaystvo-v-proverkah`) заведены **одноимённые** списки `KOMU_MOZHNO`,
и следующая смена почти наверняка примет один за другой.
### После куска 7