WEB-325 · Задача · — · web
Движок Gate E: mutating AI — AI-фичи пишут в документ через движок
Закрыт
P2
ведёт: —
Суть
## Суть
Движок Gate E: mutating AI — AI-фичи (Fix/Shorter/Simplify) пишут в документ через gated-writer движка (не мимо), флаг тёмный до лестницы C→D→E, защита от двойной операции и kill-switch fail-closed.
## Где мы сейчас (13.09.2026)
Прод = l115j (133fe00c). Gate E построен 25.08 (6d84d7f), посажен тёмным (посадка 50, v4-fd5e1b7); приёмка ACCGATEE9 GO 28.08 (защита от двойной операции). Видимость флага починена (70b162ab, l67). Флаги на проде ВКЛЮЧЕНЫ: NEXT_PUBLIC_DOCUMENT_SESSION_GATED_WRITER=1 и NEXT_PUBLIC_DOCUMENT_SESSION_MUTATING_AI=1 (run-env l115g, 12.09; feature-toggles mutatingAi=true, gatedWriter=true). Рецепт включения принят (волна 3579 GO). Осталось: браузерная приёмка глазами (волна 3645 в полёте) и решение по WEB-428 (реальная модель не в MODEL_ALLOWLIST).
## Хронология
- 25.08: Gate E построен (6d84d7f), посажен тёмным; GATE_E_DONE.
- 28.08: ACCGATEE4 NO-GO → … → ACCGATEE9 GO (защита от двойной операции).
- 29.08: видимость флага починена (70b162ab, l67); AI-правка → 500 (gpt-4o-mini не в MODEL_ALLOWLIST) → WEB-428.
- 12.09: wash 3337 — функция не включалась; владелец 22:27Z «можете включать»; волна 3579 GO (рецепт включения, 7 проверок).
- 12.09 22:59Z: координатор — Gate E УЖЕ включён на l115g; остаток = браузерная приёмка шагом 7.
- 13.09 09:57Z: волна 3645 (A2) делает браузерную приёмку на артефакте l115j (заглушка стенда, не платный провайдер).
## Карта документов и кода
- src/lib/document-session/mutating-ai.ts — флаг/kill-switch.
- src/lib/document-session/gated-writer.ts — gated writer (ai-insert/ai-replace).
- src/lib/document-session/ai-operation-ledger.ts — защита от двойной операции (IndexedDB).
- src/components/modals/EditorModal.tsx — маршрутизация AI-правки.
- Отчёт рецепта: shift-20260912-resume/colA/3579GATEEREADINESS-REPORT.md.
## Остаток
1. Браузерная приёмка Gate E — волна 3645 в полёте (A2, артефакт l115j): панель AI Tools видна, текст заменяется ровно один раз, дубля нет, kill-switch fail-closed. До её GO карточку не закрывать.
2. WEB-428 — реальная модель (gpt-4o-mini) не в MODEL_ALLOWLIST; 3645 использует заглушку стенда, поэтому «работает на реальном провайдере» остаётся блокированным allowlist-ом. Ответственный: координатор/отдельная волна.
## Критерий закрытия
Браузерная приёмка (волна 3645) GO по чек-листу из 7 шагов; отдельно зафиксировано, что на больших документах в Hybrid-режиме флаг не действует (не дефект Gate E); решение по WEB-428 (allowlist) записано.
---
## История (старое тело)
## Суть
Движок Gate E: mutating AI — AI-фичи пишут в документ через gated-writer движка (не мимо), флаг тёмный до лестницы C→D→E, защита от двойной операции и kill-switch fail-closed.
## Где мы на 12.09
Gate E построен 25.08 (6d84d7f), посажен тёмным (посадка 50, v4-fd5e1b7). 28.08 ACCGATEE9 GO (защита от двойной операции). 29.08 видимость флага починена (70b162ab, l67); AI-правка падает на POST /api/completion 500 — gpt-4o-mini не в MODEL_ALLOWLIST → WEB-428. Флаг держим выключенным.
## Остаток
1. «Работает» блокировано WEB-428 (gpt-4o-mini не в MODEL_ALLOWLIST).
2. Включение флага — только после лестницы C→D→E.
## Кто/что дальше
WEB-428 (allowlist) → после лестницы C→D→E включить флаг. Карточка в backlog (паркуется).
## История
- 25.08: Gate E построен (6d84d7f), посажен тёмным.
- 28.08: ACCGATEE4 NO-GO → … → ACCGATEE9 GO (защита от двойной операции).
- 29.08: видимость флага починена (70b162ab, l67); AI-правка → 500 (gpt-4o-mini) → WEB-428.
- 10.09: wash 3337 — функция не включается, статус backlog сохранён.
---
## история (тело до 13.09.2026)
## Суть
Движок Gate E: mutating AI — AI-фичи пишут в документ через gated-writer движка (не мимо), флаг тёмный до лестницы C→D→E, защита от двойной операции и kill-switch fail-closed.
## Где мы на 12.09
Gate E построен 25.08 (6d84d7f), посажен тёмным (посадка 50, v4-fd5e1b7). 28.08 ACCGATEE9 GO (защита от двойной операции). 29.08 видимость флага починена (70b162ab, l67); AI-правка падает на POST /api/completion 500 — gpt-4o-mini не в MODEL_ALLOWLIST → WEB-428. Флаг держим выключенным.
## Остаток
1. «Работает» блокировано WEB-428 (gpt-4o-mini не в MODEL_ALLOWLIST).
2. Включение флага — только после лестницы C→D→E.
## Кто/что дальше
WEB-428 (allowlist) → после лестницы C→D→E включить флаг. Карточка в backlog (паркуется).
## История
- 25.08: Gate E построен (6d84d7f), посажен тёмным.
- 28.08: ACCGATEE4 NO-GO → … → ACCGATEE9 GO (защита от двойной операции).
- 29.08: видимость флага починена (70b162ab, l67); AI-правка → 500 (gpt-4o-mini) → WEB-428.
- 10.09: wash 3337 — функция не включается, статус backlog сохранён.
Доказательства
[2026-08-25 ~13:00] Gate E (mutating AI) — предпосылка ВЫПОЛНЕНА: Gate D controlled writer приземлён тёмным в проде (посадка 49, v4-70ab8c1, см. WEB-324). Код writer'а движка теперь существует в линии → Gate E можно СТРОИТЬ (AI-фичи пишут в документ через этот writer). Зависимость: СТРОЙКА E — сейчас; ВКЛЮЧЕНИЕ E (флаг) — только после вердикта телеметрии Gate C (архив 19153+ записей на Pi) И флипа Gate D. Пуск волны E — в первый свободный слот A1/M4 (сейчас: A1=R9.18 фикс аудита ролей, M4=r28 фактчек). Родня: [[WEB-324]] Gate D, [[WEB-326]] Gate F, [[WEB-283]] эпик, [[WEB-347]]/[[WEB-354]] телеметрия.
[2026-08-25 ~13:20] Gate E СТРОЙКА ЗАПУЩЕНА (owner: «на A1 поместится всё, E и F в параллель»): волна на A1 (Luna xhigh), worktree /home/ubuntu/waves/wt-gate-e (ветка gate-e от l48-salvage 70ab8c1 = Gate D+WEB-352, node_modules симлинк). Флаг NEXT_PUBLIC_DOCUMENT_SESSION_MUTATING_AI тёмный. Фаза 1: AI-правки текста через gated-writer движка, error-boundary+откат на легаси, kill-switch, телеметрия producer=engine op=ai-mutation, 311-сюита неприкосновенна, только tsc+node --test (без webpack — не сталкивать с R9.18). Маркер GATE_E_DONE/BLOCKED. Параллельно на A1: R9.18 (роли) + Gate F. Диск почищен 90%→86%.
[2026-08-25 ~13:50] GATE_E_DONE (W1, commit 6d84d7f, ветка gate-e). Дизайн: флаг NEXT_PUBLIC_DOCUMENT_SESSION_MUTATING_AI тёмный (next.config.ts), mutating-ai.ts с Gate-D-style kill-switch (fail-closed), gated-writer.ts расширен сценариями ai-insert/ai-replace (движок коммитит первым, легаси тень), error-boundary+откат на легаси+safety-beacon при сбое, телеметрия producer=engine opKind=ai-mutation с primarySafety-счётчиками. EditorModal маршрутизирует фазу-1 AI-вставку/замену через boundary при Gate E ON; OFF = легаси без изменений. ПРУФ: замороженная 311-сюита 311/311 rc=0, mutating-ai+gated-writer тесты 17/17, tsc core/web248/web311 rc=0, git diff --check rc=0, контракт V2.1.2 не тронут. Флаг в сборку не включён (тёмный). Родня: [[WEB-324]] Gate D, [[WEB-326]] Gate F. → поедет в прод посадкой 50 тёмным вместе с Gate F.
[2026-08-25 ~16:50] Gate E (mutating AI) В ПРОДЕ ТЁМНЫМ — посадка 50 (v4-fd5e1b7). Флаг NEXT_PUBLIC_DOCUMENT_SESSION_MUTATING_AI OFF, код в линии. Включение по лестнице C→D→E. Родня [[WEB-324]] [[WEB-326]].
[2026-08-28 ~01:05Z ступень E — третий круг, каждый глубже предыдущего]
gatee4 закрыл прежние блокеры с цифрами: E 23/23, сводный 85/85 против 77/77, набор гейта D зелёный, Orb 291/291.
ПРИЁМКА ACCGATEE4 — NO-GO, три новых блокера: (1) интерфейс E и писатель E расходятся на СТРУКТУРНЫХ границах — валидная вставка во второй абзац получает `ai-invalid-request`; модель невидимых символов ВСЁ ЕЩЁ не одна (третий круг по одной болезни); (2) durable-леджер не даёт «не более одного раза» при ОДНОВРЕМЕННЫХ независимых процессах; (3) Orb после рестарта не сохраняет идентификатор операции и в воспроизведении применяет логический повтор (`hello!` -> `hello!!`).
Запущена gatee5: свести обе стороны к ОДНОЙ модели координат и ОДНОЙ модели невидимых символов через существующий `legacyHtmlWhitespace.ts` (не писать вторую), доказать вставками во все структурные позиции; сделать леджер атомарным (уникальный ключ + условная вставка) и доказать гонкой процессов; сохранить идентификатор через рестарт.
ПОДТВЕРЖДЕНО ПРИЁМЩИКОМ И ЗАФИКСИРОВАНО: даже при будущем GO это НЕ разрешение включать ступень — впереди обязательная браузерная приёмка (шаг 5 плана разведки).
ОБЩИЙ КЛАСС, вскрытый ТРЕМЯ приёмками в РАЗНЫХ линиях за ночь 28.08: защита живёт в памяти процесса либо верит файлу вместо живой проверки. Проявления: движок — леджер не даёт «не более одного раза» при одновременных процессах, а идентификатор операции теряется после рестарта (в воспроизведении текст удваивается: `hello!` -> `hello!!`); внутренний вызов — защита от переигровки в памяти, тот же валидный proof принят новым процессом; тумблер — маршрут принимается по локальным файлам готовности/исхода, мёртвая или подменённая цель принята как активная.
ТРИ ВОПРОСА к любой новой защите (внесены в брифы доделок, чтобы закрывать сразу, а не третьим кругом): переживает ли рестарт; держит ли одновременность (атомарно, а не «проверил, потом записал»); жива ли цель НА САМОМ ДЕЛЕ (проверять напрямую, а не по артефакту). Записано в память: guards-must-survive-process-boundary.
---
## 2026-08-29 00:45Z — эволюция видимости ступени E (для нулевого агента)
1. Код Gate E давно в сборке ship-dark: build-флаг NEXT_PUBLIC_DOCUMENT_SESSION_MUTATING_AI — первый гейт (src/lib/document-session/mutating-ai.ts L4-24: имя env собирается динамически НАРОЧНО, чтобы литерал не светился в client chunks); localStorage-ключ document-session-mutating-ai-kill-switch только ГАСИТ (значения 0/false/off), «1» НЕ включает. Урок EVISUAL2 28.08: на проде с выключенным флагом посмотреть E глазами НЕВОЗМОЖНО.
2. Решение owner 28.08 20:54Z: включить флаг прямо в сборку l66 (=1 в env шага next build).
3. Посадка l66 (21:27Z): проба L66PROBE — элементы UI видны, но buildEnabled=false ПРИ флаге в сборке. Корень: EditorModal.tsx:889 читает process.env[KEY] ВЫЧИСЛЯЕМО → DefinePlugin не инлайнит (в браузере process нет); сосед-Gate D строка 812 читает статически и работает. Класс «флаг объявлен, но не действует».
4. Починка L66FIX2-семьи: L66FIX3 коммит 70b162ab (wt-l66fix3, база l66 eb577cd1) — статическое чтение; на приёмке ACCL66FIX3 (A1 queue/337): греп на отсутствие вычисляемых чтений, обе стороны юнитами, гаситель не сломан. GO → едет в l67, после посадки E смотреть глазами (владелец ждёт).
Доки: memory e-stage-cannot-be-enabled-by-localstorage; отчёты M4 ~/L66PROBE-REPORT.md, A1 /home/ubuntu/waves/L66FIX3-REPORT.md; хендофф §3 урок 3 в OPS-STATUS-LIVE.md.
---
## 2026-08-29 00:55Z — ACCL66FIX3: GO. Видимость E-флага починена
Приёмка /home/ubuntu/waves/ACCL66FIX3-REPORT.md (GO): чтение флага стало статическим (литерал process.env.NEXT_PUBLIC_DOCUMENT_SESSION_MUTATING_AI), вычисляемых process.env[KEY] для флага в client-коде не осталось, обе стороны (=1/=0) юнитами, аварийный localStorage-гаситель цел. Коммит 70b162ab. → едет в l67; после посадки E видна глазами. WEB-325 остаётся в работе до посадки+визуальной проверки.
---
## 2026-08-29 07:45Z — ⭐ СТУПЕНЬ E ВИДНА НА ПРОДЕ (цель owner-а достигнута в части видимости)
Проба L67PROBE на живом проде l67 под QA-учёткой: buildEnabled=TRUE, kill-switch не взведён, элементы AI TOOLS / Polish / Verify активны и видны. То есть починка статического чтения флага (70b162ab) сработала — прошлый провал «флаг в сборке, а в браузере выключено» закрыт.
НО работой ступень не подтверждена: AI-правка падает раньше — POST /api/completion → 500 с пустым телом. Корень найден координатором по логам прода: канал editor_completion просит модель gpt-4o-mini, которой нет в MODEL_ALLOWLIST → денежный страж отбивает (billing_guard_model_not_allowed). Заведено WEB-428, волна заряжена.
Итог по тикету: гейт E открыт и виден; для «работает» нужен WEB-428.
Связи
- связан (обратная) → WEB-324 — Движок Gate D: controlled writer — движок владеет записью в ограниченных сценариях (NO-GO до закрытия WEB-323 + owner-одобрение) · ступень лестницы движка
Лента
2026-09-08T02:28:18.717Z · coordinator[08.09 02:28Z координатор] СРОЧНО: ПОТЕРЯ ТЕКСТА ПОЛЬЗОВАТЕЛЯ ЧЕРЕЗ ПУТЬ СПАСЕНИЯ РАБОТЫ.
Найдено волной 2698 при анализе потолка больших документов. Отчёт ENGINEW4-ANALYSIS-REPORT.md, первая строка URGENT_FINDING=RESCUE_DOWNLOAD_CAN_EXPORT_STALE_OR_EMPTY_TEXT.
Сценарий: пользователь работает с большим документом, сохранение отказывает по потолку, пользователь жмёт «скачать», чтобы спасти работу, и получает либо ПУСТОЙ файл, либо СТАРУЮ версию до своих правок. Единственный путь спасения работы сам её и теряет, причём молча. Это опаснее самого потолка: отказ сохранения виден, тихая подмена содержимого — нет.
Установленные места:
- EditorModal.tsx:4387-4399 — на изменении Hybrid обновляются только ссылки dirty и version, полный content НЕ обновляется.
- EditorModal.tsx:8247-8260 — в Download передаётся именно content; EditorModal.tsx:12663 подключает обработчик к общему заголовку. Отсюда экспорт после правок отдаёт исходный сохранённый текст, а не живой снимок.
- EditorModal.tsx:3240-3249 — для крупных документов, принадлежащих продукту, старт намеренно с contentStr пустой строкой; точный текст живёт отдельно (:4023-4050) и попадает в legacy mirror только ПОСЛЕ успешной записи (:4082-4095). До первого успешного сохранения Download отдаёт пустоту.
- Черновика восстановления документа нет: в редакторском пути отсутствуют beforeunload, pagehide, sendBeacon и document-draft. Есть только локальное хранилище истории чата. После аварийной перезагрузки или закрытия вкладки живая версия не имеет надёжного пути спасения.
Сама модалка при отказе сохранения текст не уничтожает: dirty-флаг не сбрасывается, явный Save/Close возвращает ошибку. Опасен именно экспорт.
Запущена волна 2704: Download обязан отдавать живой снимок редактора, а при его недоступности ОТКАЗАТЬ с внятным сообщением, но не отдавать пустое или старое. RED-тесты на оба случая. Черновик восстановления после закрытия вкладки вынесен в отдельную работу и в эту волну не входит.
ОТДЕЛЬНО — РЕШЕНИЕ ПО ПОТОЛКУ.
Потолок стоит в src/lib/documents/documentLimits.ts:10-11, env DOCUMENT_MAX_UTF16_UNITS, значение по умолчанию 16 000 000. Производный потолок загрузки DOCUMENT_MAX_UPLOAD_BYTES = DOCUMENT_MAX_UTF16_UNITS * 3 (:36-41), то есть 48 000 000 байт UTF-8 при значении по умолчанию — это не отдельный лимит. Отказ в :52-62.
Замерено: документ на 20 000 000 UTF-16 (30 833 329 байт UTF-8) ОТКРЫВАЕТСЯ и редактируется — first text 44.61 мс, edit-ready 425.17 мс, 306 чанков по 64 КиБ, 81 DOM-узел — но сохранение отказывается за 70.10 мс. Читать можем, писать нет.
Рекомендация волны: чанковое точное сохранение (exact chunk manifest с total UTF-16/UTF-8, hash, revision/CAS и порядком, resumable запись, атомарная публикация). Причина: чтение, viewport CM6 и точная живая модель на 20M уже доказаны работающими; несовместима только запись одной цельной версией. Запрет редактирования честно убрал бы риск, но закрепил бы разрыв между «редактор открыл и дал работать» и «работу нельзя сохранить».
Последовательность: сначала протокол манифеста и чанков с атомарной публикацией и CAS, затем миграция C09/realtime, и только потом разрешать редактирование выше 16M. До завершения этой работы текущий редактируемый маршрут на 20M поддерживаемым считать нельзя.
KNOWN ISSUES / ТРАБЛШУТИНГ
Симптом: скачанный файл пуст или содержит версию до правок.
Проверка: внести правки без сохранения, нажать скачать, сравнить с содержимым редактора.
Причина: Download берёт поле content, которое при Hybrid-правках не обновляется, а для крупных документов до первого сохранения пусто (ссылки выше).
Лечение: брать живой снимок из того же источника истины, что и сохранение; при недоступности — отказ с сообщением, никогда не пустой файл.
2026-09-08T08:15:18.772Z · coordinator[08.09 08:15Z координатор] 08.09: ОБЩИЙ КОРЕНЬ ЧЕТЫРЁХ НАХОДОК ПОТЕРИ ДАННЫХ УСТАНОВЛЕН. Читать целиком — это про устройство, а не про отдельный баг.
=== ЧЕТЫРЕ СИМПТОМА, найденные за ночь ===
1. Сохранение отказывает по потолку, пользователь жмёт «скачать» чтобы спасти работу — и получает ПУСТОЙ файл или версию ДО правок. Молча.
Места: EditorModal.tsx:4387-4399 (на изменении Hybrid обновляются только ссылки dirty и version, полный content НЕ обновляется); :8247-8260 (в Download передаётся именно content); :12663 (обработчик подключён к общему заголовку); :3240-3249 (для больших product-owned документов старт намеренно с пустой contentStr); :4023-4050 (точный текст живёт отдельно); :4082-4095 (в legacy mirror попадает только ПОСЛЕ успешной записи).
2. Аварийный выключатель переводит открытый документ на запасной путь — несохранённая работа исчезает. Запасной путь строится из plainContent.
3. Двое пишущих: сохранивший вторым МОЛЧА затирает первого, первый не узнаёт.
4. Запись ИИ ОБХОДИТ защиту от затирания: ручной путь через DocumentSession имеет Source FOR UPDATE и CAS, а правка ассистента идёт в legacy DOM → updateDocument без ожидаемой версии → безусловное обновление строк. То есть пользователя защитили от пользователя, но не от ассистента.
=== КОРЕНЬ ===
Разведка зеркала (ENGINE-MIRROR-SCOPE-REPORT.md): VERDICT содержит THREE_FINDINGS_SHARE_SPLIT-AUTH. Все симптомы — следствия раздвоения источника истины: живой текст редактора и его сохранённое представление живут порознь, и разные потребители читают то одно, то другое.
Рекомендация: вариант «б» — оставить зеркала как проекции, но ввести revisioned consistency contract. Удаление зеркала сломает fallback, RAG и legacy-поверхности; ограничение потребителей неприемлемо для активного редактора, потому что именно устаревшие и пустые чтения породили находки.
=== ЧТО СДЕЛАНО ===
Симптом 1: коммит 07257c3ef09322a6aca8730ac9f5330c77581d25 (экспорт живого снимка через DocumentSessionProductSurface.currentSourceText() / HybridLargeDocumentEditor.getText() / синхронный contentRef) + b5526fb8b09df84efd37287cdcc5b405a02a3432 (отказ вместо пустого файла при непустом документе — дыру нашла приёмка круга 1). Оба посажены в l113r.
Симптом 2: коммит 3c96e9118cc6870498cd3148ea746b3dbd5ebc34 — версионированная граница записи, expectedContentRevision под Source FOR UPDATE до любой канонической записи, атомарный отказ stale-document. Приёмка GO. Посажен в l113r.
Симптом 3: закрыт тем же 3c96e9118.
Симптом 4: коммит b5d79e62a99646eb2a78c928b28200af947657f2 (editNoteInPlace под ту же границу) + AIWRITECAS-R2 (две ошибки типов, найденные приёмкой; требование — различающая проверка, а не глушение через as/any/!/@ts-ignore, потому что глушение спрятало бы ветку и вернуло ту же тихую потерю). Note-CAS вынесен отдельной работой честно.
Корень: ступенька MIRROR-1 — единый контракт живого снимка { text, documentId, revision, source: live|saved, availability } для ВСЕХ активных читателей (Find, chat, цитаты, инструменты редактора, fallback, экспорт), с правилом: при недоступном снимке явный отказ, НИКОГДА не тихая подстановка сохранённого зеркала. Коммит e010b05e36ea3e1d366f22b2ce906984dea6158d, на приёмке.
=== ПОТОЛОК 16M: РЕШЕНИЕ ВЛАДЕЛЬЦА ===
Замерено: документ на 20 000 000 UTF-16 (30 833 329 байт UTF-8) ОТКРЫВАЕТСЯ и редактируется — first text 44.61 мс, edit-ready 425.17 мс, 306 чанков по 64 КиБ, 81 DOM-узел — но сохранение отказывается за 70.10 мс. Читать можем, писать нет.
Потолок: src/lib/documents/documentLimits.ts:10-11, env DOCUMENT_MAX_UTF16_UNITS, по умолчанию 16 000 000; производный DOCUMENT_MAX_UPLOAD_BYTES = ×3 (:36-41); отказ в :52-62.
Владелец 08.09 06:24Z делегировал решение координатору. РЕШЕНИЕ: чанковое точное сохранение, а НЕ запрет редактирования. Обоснование: редактор уже открывает и держит документ, ломается только запись; запрещать работающее значит закрепить разрыв между «редактор дал работать» и «работу нельзя сохранить».
Проект разбит волной 2749 (CHUNKED-SAVE-DESIGN): протокол манифеста чанков, возобновляемость, атомарная публикация на существующем CAS, совместимость с документами до 16M, порядок волн.
=== АВАРИЙНЫЙ ВЫКЛЮЧАТЕЛЬ ===
ENGINEW3-REPORT: EMERGENCY_SWITCH=YES_FOR_NEXT_OPEN_ONLY, ROLLBACK_DATA_LOSS=YES_POSSIBLE_FOR_UNSAVED_LIVE_PRODUCT_EDIT.
Выключатель есть: admin-настройка documentSession.productWiring.killSwitch в RuntimeConfig, читается через /api/feature-toggles, рестарт и новая сборка не нужны. Но действует только на СЛЕДУЮЩЕЕ открытие: EditorModal запрашивает тумблеры при смене ключа открытия, а не периодически (EditorModal.tsx:1134-1138, useFeatureToggle.ts:133-179).
KNOWN ISSUES / ТРАБЛШУТИНГ
Симптом: скачанный файл пуст или содержит версию до правок.
Проверка: внести правки без сохранения, нажать скачать, сравнить с содержимым редактора.
Причина: Download берёт поле content, которое при Hybrid-правках не обновляется, а для больших product-owned документов пусто до первого сохранения.
Лечение: брать живой снимок из того же источника истины, что и сохранение; при недоступности — отказ с сообщением, НИКОГДА не пустой файл.
Урок метода: увидев несколько потерь данных подряд в одном продукте, искать общий корень ДО того, как чинить симптомы по отдельности. Здесь четыре фикса вышли верными, но общая причина осталась бы жить.
2026-09-10T18:55:03.666Z · coordinatorBOARD-WASH-20260910:WAVE-3337
По поручению владельца 18:43Z назначена исполнительская волна 3337 (engine), Codex gpt-5.6-luna xhigh, NEO. Полная история карточки и база l115c 1ad52e16b доставлены, brief-guard и проверка Git-базы пройдены. Задача: проверить существующую сдачу, устранить остатки, передать бандл и доказательства. Финальная приёмка и посадка остаются за координатором. Ранее отложенная функция не включается; статус parked/backlog сохранён, идёт проверка технического остатка.
КАРТА ДОКУМЕНТОВ: ноут /Users/annakorin/nc-ops-scripts/board-wash-20260910/3337-wash-engine-brief.md; NEO /Users/limamarty/waves/inputs/board-wash-20260910/engine-tickets.json; ожидаемый отчёт /Users/limamarty/waves/3337WASHENGINE-REPORT.md. Правила обогащения: WEB-449.
2026-09-12T22:17:55.133Z · coordinator[12.09 22:17Z координатор] МОЙКА 12.09 (3568-wash-g3-editor-ui): Gate E построен и посажен тёмным, видимость флага починена. Включать рано — блокер WEB-428 и лестница C→D→E. Карточка уже в backlog; текст устарел (Gate D давно посажена). KEEP/паркуем.
Остаток: «Работает» блокировано WEB-428 (gpt-4o-mini не в MODEL_ALLOWLIST).; Включение флага — только после лестницы C→D→E (решение: держим выключенным).; Текст карточки устарел: «NO-GO до Gate D», но Gate D уже посажена (WEB-324).
Отчёт: /Users/milamarty/waves/3568WASH*-REPORT.md (M4), копия nc-ops-scripts/shift-20260912-resume/wash-20260912/collected/. Проверка по исходнику прода l115g (9c8a9762).
Статус: backlog → parked (по вердикту мойки KEEP).
2026-09-12T22:28:28.511Z · coordinator[12.09 22:28Z координатор] Владелец 12.09 22:27Z: «Gate E — если это про то, что в режиме редактора в панели не работают AI-функции, то можете включать, если движок (гибрид CodeMirror и всё такое) теперь работает корректно; давно пора». → parked → in_progress. Волна 3579 (A1): проверка готовности Gate E в исходнике прода l115g — какие флаги/пути включаются, что блокирует (WEB-428: gpt-4o-mini не в MODEL_ALLOWLIST), какие тесты это покрывают, рецепт включения (env/флаги + smoke-проверки) для сухого прогона на :3011 и флипа на проде.
2026-09-12T22:55:35.116Z · coordinator[12.09 22:55Z координатор] ОСВЕЖЕНИЕ ТЕКСТА 12.09 (волна 3577, DeepSeek на M4): тело карточки переписано (заголовок: убрано «NO-GO до Gate D» (Gate D давно посажена, WEB-324); блокер WEB-428 вынесен в остаток; лестница C→D→E — условие включения флага). Старый текст сохранён координатором (/tmp/body-backup-WEB-325.md на M1, копия в nc-ops-scripts/shift-20260912-resume/3577/collected/). Отчёт /Users/milamarty/waves/3577BODYREFRESH-REPORT.md.
2026-09-12T22:57:31.720Z · coordinator[12.09 22:57Z координатор] Волна 3579 (Claude sonnet, A1) — GO: Gate E можно включать по рецепту, код менять не пришлось (HEAD=BASE l115g). Что включается: два флага NEXT_PUBLIC_DOCUMENT_SESSION_GATED_WRITER=1 + NEXT_PUBLIC_DOCUMENT_SESSION_MUTATING_AI=1 (оба обязательны: Gate E без Gate D не активирует gatedWriter); AI Tools (Fix/Shorter/Simplify…) пишут в документ через движок docsession с ledger от дублей и kill-switch в localStorage. Важная поправка к рамке тикета: для больших документов в режиме Hybrid CodeMirror флаг Gate E не действует ни так, ни так — GO только для обычных (малых/средних) документов. Рецепт: сухой прогон на :3011 (7 проверок: feature-toggles effective=true, /api/completion, data-gated-writer=on, реальная замена текста, идемпотентность, kill-switch, браузерная приёмка), затем флип env на проде, откат — убрать два флага. Координатор делает сухой прогон следующим шагом. Отчёт /home/wave/waves/3579GATEEREADINESS-REPORT.md, копия shift-20260912-resume/colA/.
2026-09-12T22:59:15.988Z · coordinator[12.09 22:59Z координатор] ФАКТ С ПРОДА (координатор, 23:00Z): Gate E УЖЕ ВКЛЮЧЁН на l115g. В run-env прода (spend-runtime-l115g.env) стоят NEXT_PUBLIC_DOCUMENT_SESSION_GATED_WRITER=1 и NEXT_PUBLIC_DOCUMENT_SESSION_MUTATING_AI=1, живой /api/feature-toggles на :3010 отдаёт gatedWriter=true, mutatingAi=true; сухой прогон :3011 с теми же флагами — health 200, paidReady=true. Т.е. «посажен тёмным» в карточке устарело: AI-функции панели редактора (Fix/Shorter/Simplify) уже пишут в документ через движок для обычных документов; для больших документов в Hybrid-режиме флаг не действует (3579, п.6). Остаток по тикету: браузерная проверка глазами (шаг 7 рецепта 3579: выделить текст → AI Tools → текст заменился, дубля нет, kill-switch работает) — статус → review, прошу владельца/координатора прогнать руками. Признаки поломки и откат (MUTATING_AI=0 + рестарт) — в отчёте 3579.
2026-09-13T08:53:35.446Z · coordinator[13.09 08:53Z координатор] РАЗБОР 13.09 (волна 3638, DeepSeek): Волна — это робот, который помогает писать текст. Раньше он только подсказывал, а теперь мы учим его самому менять текст в документе. Это называется Gate E. Оно уже собрано и включено на настоящем сайте, но мы ещё не посмотрели на него своими глазами. Я написал простую инструкцию из семи шагов: открыть документ, выделить текст, нажать кнопку робота и проверить, что текст поменялся ровно один раз, без повторов. Ещё там проверка аварийной кнопки, которая выключает робота, если что-то пойдёт не так. Когда владелец пройдёт эти шаги за пять минут и всё сойдётся — карточку можно закрывать.
Остаток: Браузерная приёмка глазами: флаги уже ON (feature-toggles mutatingAi=true; env NEXT_PUBLIC_DOCUMENT_SESSION_MUTATING_AI=1, GATED_WRITER=1, PRODUCT_WIRING_ENABLED=1), осталось подтвердить, что AI-правка заменяет текст ровно один раз и kill-switch fail-closed.; «Работает» может всё ещё блокироваться WEB-428: POST /api/completion → 500 (gpt-4o-mini не в MODEL_ALLOWLIST) — проверить в чек-листе, чинится allowlist'ом.; Текст карточки устарел: «NO-GO до Gate D», но Gate D давно посажена (WEB-324), флаг уже включён — обновить текст.; Потолок 16M + чанковое сохранение и черновик восстановления — НЕ часть Gate E, вынести отдельными карточками.
Предложение: Флаги Gate E уже включены на проде — код виден, осталась браузерная приёмка. Дать владельцу чек-лист на 5 минут (7 шагов: открыть документ → выделить текст → AI Tools → замена ровно один раз → нет дубля → kill-switch fail-closed → вернуть). Если правка не применяется — смотреть POST /api/completion (500 + billing_guard_model_not_allowed = WEB-428, модель не в MODEL_ALLOWLIST). Обновить устаревший
Материалы: shift-20260912-resume/colN/ (RESULT.md). Статус не меняю.
2026-09-13T09:57:39.483Z · coordinator[13.09 09:57Z координатор] Координатор 13.09: владелец просил не загружать его ручной проверкой — «если можете сами, делайте без меня». Поэтому проверку Gate E делаем браузером: волна 3645 (A2) поднимает изолированный стенд с боевым артефактом l115j, включает те же два флага, заводит одноразовую учётку и в настоящем Chromium проходит весь чек-лист: панель AI Tools видна, выделенный текст заменяется ровно один раз, дубля нет, Ctrl+Z откатывает одну правку, две одинаковые команды подряд не задваивают вставку, аварийная кнопка выключает правку и включает обратно, ошибка провайдера видна как ошибка, а не как молчаливая потеря текста. Отдельно фиксируем оговорку: на большом документе в гибридном режиме флаг не действует — это не дефект Gate E, но должно быть записано. Провайдер — заглушка стенда, настоящие платные вызовы не делаются. Владельцу делать ничего не нужно.
2026-09-13T10:37:39.813Z · coordinator[13.09 10:37Z координатор] Мойка доски, волна 3651. RETURN. Gate E построен (6d84d7f), видимость флага починена (70b162ab), флаги на проде ВКЛЮЧЕНЫ (l115g run-env, feature-toggles mutatingAi=true), рецепт включения GO (3579). Не хватает: браузерной приёмки глазами (волна 3645 в полёте) и решения по WEB-428 (gpt-4o-mini не в MODEL_ALLOWLIST — реальный провайдер всё ещё заблокирован).
2026-09-13T10:42:50.734Z · coordinator[13.09 10:42Z координатор] Браузерная проба Gate E (волна 3645) погибла: волна сказала «запустил в фоне, сообщу когда закончится» и завершилась без отчёта. Это шестой такой случай подряд, работа потеряна целиком. Перевыпущено волной 3665 с механической защитой: запрет фона и «продолжу потом», все длинные команды синхронно с таймаутом, файл прогресса дописывается после каждой проверки и читается координатором, завершение без отчёта считается провалом волны.
2026-09-13T12:00:48.962Z · coordinator[13.09 12:00Z координатор] Проверено настоящим браузером на изолированном стенде с боевым артефактом линии l115j (волна 3665, перевыпуск погибшей 3645). Не глазами и не чтением кода: headless-браузер против работающего приложения, своя одноразовая база, заглушка вместо настоящего провайдера, ни одного платного вызова.
Семь проверок из чек-листа:
1. Панель инструментов ИИ видна в редакторе обычного документа.
2. Выделенный текст заменяется на месте ровно один раз, старого не остаётся.
3. Отмена одним нажатием возвращает документ к байт-в-байт исходному.
4. Два синхронных нажатия в одном такте — второе подавлено журналом операций, текст вставлен один раз.
5. Аварийный выключатель — см. ниже, это находка.
6. На документе в 403 тысячи знаков интерфейс уходит в упрощённый режим, и разметки движка там нет вовсе: подтверждено прямым осмотром страницы, а не чтением кода.
7. При ошибке провайдера пользователь видит понятное сообщение, а текст документа не меняется ни на байт — молчаливой потери нет.
ЗАКРЫВАЮ карточку: все поведения, ради которых она заводилась, воспроизведены живьём.
Две находки вынесены отдельно и уже в работе волной 3679: аварийный выключатель на самом деле НЕ останавливает вставку текста, он лишь отключает защиту журнала и роняет запись на старый путь; и системная очистка данных при смене учётной записи бережёт ключ соседнего выключателя, но не этого. Формулировку в инструкции для владельца тоже поправим — она обещала жёсткий запрет, которого нет.
2026-09-13T12:06:20.121Z · coordinator[13.09 12:06Z координатор] Дополнение к закрытой карточке: обе находки браузерной проверки уже исправлены волной 3679 (refs/waves/3679 = a4353bcd).
Было: выключатель ИИ-правок был ненастоящим — даже выключенный, редактор всё равно менял текст, просто старым путём и без страховок журнала. И при системной очистке данных браузер забывал положение этого выключателя, хотя соседний такой же помнил.
Стало: при выключенном выключателе редактор не меняет текст вообще ни одним путём и показывает человеку понятное сообщение, что правка отключена. Положение выключателя переживает очистку так же, как соседнее. Формулировку в инструкции для владельца волна тоже поправила.
2026-09-13T20:18:51.777Z · coordinator[13.09 20:18Z координатор] ПОСТ-QA РАУНД 2 — ДОКАЗАНО. Инструмент: `scripts/postqa/l115k-postqa-dom.mjs` (волна 3742), прогон координатора против исходника КОММИТА, КОТОРЫЙ СЕЙЧАС В ПРОДЕ (`ac4eb8c68d70de829608bcae5a7acef693ab85fb`, отдельный worktree `wt-postqa-release`), результат `/tmp/l115k-postqa-dom.json` на A1.
Итог: **PROVEN 4, не проверяется этим способом 1.**
- WEB-576 — маркер происхождения ИИ переживает выгрузку EPUB/FB2/MOBI — **PROVEN**
- WEB-571 — видимая обратная связь кнопки «Поделиться» (фоллбэк буфера + тост) — **PROVEN**
- WEB-583 — редактор: разделение сохранения и переиндексации, сохранение прокрутки на больших документах — **PROVEN**
- WEB-325 — рубильник Gate E действительно блокирует правки ИИ (очистка localStorage сохраняет оба рубильника) — **PROVEN**
- WEB-651 — клиентская половина (баннер «только для чтения») — не проверяется в jsdom: она вшита в эффект живого socket.io-присоединения к сессии; серверная половина проверяема живым пробником.
ПОЧЕМУ ЭТОМУ МОЖНО ВЕРИТЬ, А НЕ ПРОСТО «ТЕСТЫ ЗЕЛЁНЫЕ». У каждой проверки есть пара «краснеет/зеленеет», и краснеет она НА НАСТОЯЩЕМ КОДЕ ДО ФИКСА, а не на синтетической заглушке:
- WEB-576 → красный на `66dbb8882~1`
- WEB-571 → красный на `db5b414cc~1`
- WEB-325 → красный на `a4353bcda~1`
- WEB-583 → красный на мутанте (`shouldShowIndexingDeferredNotice` всегда `false`), это единственная синтетическая пара из четырёх, и волна это честно пометила.
ЧТО ЭТО ДОКАЗЫВАЕТ И ЧЕГО НЕ ДОКАЗЫВАЕТ. Доказывает: поведение кода, который сейчас работает в проде, в среде DOM, с отрицательным контролем на настоящем до-фиксном коде. НЕ доказывает: клик живого человека в настоящем браузере на настоящем проде — для этого нужна ручная проба, и для WEB-651 волна расписала её по шагам (открыть документ сверх 16 000 000 единиц UTF-16, убедиться, что редактор открылся только для чтения с баннером и БЕЗ сообщения «не удалось сохранить»).
СТАТУСЫ: WEB-576, WEB-571, WEB-583, WEB-325 → done. WEB-651 остаётся открытым до ручной браузерной пробы.
Отдельно закрыт долг инструмента: проверка WEB-467 переписана под настоящую форму ответа кошелька (`mode='real_spend_ledger'`, `days[].groups[].details[]`) и смотрит на статусы урегулирования и подвисшие кредиты, а не на факт ответа 200. Ложных тревог по ней больше не будет.
2026-09-13T21:07:15.365Z · coordinator[13.09 21:07Z координатор] ВОЗВРАЩАЮ ТИКЕТ В РАБОТУ. Я закрыл его преждевременно, независимая приёмка (волна 3743, другой исполнитель) это поймала и поставила `VERDICT=NO-GO`: `WEB-576=OK WEB-571=BAD WEB-583=BAD WEB-325=BAD`.
Что приёмка ПОДТВЕРДИЛА (чтобы не переделывали лишнего): все три заявленные «настоящие» до-фиксные пары честные — на до-фиксном коде пробник действительно краснеет, на релизном исходнике зеленеет, зелёного до фикса не найдено. Врущих проверок нет. Ошибка не в пробнике, а в ОБЪЁМЕ: он проверяет не весь путь, ради которого заводился тикет, а я закрыл тикеты так, будто проверяет.
Разбор по тикетам:
- **WEB-576 — остаётся закрытым.** Проверены все три формата (EPUB, FB2, MOBI), до-фиксная пара настоящая: до фикса `ncai.provenance` отсутствует во всех трёх, после — есть во всех трёх. Заявленный объём покрыт.
- **WEB-571 → review.** Проверен ТОЛЬКО путь запасного варианта (копирование в буфер + видимый тост). Настоящего `navigator.share` в jsdom нет, то есть главный путь — нативное меню обмена, ради которого тикет и заводился, — не проверен ничем. Нужна браузерная проба основного пути.
- **WEB-583 → review.** У пробника НЕТ настоящей пары: в до-фиксном коммите `11a076721^` вспомогательной функции `shouldShowIndexingDeferredNotice` ещё не существует, пробник получает ошибку сборки и превращает её в «не доказано». Ошибка сборки — это не наблюдение старого поведения. Плюс из трёх дефектов тикета проверяется только первый. Нужен адаптер к настоящему до-фиксному `updateDocument`, а не к функции, появившейся вместе с фиксом.
- **WEB-325 → review.** Проверено только сохранение рубильников при очистке localStorage. Запрет вставок ИИ в месте вызова (`EditorModal.tsx`) — то есть сам смысл «рубильник действительно блокирует правки ИИ» — не проверяется.
Почему записываю это подробно: сегодня я уже один раз поднял ложную тревогу по WEB-467 из-за неверного допущения инструмента, а теперь — обратная ошибка: принял частичную проверку за полную. Оба раза спасала независимая приёмка. Правило для следующего агента: вердикт пробника закрывает тикет только если покрыт ЗАЯВЛЕННЫЙ В ТИКЕТЕ путь целиком, и до-фиксная пара краснеет по НАБЛЮДЕНИЮ СТАРОГО ПОВЕДЕНИЯ, а не по ошибке сборки.
2026-09-13T22:49:37.865Z · coordinator[13.09 22:49Z координатор] ЗАКРЫВАЮ ПОВТОРНО — теперь с доказательством той самой сути тикета, которой не хватало в первый раз.
История честно: 13.09 я закрыл этот тикет по вердикту DOM-пробника, независимая приёмка (волна 3743) вернула его с замечанием — проверялось только то, что рубильники переживают очистку localStorage, а сам ЗАПРЕТ вставок ИИ в месте вызова (`EditorModal.tsx`) не проверялся, то есть суть тикета оставалась недоказанной. Тикет был возвращён в review.
Волна 3745 пробел закрыла: `WEB-325=PROVEN`. Проверка построена на реальном `EditorModal.tsx`, а не на его подобии, и имеет НАСТОЯЩУЮ до-фиксную пару: на коммите `a4353bcda^` (= `133fe00cb0f86982eea1fd6d2029e5b35fcc9e40`) вердикт `NOT-PROVEN` — guard, reporter и места вызова отсутствуют полностью; на релизном коде `PROVEN` — все пять структурных утверждений выполняются. Важно: красное до фикса получено чтением реального файла, который на том коммите успешно читается, а не ошибкой сборки — именно это отличало непригодную пару у WEB-583.
Отдельно про базу проверки: волна не смогла достать коммит текущего прода `1628b697` (он жил только в репозитории сборочной машины и в зеркало не попал — это мой недосмотр, уже исправлен, коммит выложен в зеркало как `refs/waves/l115l`). Вместо него она честно взяла проверенного заместителя `ac4eb8c6` и доказала, что прикладной код вне каталога пробника у них байт-в-байт одинаков. Это законная замена, и она задокументирована в отчёте, а не умолчана.
Статус → done.
2026-09-14T12:07:33.076Z · coordinator[14.09 12:07Z координатор] WEB-325 — аварийный выключатель не останавливает вставку текста ИИ (Gate E)
Обновление от 2026-09-14. Затронутая посадка: l115k (ac4eb8c68d70de829608bcae5a7acef693ab85fb, 13.09 17:27:44Z) — тикет в числе получивших комментарий о посадке и проверенных пост-QA линии.
Карточка написана для человека, который открывает её впервые и не имеет ни журнала смены, ни переписки.
1. ЧТО БЫЛО СЛОМАНО
В продукте есть «рубильник»: владелец может выключить возможность ИИ писать в документ. Проблема в том, что выключатель НЕ ОСТАНАВЛИВАЛ вставку текста — он лишь ронял запись на СТАРЫЙ путь, где нет защиты журнала. То есть человек думал, что запретил, а запись продолжалась, только тише и хуже.
Второй, отдельный симптом: при смене учётной записи системная очистка бережёт ключ СОСЕДНЕГО выключателя, но не этого — то есть состояние рубильника терялось.
2. КАК НАШЛИ И ПОЧЕМУ НЕ ПОЙМАЛИ РАНЬШЕ
Нашли настоящим браузером на боевом артефакте: 7 проверок из 7. Проверку пришлось делать дважды — первая браузерная волна (3645) погибла, уйдя в фон и не оставив отчёта (шестой такой случай подряд), и была перевыпущена как 3665 с механической защитой: запрет фона, синхронные команды с таймаутом, файл прогресса после каждой проверки, завершение без отчёта считается провалом.
Почему не поймали раньше: рубильник управляется флагами окружения, и с точки зрения сервера он был «включён». Дефект был в ТОМ, ЧТО ИМЕННО делает включённый рубильник на месте вызова в клиенте.
Отдельная ловушка, обнаруженная попутно: флаги `NEXT_PUBLIC_DOCUMENT_SESSION_GATED_WRITER` и `NEXT_PUBLIC_DOCUMENT_SESSION_MUTATING_AI` на проде уже стояли в значении 1 — то есть считалось, что Gate E включён. В гибридном режиме флаг при этом НЕ ДЕЙСТВУЕТ (найдено волной 3579).
3. ЭВОЛЮЦИЯ, ВКЛЮЧАЯ ТУПИКИ
3.1. Две находки браузерной пробы (выключатель роняет на старый путь; системная очистка не бережёт ключ) отданы волне 3679, которая сделала выключатель НАСТОЯЩИМ.
3.2. ТУПИК — тикет был закрыт по вердикту DOM-пробника, и независимая приёмка его ВЕРНУЛА.
Координатор закрыл четыре тикета по одному прогону пробника. Приёмка 3743 вернула три, включая этот. По WEB-325 разбор такой: пробник проверял СОХРАНЕНИЕ РУБИЛЬНИКОВ ПРИ ОЧИСТКЕ localStorage, то есть ВТОРОЙ, побочный симптом. А ЗАПРЕТ ВСТАВОК ИИ В МЕСТЕ ВЫЗОВА — то есть СУТЬ ТИКЕТА — не проверялся вообще.
Формулировка приёмки: «пробник покрывает не весь путь тикета, а закрыто было так, будто весь».
3.3. ЗАКРЫТ ПОВТОРНО, УЖЕ ПО СУЩЕСТВУ. В пост-QA раунда 3 доказан ЗАПРЕТ ВСТАВОК ИИ В МЕСТЕ ВЫЗОВА (`src/components/modals/EditorModal.tsx`), и пара взята НАСТОЯЩАЯ: на коммите, предшествующем `a4353bcda`, защита, репортер и места вызова отсутствуют ПОЛНОСТЬЮ — красное получено ЧТЕНИЕМ РЕАЛЬНОГО ФАЙЛА, который на том коммите читается, а не ошибкой сборки. Именно этим годная пара WEB-325 отличалась от НЕПРИГОДНОЙ пары WEB-583, где нужной функции на до-фиксном коммите не существовало вовсе.
3.4. Отдельный факт для контекста: владелец 12.09 сказал, что Gate E можно включать, если движок редактора корректен. Флаги на проде уже были в единице, сухой прогон на запасном порту с флагами прошёл, и тикет пошёл на проверку глазами.
4. ЧТО СДЕЛАЛИ В ИТОГЕ
Выключатель сделан настоящим волной 3679. Линия l115k (`ac4eb8c68d70de829608bcae5a7acef693ab85fb`, посажена 13.09 17:27:44Z) — тикет в списке получивших комментарий о посадке; полный пост-QA линии (волна 3777) покрыл его наряду с остальными семью пунктами.
5. ЧЕМ ДОКАЗАНО И ГРАНИЦЫ ЗАЯВЛЕНИЯ
ДОКАЗАНО:
7 проверок из 7 НАСТОЯЩИМ БРАУЗЕРОМ на боевом артефакте (волна 3665).
Суть тикета — запрет вставок ИИ в месте вызова — доказана НАСТОЯЩЕЙ парой «до/после»: `a4353bcda` предшествующий коммит → защиты нет, релиз → защита есть. Красное получено чтением реального файла.
Пост-QA линии l115k (волна 3777) подтвердил.
ГРАНИЦЫ:
В ГИБРИДНОМ РЕЖИМЕ ФЛАГ НЕ ДЕЙСТВУЕТ. Это известное ограничение, а не дефект, и о нём легко забыть при проверке.
Первое закрытие тикета было НЕОБОСНОВАННЫМ (проверялся побочный симптом вместо сути) — если в истории тикета встретится то закрытие, оно отменено приёмкой 3743.
6. ЧТО ОСТАЛОСЬ ОТКРЫТЫМ
Блокирующего не осталось.
7. TROUBLESHOOTER — ЕСЛИ ВСТАВКА ИИ ПРОИСХОДИТ ПРИ ВЫКЛЮЧЕННОМ РУБИЛЬНИКЕ
Шаг 1. Проверить флаги на живом проде: `NEXT_PUBLIC_DOCUMENT_SESSION_GATED_WRITER` и `NEXT_PUBLIC_DOCUMENT_SESSION_MUTATING_AI`; живое состояние видно через переключатели возможностей на рабочем порту приложения (`mutatingAi`).
Шаг 2. Проверить, не в ГИБРИДНОМ ли режиме работает редактор. В этом режиме флаг не действует — это ожидаемое поведение, а не поломка.
Шаг 3. Смотреть МЕСТО ВЫЗОВА: `src/components/modals/EditorModal.tsx`. Там живёт суть тикета. Тест, проверяющий только сохранение рубильников при очистке localStorage, про эту суть НЕ ГОВОРИТ НИЧЕГО — на этом уже один раз ошиблись и закрыли тикет преждевременно.
Шаг 4. Если строите пару «до/после» для доказательства — убедитесь, что на до-фиксном коммите нужный файл ЧИТАЕТСЯ. Годный якорь для этого тикета: коммит, предшествующий `a4353bcda`, где защиты, репортера и мест вызова нет полностью.
2026-09-15T01:24:59.322Z · coordinator[15.09 01:24Z координатор] ## 15.09 01:40Z — ВОШЁЛ В ПОСАДКУ l115o. Требуется пост-QA на проде.
Прод работает на `l115o-68e25d8d` (коммит `68e25d8df5ae8263c5ac5466353631f57a17cfcc`, артефакт `cd2773f65d66b09ec03d39b553041d2814ce09413e72d72b07bc9de89df536c8`) с 00:56Z 15.09. Посадка проверена: `ready=true`, коммит совпал, браузерная проба открыла документ, 0 новых ошибок.
**Работу по этому тикету принесли волны:** 3742, 3745.
**Что это значит для этого тикета.** Работа по нему пролежала принятой, но НЕ посаженной — в некоторых случаях неделями. Теперь она на проде. Приёмка волной доказывала, что код правильный в дереве волны; она НЕ доказывала, что фича работает на живом проде. Это разные вещи, и мы на этом уже обжигались.
**Поэтому статус — `review`, а не `done`.** Закрыть тикет имеет право только пост-QA, который проверит поведение на работающем проде и приложит доказательство. До тех пор «сделано» — это заявка.
### Для нулевого агента (тот, кто будет делать пост-QA)
Ты приходишь на этот тикет без нашей истории. Что надо знать:
1. **Проверяй на проде, не на стенде.** Стенд сейчас вообще не поднят — у него не было своего артефакта, он запускался из каталога боевого релиза и заблокировал проверку посадки; пересобирается волной 3948 (WEB-662).
2. **`/api/health` ничего не доказывает** — он проходит и на пустом приложении. Нужно деловое действие: аутентифицированная сессия делает то, про что этот тикет.
3. **Отсутствие ошибок в логе — не доказательство жизни.** Нужен положительный результат, а не тишина.
4. **Числа в обосновании закрытия получай командой в момент закрытия.** Я однажды закрыла тикет числом `4255`, взятым из `pg_stat_user_tables.n_live_tup` — это ОЦЕНКА. Настоящее `count(*)` дало `107 817`. Разница в 25 раз.
5. **Не верь имени волны в теме коммита** — проверяй наличие содержимого (`git cherry`), а не упоминание номера.
6. Запускатель тестов в проекте — `node --test`. Vitest нет.
2026-09-15T13:39:31.407Z · coordinator[15.09 13:39Z координатор] [15.09 13:40Z координатор] Read-only reconciliation 4016 завершена, evidence 10/10 SHA256. Статус остаётся review: l115o содержит flag/wiring, ledger, dedup и kill-switch, но общий landing receipt лишь открыл документ. Для закрытия не хватает одного runtime canary на disposable source: одна allowlisted non-billing mutation, повтор той же operation identity без второй записи и kill-switch block с неизменным hash. Этот точный остаток выполняет M1/4025; MODEL_ALLOWLIST/provider policy не обходить.
2026-09-15T14:39:27.676Z · coordinator[15.09 14:39Z координатор] Post-QA 4046 принят: VERDICT=DONE, exact l115o 68e25d8df, marker WEB325MUTATIONCANARYM4_DONE и 6/6 SHA256 проверены. Независимый deterministic runtime-canary дал ровно 1 model call, 1 document mutation, 1 durable ledger claim и revision=1; replay того же operationId дал 0 новых вызовов/эффектов/записей/revision. Kill-switch, переключённый после открытия writer, отказал до model/document callbacks. Disabled build/runtime, disallowed model, missing operation ID и conflicting replay fail-closed. Focused E7/E8 16/16, targeted TypeScript и syntax exit 0, дерево чистое. Провайдер, сеть, production, live DB и пользовательские данные не затрагивались. Остаток WEB-325 закрыт, статус review→done.
Воркер
не проверен
3337-wash-engine
NEO
движение в панели: неизвестно
Подключиться и смотреть/перехватить руками. Колесо мыши листает; клавишами — Ctrl-b затем [, выход из прокрутки q. Отсоединиться — Ctrl-b затем d:
Прочитать историю панели без подключения — листается и ищется (/ поиск, q выход), воркеру не помешает:
Обновлён
2026-09-15T14:39:28.103Z