WEB-670 · Дефект · Инфраструктура · web
P1 [класс]: объявленные, но мёртвые защиты — облава нашла 7, из них 4 опасных
Закрыт
P1 · важно
ведёт: —
Суть
## Облава волны 3961 по классу «объявленная, но мёртвая защита». Найдено 7, из них опасных 4.
Класс завели после того, как за одни сутки наткнулись на три таких защиты подряд: мёртвый `failClosed` в телефонии (объявлен, в теле функции не используется), правило ufw на `uid 999` при стенде под `uid 1001`, и **28 из 29 карточек миграций со ссылкой на несуществующий флаг возможности**. По правилу «третья находка одного класса — это устройство, а не баги» поставили облаву на весь код.
Ветка в зеркале: `refs/waves/3961/audit/3961-dead-guards`. Отчёт и доказательства на M4: `~/waves/3961GUARDS-REPORT.md`, `~/waves/3961GUARDS-evidence/`.
### Четыре опасные
**1. Рубильник принуждения политики R14 ничего не переключает.** Настройка включается оператором из базы и называется «принуждение политики R14». В коде **нет ни одного места, которое её спрашивает**. Оператор включает — ничего не происходит, и он об этом не узнаёт. Рядом два похожих рубильника работают по-настоящему, поэтому снаружи все выглядят одинаково живыми.
**2. Две роли объявляют запрет на внешние источники, и запрета нет.** В карточках ролей `support` и `timeline` написано: внешние источники запрещены, чувствительные личные данные — только по прямому запросу пользователя. **Ни одно из двух правил никем не читается.** Выбрав такую роль, пользователь получает ровно тот же доступ, что и без неё.
**3. Сломанная настройка телефонного корпуса молча становится «ничего не настроено».** Когда область документов у номера сохранена неправильно или слишком большая, код это замечает и ставит пометку «настройка недействительна». **Пометку никто не читает.** Звонок продолжается с пустой областью — то есть ведёт себя так же, как если бы область не настраивали. Отличить поломку от «ещё не настроили» снаружи нельзя. Смежно с WEB-665: там пустая область означала поиск без фильтра.
**4. Правило скрытия секретов в логах шлюза написано не про то место.** Шлюз реального времени принимает токен доступа к комнате двумя способами — в заголовке и в адресе ссылки. Правило, вычищающее токен из логов, написано **только про заголовок**. Собственные тесты шлюза ходят как раз через адрес. Если хоть одна строка лога напечатает запрос целиком, токен уйдёт в лог открытым. Прогоном подтвердить не удалось — в той копии нет установленных зависимостей.
### Три поспокойнее
- признак «расчёт закрылся нездорово» объявлен в контракте и **никогда не выставляется** — нездоровые расчёты выглядят здоровыми;
- приглашение в комнату пишет в журнал утверждение «обхода гостевого чата не было», **ничего при этом не измеряя**;
- проверка типов «Gate F» существует как конфигурация и документ, но **её не запускает ни один скрипт и ни один шаг CI**, и вдобавок 4 из 16 файлов в её списке давно удалены.
### Важный вывод волны — это не незнание
Забор, отрезающий интернет на стенде Gate0, устроен по **той же геометрии**, что и сломанное правило на стенде замеров: правило файрвола пишется на один системный аккаунт, а ходит другой. Но там оба берутся **из одного места при установке**, и субъекты совпадают. То есть класс в проекте знают и умеют делать правильно — сломанные случаи это **несведённые концы, а не непонимание**.
### Что дальше
Волне было запрещено чинить — это облава, а не починка. Каждую из семи закрывать отдельно, и у каждой обязан быть **отрицательный тест**: сломай вход и покажи, что защита сказала «нет». Защита, которая никогда не говорила «нет», ничего не доказывает — именно так все семь и дожили до сегодня.
Связано: WEB-665 (мёртвый `failClosed`, пустая область), WEB-629 (ufw на чужой uid), WEB-660 (28 из 29 карточек миграций), WEB-667 (нет обратной проверки миграций).
## HANDOFF 2026-09-19T20:23Z — 4245 author GO → 4248 independent
4245/M4 terminal: GO_FOR_INDEPENDENT_ACCEPTANCE, exit 0; manifest PASS 63/63, manifest SHA-256 a23d153a6ab995b5adf6caaa629f5702bcb09eaf5df1d1fd789db8d761f6cfde, self-entry 0, *_DONE 0. Repaired head 4741f156d0c7e4cd14be1de86d7d0f4e7b7891f6; bundle SHA-256 79beb0351818974a57fb6f2497a9a38c5a11196afe1f7dff7ce9b49c9497be97. Author claims 47/47 behavioral, 5/5 global-route, 35/35 sealed-independent, 5/5 gateway bytes, 15/15 mutations. Literal residuals preserved: broad chat-global mock suite 9/20 pass (11 fail), full-root typecheck OOM exit137/not run, one mock case skipped. Exact input/output transported to M1 and read back; fresh 4248/Codex Luna high independently verifies ordering, redaction, caller-ID failClosed, corpus guard and mutation verdict integrity. Maximum GO_FOR_CANDIDATE_BUILD; build/landing/live NOT_EXECUTED.
Лента
2026-09-15T03:20:46.522Z · coordinator[15.09 03:20Z координатор] ## 15.09 08:15Z — волна 3964 сдала `VERDICT=GO`, **закрыто 4 из 4**. У каждой починки отрицательный тест, падающий на старом коде.
Ветка в зеркале: `refs/waves/3964/fix/3964-dead-guards` = `29a86d21da140ddea13db43cb4b649c8501c70fb`.
**1. Переключатель «принуждение политики R14» — удалён, а не подключён.** Волна проверила **всю историю**: места, которое бы его спрашивало, не было **никогда**, и подсистемы, которой он якобы управляет, в продукте **не существует** — подключать было бы нечем. Убран, чтобы оператор не видел пустышку. **Плюс поставлена проверка сборки: любой новый переключатель без потребителя роняет сборку.** Это ровно то, что нужно классу — защита от повторения, а не только починка случая.
**2. Роли «Talk It Through» и «Then & Now» теперь соблюдают своё обещание.** Раньше запрет внешних источников и ограничение по личным данным были просто словами в карточке. Теперь: роли не дают веб-поиск и прочие внешние источники, а по аккаунту без спроса они могут ходить **только если пользователь сам указал, где смотреть** — выбрал блокнот или конкретные источники.
**3. Сломанная настройка телефонного номера больше не притворяется ненастроенной.** Неправильная или слишком большая область документов **останавливает звонок с понятной причиной**, вместо того чтобы продолжаться с пустой областью. Это закрывает и смежную дыру WEB-665, где пустая область означала поиск вообще без фильтра.
**4. Токен доступа к комнате больше не попадает в логи шлюза — доказано прогоном.** Волна **подняла шлюз** и проверила: на старом коде токен действительно печатается открытым текстом; на новом на его месте заглушка, а сам адрес остаётся читаемым.
⚠️ Её формулировка про этот пункт точная и её стоит запомнить: **«это была скрытая мина: сегодня шлюз запросы не логирует, поэтому наружу ничего не текло, но утечка включилась бы сама в первый же момент, когда какая-нибудь ошибка залогировала бы запрос»**. То есть дефект был неактивен не по устройству, а по случайности конфигурации.
### Главное — почему они дожили до сегодня
Дословно: «у всех четырёх был один и тот же изъян проверки: вопрос "защита объявлена?" отвечал "да", а вопрос "защита участвует в решении?" никто не задавал».
Поэтому к каждой починке приложен тест, который **ломает вход и требует услышать «нет»**, и каждый **падает на старом коде — и падает по делу**, называя именно утёкшее: какие инструменты роль всё ещё получает, что токен напечатан открытым.
### Остаток по тикету
Три «поспокойнее» находки не трогали, как и было велено: признак «расчёт закрылся нездорово», который никогда не выставляется; запись в журнал про обход гостевого чата, ничего не измеряющая; проверка типов Gate F, которую не запускает ни один скрипт и у которой 4 из 16 файлов в списке удалены.
Нужна независимая приёмка. Пункты 2 и 4 — правки безопасности, значит **приёмка не на моделях OpenAI**.
2026-09-15T12:56:35.793Z · coordinator[15.09 12:56Z координатор] [15.09 12:54Z координатор] Независимая приёмка 4007: VERDICT=NO-GO. Три защиты из четырёх подтверждены RED→GREEN, но найден actual-wiring bypass.
Role privacy подключена в `src/app/actions.ts` / `chatWithSources`, однако отдельный `/api/chat-global` не вызывает этот reader и напрямую строит `allowedSourceIds` из всего доступного аккаунта. Поэтому support/timeline personal-data sweep в global entrypoint остаётся несуженным. Это реальный обход, а не недостаток fixture. Gateway byte-level run отдельно не выполнен из-за отсутствующего Fastify; module-level redaction зелёный.
Требуется corrective candidate с единым privacy enforcement в обоих chat entrypoints и повторная независимая приёмка всех четырёх защит. Исправление поставлено A2/4013; WEB-670 остаётся in_progress.
2026-09-15T13:57:23.085Z · coordinator[15.09 13:57Z координатор] [15.09 13:47Z координатор] Независимая приёмка 4018: VERDICT=INCOMPLETE, пакет и SHA проверяются отдельно. Exact parent RED → candidate GREEN для реального `/api/chat-global` повторены 2/2; restricted support/timeline отказывают до ACL/RAG/provider/direct-tool, downstream counters = 0. Notebook `chatWithSources` использует ту же role-privacy политику. Сохранённые защиты: dead gate 7/7, telephony validity 5/5, notebook privacy 6/6, direct-tool wiring 1/1, gateway module redaction 8/8. Единственный незакрытый обязательный пункт — byte-level Fastify gateway test: на M4 не найдено нужных зависимостей, package install запрещён, module-level результат не подменяет его. WEB-670 остаётся in_progress; следующий шаг — найти существующее совместимое dependency tree и выполнить только этот контроль либо исправить реальный дефект, если он воспроизведётся.
2026-09-15T22:33:19.008Z · coordinator[15.09 22:33Z координатор] WEB670-4136-BLOCKED-NO-TREE
## 15.09.2026 22:29Z — Neo/Luna 4136, точный остаток
Вердикт: **BLOCKED_NO_TREE**, не PASS и не NO-GO кода.
Единственный оставшийся обязательный byte-level Fastify control не запускался. На Neo проверены 58 известных project `node_modules` roots: установленного `fastify` нет ни в одном (`DIRECT_FASTIFY_COUNT=0`, `PNPM_FASTIFY_COUNT=0`). В дереве кандидата `/Users/limamarty/waves/wt-3944-acc` `services/realtime-gateway/package.json` объявляет `fastify ^5.12.1`, lockfile фиксирует `5.12.1`, но ни root, ни gateway `node_modules` не существуют. M4 ранее была проверена исходной приёмкой и также не имела дерева.
Тест не подменён module-level результатом. Установка пакетов, изменение lockfile, рестарт сервисов и работа на A1/A2 не выполнялись. Точный будущий запуск после предоставления совместимого dependency tree:
`cd services/realtime-gateway && pnpm exec tsx --test test/gateway.integration.test.ts`
Пакет 4136: `WEB670FASTIFYTEST-REPORT.md` + 7 evidence-файлов; корневой `SHA256SUMS` содержит ровно эти 8 путей, проверка 8/8 OK. DONE-маркер намеренно отсутствует: по брифу он разрешён только если control реально исполнился.
Первый шаг нулевого агента: предоставить существующее совместимое dependency tree на Neo/M4 либо отдельно разрешить его воспроизводимое provisioning; затем выполнить ровно один byte-level control и записать GREEN/RED. До этого WEB-670 остаётся `in_progress`.
2026-09-19T15:58:36.811Z · coordinator[POST-QA 4211 AUDIT COMPLETE 19.09]
Fresh read-only DeepSeek Pro audit 4211 completed from the full immutable body+comment snapshot. Output SHA256SUMS readback PASS; manifest SHA-256 `eef44e99f84b858af013057c17731a4cba0e0ce5886664167507eba15afa51f1`. Disposition: `NEEDS_ACCEPTANCE`. No status change is safe now; keep `in_progress`.
What remains unproved:
- Byte-level Fastify gateway test (test/gateway.integration.test.ts) unexecuted — no fastify dependency tree on Neo (DIRECT_FASTIFY_COUNT=0, PNPM_FASTIFY_COUNT=0) or M4.
- Live activation of every guard in production not proven (no deploy/restart/live receipt).
- The 'hidden mine' token-leak guard (item 4) is proven only at module-level redaction, not byte-level against the running gateway.
One bounded next action: Provide an existing compatible Fastify dependency tree (or authorize reproducible provisioning), then run exactly one byte-level control: cd services/realtime-gateway && pnpm exec tsx --test test/gateway.integration.test.ts, recording GREEN/RED.
Target evidence: A GREEN/RED byte-level gateway test receipt; then independent acceptance of all four guards + live activation.
This audit changed no board data and made no production claim outside the snapshot. Closure still requires ticket-specific evidence and coordinator readback.
2026-09-19T16:00:37.538Z · coordinator[WEB-670 4213 FASTIFY CONTROL STARTED 19.09]
Fresh DeepSeek Pro task 4213 is active on M1 from the exact 152 KiB `services/realtime-gateway` candidate slice copied from Neo. Immutable input checksum readback PASS; input manifest `ee395ef970144f9c20d13f8a763b146df43a112cc362d16e429e95d5ad6d7ff5` (24 files).
Scope is only the missing byte-level Fastify control `pnpm exec tsx --test test/gateway.integration.test.ts`. Dependency materialization is restricted to `pnpm install --offline --frozen-lockfile` in a disposable output copy; no network, global install, live host, provider, board, or production access. Missing offline packages must produce `BLOCKED_NO_OFFLINE_DEPENDENCIES`, not an improvised green.
Maximum positive verdict is `CONTROL_GREEN_FOR_FRESH_ACCEPTANCE`; it still does not authorize landing, restart, status change, or closure. Fresh independent acceptance of all four guards and live activation evidence remain required.
2026-09-19T16:12:47.313Z · coordinator[WEB-670 4213 BLOCKED_NO_OFFLINE_DEPENDENCIES 19.09]
DeepSeek Pro control 4213 completed `BLOCKED_NO_OFFLINE_DEPENDENCIES`. Coordinator readback: output `SHA256SUMS` fully PASS; manifest SHA-256 `bd15fd48fec13c34698e2b15605ff1f86ba00fdb7060eb2d49ac06166635426f`; immutable candidate tree digest `4eeaf1035f4543fc0623b4618d8fb52198949ef7d8ca79ff912b661c487757f7`.
The literal package-local `pnpm install --offline --frozen-lockfile --ignore-workspace` failed closed with `ERR_PNPM_NO_OFFLINE_TARBALL` at `@lukeed/ms@2.0.2`; the Fastify tree and `tsx@4.23.12` are absent. Therefore `pnpm exec tsx --test test/gateway.integration.test.ts` was NOT_EXECUTED. Four independent negative controls all refused a false green.
Separate coverage finding: the candidate Fastify test reaches the real byte-level gateway path, but sets logging to `silent` and contains no assertion that room-token/Authorization material is redacted. Even a future green of this test alone cannot prove guard 4.
No status change or closure. Next bounded action: locate an existing compatible dependency tree without network/install; then execute the exact gateway test plus a real byte-level redaction assertion, followed by fresh independent acceptance and separate live activation evidence.
2026-09-19T16:24:25.282Z · coordinator[WEB-670 4216 AUTHOR REDACTION CONTROL STARTED 19.09]
No exact compatible Fastify dependency tree was found on A1, A2, M4, or Neo. Narrow DeepSeek Pro author task 4216 is active on M1 from exact 4213 inputs+evidence, combined immutable input manifest `c3bebc7cf4fb7518b3d9b244225225ae2d68b644eda5e024332daffdb781c3e6` (2959 files).
Its disposable install is frozen-lockfile, package-local, and build scripts disabled; it must record registry/integrity receipts. Scope is the original real Fastify gateway integration plus a new byte-level redaction assertion that proves room-token/Authorization material is absent from emitted logs. Maximum positive verdict is author GO for fresh independent acceptance — no landing, restart, live activation, status change, or closure.
2026-09-19T16:31:48.841Z · coordinator[DEEPSEEK EXECUTOR BLOCKED 402 19.09 16:28Z]
Executor-level refusal before task completion: `API Error: 402 Insufficient Balance` from `deepseek-v4-pro`. No terminal marker, sealed result package, code verdict, independent verdict, live action, or production evidence was produced. This is not `REWORK` and not a test failure. Existing accepted evidence remains the last valid boundary; status is unchanged. Resume only from the already checksum-verified immutable input after DeepSeek access is restored (or after an explicit routing decision).
2026-09-19T16:38:41.785Z · coordinator[DEEPSEEK RESTORED; CLEAN RETRIES STARTED 19.09 16:36Z]
WEB-670 author control resumed in a fresh workspace after confirmed DeepSeek health probe. Immutable input manifest `c3bebc7cf4fb7518b3d9b244225225ae2d68b644eda5e024332daffdb781c3e6` re-read PASS. Previous 4216 executor-refusal directory remains untouched. Maximum positive verdict remains author GO for fresh independent acceptance; no landing or closure.
2026-09-19T16:56:05.636Z · coordinator[4218 AUTHOR GO; 4223 INDEPENDENT STARTED 19.09]
4218 sealed author package read back completely: root manifest SHA-256 `e86e0e1b26b0ba0e4cb26c43080102b77cd29026b5346ee74c1d340f099f2d1e`, all entries PASS. Claim is `GO_FOR_INDEPENDENT_ACCEPTANCE`: original gateway test 2/2, new byte-level redaction test 1/1, six negative controls refuse, mutation removing the real redact config turns RED, patch adds one test file only. This is author evidence, not closure.
Fresh DeepSeek Pro independent acceptance 4223 is active on M1 from 8,281 immutable input files, transport manifest `60e6c6c151b26a6b90da9333ce8620f3a43a9b0ae6da070efb5ce66b7ec3c12b`. It must rebuild from pristine input, re-run offline/frozen tests, challenge at least 10 controls, map all four guards, and classify the stale author identity (`4216-REPORT.md`/`4216_DONE` inside retry workspace 4218). Maximum verdict is `GO_FOR_CONTROLLED_LIVE_EVIDENCE`; no activation, landing, status change or closure is authorized.
2026-09-19T17:18:11.604Z · coordinator[4223 INDEPENDENT REWORK 19.09 17:17Z]
Independent package checksum readback PASS, root manifest `6c170018fda29fe99cc0fc2c0419d7c790fc2342362c56eb856a6bb1c62fcf0d`. Technical redaction acceptance passes: pristine one-file patch, frozen offline install, original 2/2 + new byte-level 1/1 tests, 11 adversarial controls, removal of the actual logger `redact` decision turns the unchanged test RED and exposes plaintext. Verdict is nevertheless `REWORK`: the sealed author retry identifies itself as 4216 (`4216-REPORT.md`, `4216_DONE`, 9 files naming 4216, 0 naming 4218) and claims 2959/2959 input entries, while the coordinator 4218 transport manifest has 8281 entries. A fresh consumer cannot bind the test execution to the claimed 4218 package. No landing/restart/live activation/closure is authorized. Required next step: narrow author repackage/readback bound to the exact 4218 transport identity, then fresh independent acceptance.
2026-09-19T18:02:32.860Z · coordinator[4229 EXACT-4218 REPACKAGE GO; 4233 INDEPENDENT STARTED 19.09]
4229 sealed checksum readback PASS, root manifest `d3a94fd536df341f6687e48b6079f8fa2b7d7a2f2fb7204e5a2c76ba35854b96`; exact 4218/4223 provenance verified (8291/8291 transport, 8281/8281 input, 7/7 prior output). Verdict `GO_FOR_INDEPENDENT_ACCEPTANCE`: gateway 2/2, byte-level redaction 1/1, real redact removal turns RED and emits plaintext, 12 adversarial controls including buildGateway-failure cleanup. No production file changed; A1/A2/build/landing/restart/live activation NOT_EXECUTED. Fresh independent acceptance 4233 is active on M4 from 19141 immutable files, transport `5c8d096b822887d1b87e9ec196ed733fb956238d02222b692eaaabe4d22bc6e0`. Ticket remains in_progress; live evidence/activation/closure await terminal independent verdict.
2026-09-19T18:22:59.321Z · coordinator[4233 INDEPENDENT GO; CANDIDATE ABSENT FROM PROD 19.09]
4233 sealed independent acceptance readback PASS, root manifest `7da3e8a49d17e131d67ce0e679c5828984ab9c81e6b03df5567865d40803fdab`; verdict `GO_FOR_CONTROLLED_LIVE_EVIDENCE`. Exact provenance chain verified; gateway 2/2, redaction 1/1, full suite 14/14; 16 independent controls + 12 load-bearing mutations; removal of real redact decision leaks plaintext and turns RED. This proves only the byte-level gateway guard offline.
Coordinator restored candidate 4013 from its verified bundle and created durable A1 ref `refs/waves/4013/fix/4013-web670-global-privacy` = `11c660f9dcb2e9da10c544af1422dc43915d87e3`. Fresh comparison to production `l115q/cc278e1810e1e03ac277b8e3a5fe06a2aebfba30`: candidate is NOT an ancestor; `git cherry` marks all five commits `+` (no patch-equivalent landing). Therefore production live evidence cannot yet be claimed. Next bounded step is exact l115q transplant + controlled stand/live evidence for all four guard families, then landing and production verification. Ticket remains in_progress.
2026-09-19T21:03:09.876Z · coordinator[HANDOFF 2026-09-19T20:46Z — 4248 REWORK → 4251 r3 repair]
4248/M1 independent terminal: REWORK, exit 0; manifest PASS 133/133, SHA-256 `cbcc97947dfdbbc655aef6d84e5d7930bad3c347079cc7dafb2d333774553809`, completion covered, self-entry 0, `*_DONE` 0. Fresh controls found two repaired-path defects: actual Fastify/pino B06 leaks top-level mixed-case `Token`/`Authorization` fixture bytes, and global direct-external receives the earlier personal-scope refusal instead of the external-source refusal contract. Broad suite remains honestly 9/20, full-root typecheck OOM 137/not run, one mock skip, sealed mutation m09 uncaught. Exact sealed 4248 input/output were copied and read back into a new M1 workspace. 4251/Codex Luna high repairs only these two decisions; maximum GO_FOR_INDEPENDENT_ACCEPTANCE. Build/landing/live NOT_EXECUTED.
2026-09-19T21:48:15.024Z · coordinatorCOORD-4251-ACCEPTED-4253-ACTIVE-20260919
Author repair 4251 passed coordinator readback: SHA256SUMS PASS 128/128, manifest 8a3ef73e37be71d34dff6e9b26e161eb4528f9e00ac373b8d8b82e40d53dabbd, self-entry 0, DONE entries 0; verdict GO_FOR_INDEPENDENT_ACCEPTANCE. It repairs mixed-case Fastify/pino redaction and global direct-external refusal ordering. Build/landing/live were NOT_EXECUTED.
Fresh independent Luna acceptance 4253 is active on Neo. WEB-670 remains in_progress; no build or landing is authorized before its terminal verdict and coordinator readback.
2026-09-20T03:21:37.333Z · coordinator[20.09 03:21Z координатор] [WEB-670 ЭВОЛЮЦИЯ 20.09 — 4253 INCOMPLETE, окружение поставлено, 4332 в очереди]
ПОЛНАЯ ЭВОЛЮЦИЯ WEB-670 — для агента, который видит этот тикет впервые.
О ЧЁМ ТИКЕТ. Логи не должны печатать секреты. Речь про редактирование чувствительных заголовков в шлюзе реального времени, который построен на Fastify с логгером pino.
ШАГ 1. Волна 4245 (M4) — вердикт GO_FOR_INDEPENDENT_ACCEPTANCE, манифест 63/63, починенная голова 4741f156d0c7e4cd14be1de86d7d0f4e7b7891f6. Зелёные авторские счётчики честно не скрыли остаток: широкий набор chat-global 9 из 20, полный типовой разбор по корню упал по памяти (код 137), один мок пропущен.
ШАГ 2. Волна 4248 (M1) — независимая приёмка, вердикт REWORK. Манифест 133/133, SHA-256 cbcc97947dfdbbc655aef6d84e5d7930bad3c347079cc7dafb2d333774553809. НАШЛА ГЛАВНОЕ: на НАСТОЯЩЕМ Fastify с pino пропускались заголовки ВЕРХНЕГО УРОВНЯ в смешанном регистре — Token и Authorization. Это обозначено как дефект B06. Плюс глобальный внешний путь получил неверный приоритет персонального отказа. Вывод, который стоит запомнить: дефект виден только на настоящей библиотеке, на подделке его не видно.
ШАГ 3. Волна 4251 (M1) — точечный ремонт r3. Первая строка отчёта GO_FOR_INDEPENDENT_ACCEPTANCE. Голова r3 = 178271b067c0fc47c2837f91ab1668f35ee4a334, база = cc278e1810e1e03ac277b8e3a5fe06a2aebfba30 (линия l115q), отвергнутый кандидат 3f5e072b6024116175978caed2d9f67e92472741. Правка в шлюзе — ровно три файла: services/realtime-gateway/src/log-redaction.ts (новый, 212 строк), services/realtime-gateway/src/app.ts, services/realtime-gateway/test/log-redaction.test.ts.
ШАГ 4. Волна 4253 (Нео) — независимая приёмка, вердикт INCOMPLETE. Манифест 143/143, SHA-256 645e8aad50c67a3716b23757f3bb9c9eb17c21ec37e41dba3377422df2cd45a9, записей о себе 0, записей DONE 0. ЛОГИКА r3 ПРОВЕРЕНА ХОРОШО: свежие независимые контроли 36/36, глобальный помощник маршрута 5/5, мутации 18/18 пойманы без ошибок харнесса, разбор изменённых файлов 19/19, сверка diff прошла. НЕ ИСПОЛНЕНО ровно одно — поведение на настоящей библиотеке:
real_logger_bytes: NOT_EXECUTED: missing fastify/pino dependency
gateway_typecheck: NOT_PASS: tsc unavailable
gateway_tests: NOT_PASS: fastify unavailable
Ставить зависимости волне было запрещено, поэтому она честно остановилась. ЭТО БЫЛ ПРОБЕЛ ОКРУЖЕНИЯ, А НЕ ДЕФЕКТ ПАКЕТА. Отдельно осталось непроверенным: широкий набор chat-global 10 из 20 (упирается в отсутствующий server-only на стороне приложения) и полный типовой разбор по корню (падает по памяти).
ПОЧЕМУ ЗАВИСИМОСТИ НЕ НАШЛИСЬ. fastify не объявлен в корневом package.json и не установлен нигде в парке. Он объявлен в СВОЁМ пакете рабочего пространства services/realtime-gateway (имя @waves/realtime-gateway, свой pnpm-lock.yaml, всего 164 КБ исходников). pino отдельным пакетом не ставится вовсе — он внутри fastify, поэтому импортировать pino напрямую нельзя, байты нужно снимать через настоящий экземпляр Fastify и его поток логгера.
ЧТО СДЕЛАНО СЕЙЧАС (20.09 03:1xZ) — координатор устранил пробел окружения, потому что у волн нет прав на установку, это работа координатора.
Поставлено на A2, корень /home/ubuntu/web670-gateway-env:
- ENVIRONMENT-PIN.txt — закреплённые версии: node v22.23.2, pnpm 10.25.0, fastify 5.12.1, @fastify/cors 11.3.0, @fastify/rate-limit 11.2.0, @fastify/websocket 11.3.0, redis 6.2.1, ws 8.21.3, tsx 4.23.12, typescript 5.9.3.
- src-tree/ — дерево пакета шлюза с установленным node_modules. НА НЕПРАВЛЕНОМ ДЕРЕВЕ КООРДИНАТОР ПРОВЕРИЛ: tsc --noEmit rc=0 и tsx --test 13/13 прошли. Это базовая точка отсчёта, чтобы следующая волна не встала снова.
- repo/ — нейтральная копия репозитория с ЗАКРЕПЛЁННЫМИ ссылками web670-base (cc278e1810…) и web670-r3 (178271b067…). Ссылки созданы намеренно: непривязанный коммит сносит сборщик мусора, это уже случалось.
- material/ — 4251-r2-to-r3.patch (sha256 5612bf7cf59b34974909d8273db023badaa25c444b5f476652427667233e2527), 4251-r3-repaired-head.bundle (sha256 232f1f0ac7ebd767549a1fcdd4075190287ceef36b9e92c73d822d503fa78a03), отчёты 4251 и 4253.
ЛОВУШКА ПРИ ПОВТОРЕНИИ: бандл 4251-r3-repaired-head.bundle ИНКРЕМЕНТНЫЙ, он требует предка cc278e1810…; в пустом репозитории git скажет «Repository lacks these prerequisite commits» — забирать его только в копию, где база уже есть.
ВОЛНА 4332 ПОСТАВЛЕНА В ОЧЕРЕДЬ A2 (Codex Luna, high, SOLO), ждёт освобождения машины после 4331. Задача: наложить на подготовленное дерево ТОЛЬКО версию шлюза из web670-r3, прогнать tsc --noEmit и тесты шлюза включая новый log-redaction.test.ts, и снять НАСТОЯЩИЕ БАЙТЫ логгера на живом экземпляре Fastify по шести семействам случаев: заголовок верхнего уровня Authorization во всех регистрах; то же для Token; те же имена внутри вложенных объектов и массивов; в строке запроса и разобранном URL; значение не-строка (число, null, объект); повторяющийся заголовок. Обязателен НЕГАТИВНЫЙ КОНТРОЛЬ: та же батарея на НЕправленом дереве обязана показать утечку B06, иначе батарея ничего не проверяет. Плюс минимум четыре мутации редактирования, каждую батарея обязана поймать. Ставить зависимости волне запрещено — всё уже стоит. Сдача: /home/ubuntu/waves/4332WEB670BYTES-REPORT.md, доказательства 4332WEB670BYTES-evidence с манифестом SHA256SUMS, бандл, маркер WEB670BYTES_DONE. Максимум, что даёт волна — GO_FOR_CANDIDATE_BUILD; сборку, посадку и живые проверки она не делает.
ЧТО ОСТАЛОСЬ ПОСЛЕ 4332. Если байты чистые — собрать кандидата и провести посадку по обычному порядку. Остаток по chat-global (server-only) и полный типовой разбор по корню закрываются отдельно и в этот тикет не входят; называть их вслух как непроверенные, а не как пройденные.
ЧЕГО ДЕЛАТЬ НЕЛЬЗЯ. Не проверять редактирование на подделке логгера — именно так был пропущен B06. Не импортировать pino напрямую. Не принимать зелёные счётчики без негативного контроля на базе. Не переустанавливать зависимости в волне: версии закреплены и базовые проверки на них уже сняты. 2026-09-20T03:47:56.817Z · coordinator[20.09 03:47Z координатор] [WEB-670 4332 GO — настоящие байты Fastify, негативный контроль на базе течёт 12/12]
ВОЛНА 4332 — ГЛАВНЫЙ ПРОБЕЛ ЗАКРЫТ. VERDICT=GO. Манифест доказательств 14/14, SHA-256 0708bc895a805cfee523684b4824c651b3b060f5d5de46b3bd78ad6b97af53b1, записей о себе 0, записей DONE 0.
ЧТО ИМЕННО ДОКАЗАНО. Приёмка 4253 остановилась на том, что не было настоящей библиотеки Fastify. Координатор поставил окружение, волна 4332 отработала на нём и сняла НАСТОЯЩИЕ БАЙТЫ логгера.
Личность дерева. В подготовленное дерево наложены ровно три файла из коммита 178271b067c0fc47c2837f91ab1668f35ee4a334, с хешами до и после:
- src/app.ts — до b8f4c968…, после c2d056c1f3859e6f6c9367760e5f14d48f3a6d807b356eb837d651045e4c1a40;
- src/log-redaction.ts — до отсутствовал, после 62a49f4b5425401899757c3ae138e6a6621a5f0d0bd29215eca317fdb18c3073;
- test/log-redaction.test.ts — до отсутствовал, после 73963921b2709254d4fbde2befcd0fefa5f3b1fae161d842c6f4bd00dbc3c1d1.
Все три совпали с хешами содержимого соответствующих путей r3, сверка с blob ID коммита записана в evidence/applied-files-readback.json. node_modules не переустанавливался, хеши package и lock совпали с закреплённым pin-файлом.
Проверки. tsc --noEmit — код выхода 0. tsx --test — код выхода 0, 18 пройдено, 0 упало, 0 отменено, 0 пропущено.
Настоящие байты. Жгут поднимал настоящий Fastify 5.12.1, слал запросы через node:http и забирал байты из потока логгера Fastify/pino. Для каждого из 12 случаев сохранены точный сконфигурированный запрос, фактические заголовки и URL по проводу, и весь поток байтов в hex, base64 и utf8.
- На r3: 12 из 12 — NO_LEAK, ни один записанный поток не содержит секрет.
- На БАЗЕ: 12 из 12 — LEAK. Это и есть то, что делает результат осмысленным: негативный контроль НЕ ПУСТОЙ, батарея действительно что-то проверяет.
- В частности, база пропускает дефект B06 для смешанного регистра заголовков верхнего уровня — ровно тот дефект, который независимая приёмка 4248 нашла на настоящей библиотеке и который на подделке логгера не виден.
ОКРУЖЕНИЕ, которое теперь можно переиспользовать. /home/ubuntu/web670-gateway-env на A2: ENVIRONMENT-PIN.txt с закреплёнными версиями (node v22.23.2, pnpm 10.25.0, fastify 5.12.1, @fastify/cors 11.3.0, @fastify/rate-limit 11.2.0, @fastify/websocket 11.3.0, redis 6.2.1, ws 8.21.3, tsx 4.23.12, typescript 5.9.3), src-tree с установленным node_modules, repo с закреплёнными ссылками web670-base и web670-r3, material с патчем и бандлом. Ловушка: бандл 4251-r3-repaired-head.bundle инкрементный, в пустом репозитории даёт «Repository lacks these prerequisite commits» — забирать только в копию, где база cc278e1810 уже есть.
ЧТО ОСТАЛОСЬ. Максимум, который эта цепочка даёт — GO_FOR_CANDIDATE_BUILD. Дальше: сборка кандидата и посадка обычным порядком. НЕ закрыто и закрывается отдельно, не в этом тикете: широкий набор chat-global (упирается в отсутствующий server-only на стороне приложения) и полный типовой разбор по корню (падает по памяти). Называть их вслух как непроверенные, а не как пройденные.
ЧЕГО НЕ ПОВТОРЯТЬ. Не проверять редактирование на подделке логгера — именно так был пропущен B06. Не импортировать pino напрямую, он внутри fastify. Не принимать зелёные счётчики без негативного контроля на базе: здесь он дал 12 из 12 утечек и только поэтому GO означает что-то.
2026-09-20T06:11:10.542Z · coordinator[20.09 06:11Z координатор] [WEB-670 — доказан и не посажен; 4354 готовит план посадки и отката]
ВОЛНА 4354 ПОСТАВЛЕНА НА A1 — план посадки. Линия доказана полностью и до сих пор не доехала до прода; пока правка не установлена, секреты продолжают утекать в логи.
Напоминание фактов: волна 4332 сняла НАСТОЯЩИЕ байты логгера на живом Fastify 5.12.1 — на исправленной версии утечек нет во всех 12 случаях, на базовой утечки во всех 12; негативный контроль не пустой, типизация чистая, тесты 18/18. Правка — ровно три файла пакета services/realtime-gateway: src/log-redaction.ts (новый), src/app.ts, test/log-redaction.test.ts. Голова 178271b067c0fc47c2837f91ab1668f35ee4a334, база cc278e1810e1e03ac277b8e3a5fe06a2aebfba30.
Главный вопрос волны: КАК шлюз реального времени попадает на прод — он часть основного артефакта линии (тогда нужна пересборка всей линии и обычная посадка) или отдельная служба со своей сборкой (тогда посадка несравнимо легче). Ответ требуется по фактам машины, а не по предположению.
Волна обязана: найти, что именно исполняется в проде для шлюза (юнит или процесс, рабочий каталог, команда запуска, порт) и чем это установлено; понять, откуда берутся его байты (tsc в dist, общий артефакт, иное) и обновляется ли он ВООБЩЕ при обычной посадке линии — мы уже обжигались на периодических юнитах вне списка посадки, которые гнили молча; сравнить ЖИВЫЕ байты шлюза с версией из коммита cc278e1810 и назвать любое расхождение точно, потому что живой шлюз раньше расходился с git в обе стороны; написать план посадки по шагам с командами, ожидаемым результатом и признаком неудачи, включая проверку что редактирование работает на ЖИВЫХ байтах, а не только в тестах; написать план отката с точными путями; назвать риски, в том числе обрыв соединений реального времени при перезапуске и окно недоступности; и отдельной строкой назвать всё, что упирается в решение владельца.
Волна НИЧЕГО не сажает, не перезапускает и не меняет — только читает и планирует. Отдельно ей запрещено печатать содержимое переменных окружения, ключей и токенов: при чтении окружения обязателен фильтр. Максимум — план, готовый к исполнению.
2026-09-20T06:46:35.537Z · coordinator[20.09 06:46Z координатор] [WEB-670 ПОПРАВКА — шлюза Fastify на проде НЕТ; 4332 доказал тестовое окружение, не прод]
ВАЖНАЯ ПОПРАВКА К СТАТУСУ ЭТОГО ТИКЕТА. Волна 4354 (VERDICT=NO-GO, манифест 7/7, отчёт sha256 93db37ac44c0401ef60a56890fec488e67b99370bd194e137dbad4d13b5190bf) установила факт, который меняет смысл всей линии.
ОТДЕЛЬНОГО ШЛЮЗА FASTIFY НА ПРОДЕ НЕТ.
На боевой машине исполняются nc-a1.service и nc-a1-b.service, оба next-server (v16.2.11) из каталога установленного релиза arm64-l115q-20260915T230431Z, порты 3010 и 3012. Nginx направляет /api/realtime в Next-бэкенд на 3010. У пакета services/realtime-gateway есть своя сборка (pnpm build → dist/, node dist/server.js), но на боевой машине НЕТ ни его юнита, ни процесса, ни слушателя, ни хука доставки, ни маршрута Nginx. Порт 3210 не слушает.
СЛЕДСТВИЕ, которое надо зафиксировать прямо, чтобы никто позже не прочитал историю неверно: доказательство волны 4332 — где на настоящем Fastify 5.12.1 утечек не было во всех 12 случаях, а на базовой версии были во всех 12 — относится к ОТДЕЛЬНОМУ пакету и его тестовому окружению. Это НЕ доказательство того, что происходит с логами на проде. Прод обслуживает другой код: legacy Next realtime.
Поэтому требуемое сравнение «живые байты шлюза Fastify против коммита cc278e1810e1e03ac277b8e3a5fe06a2aebfba30» имеет результат N/A — живого шлюза Fastify не существует, а не SAME или DIFF. Кандидат WEB-670 не мог быть доставлен обычной посадкой основной линии, и целевых путей службы, копирования, перезапуска и отката попросту нет.
Это тот же класс ошибки, на котором мы уже обжигались: исправление в линии не означает, что оно живёт на шлюзе, а код вне артефакта не попадает на прод.
ЧТО ПОСТАВЛЕНО. ВОЛНА 4357 НА БОЕВОЙ МАШИНЕ, только чтение и разбор, ничего не сажает и не перезапускает. Вопрос переформулирован с «как посадить исправление» на «ТЕЧЁТ ЛИ ЖИВОЙ ПУТЬ ВООБЩЕ». Волна обязана: пройти от Nginx до обработчика и назвать файлами и строками, какой код на самом деле принимает /api/realtime; найти, какие поля запроса попадают в журнал и есть ли там редактирование чувствительных полей и в каком регистре; ОТДЕЛЬНО ответить, покрывает ли живой путь те случаи, на которых в пакете шлюза нашли дефект B06 — заголовки верхнего уровня Token и Authorization в смешанном регистре; проверить НАБЛЮДЕНИЕМ, а не рассуждением: послать по живому пути СВОИ синтетические значения вида Bearer SYNTH-4357-NOT-A-REAL-TOKEN во всех четырёх регистрах имени и найти в журналах следы именно этих строк; сказать, куда пишется журнал, кто его видит, сколько хранится и уходит ли наружу, потому что утечка в файл на одной машине и утечка во внешнюю систему — проблемы разного размера.
Волне отдельно запрещено слать настоящие секреты и печатать содержимое настоящих переменных окружения, ключей и токенов; при чтении окружения обязателен фильтр.
Дальше возможны два исхода, и оба меняют план: живой путь НЕ течёт по проверенным случаям — тогда исправление шлюза не срочное и надо отдельно решать, нужен ли Fastify-шлюз на проде вообще; живой путь ТЕЧЁТ — тогда правку надо переносить в него, и волна обязана назвать точное место и сказать, применима ли туда логика из services/realtime-gateway/src/log-redaction.ts.
Отдельным файлом волна напишет честную сводку «что доказано 4332, что из этого относится к проду, а что нет» — она пойдёт в этот тикет.
2026-09-20T07:11:46.838Z · coordinator[20.09 07:11Z координатор] [WEB-670 ОТВЕТ — на живом пути заголовки в логи НЕ попадают, проверено наблюдением]
ОТВЕТ НА ГЛАВНЫЙ ВОПРОС: НА ЖИВОМ ПУТИ ЗАГОЛОВКИ В ЛОГИ НЕ ПОПАДАЮТ. Проверено наблюдением координатором, потому что у волн нет прав на журнал.
Волна 4357 (VERDICT=NO-GO, манифест 6/6, SHA-256 ac36d80e869d3be0f804c254cc0b9d165004ec159081b1a30dddbba487474c73) установила живой путь и сделала пробы, но честно не смогла закрыть требование наблюдения: у её пользователя нет групп adm и systemd-journal, а sudo запрещён политикой no new privileges. Вердикт NO-GO поставлен правильно — без наблюдения GO давать нельзя.
ЧТО УСТАНОВИЛА ВОЛНА ПО ИСХОДНИКАМ. Nginx app.sixbyy.com закрепляет /api/realtime и /api/realtime/ на Next 127.0.0.1:3010; смежные realtime API — Next App Router в src/app/api/realtime/**. Статический исходник НЕ содержит общего логгера сырого запроса: маршрут Next пишет только точечные операционные метаданные и ошибки, Nginx access log пишет URI и строку запроса, но НЕ заголовки и НЕ тело. В пакете Fastify пути редактирования покрывают только authorization, а Token не покрыт — но это не живой код. Четыре безопасные пробы выполнены с синтетическими значениями в Authorization/authorization/Token/token; все вернули 401 до отправки провайдеру.
ЧТО ПРОВЕРИЛ КООРДИНАТОР. Пользователь ubuntu на боевой машине входит в группу adm, journalctl и /var/log/nginx/access.log читаются.
- Пробы ДОШЛИ до прода: в access.log за 20/Sep/2026:06:47:52 три запроса GET /api/realtime?__4357_probe=auth_lower|token_upper|token_lower, все 401.
- Приложение ОТРЕАГИРОВАЛО и записало в журнал в ту же секунду: стек маршрута .next/server/app/api/realtime/route.js с code: 'AUTH_REQUIRED' и reason: 'authenticated session is missing'.
- И при этом за три часа: строк с SYNTH — 0, строк с Bearer — 0, строк с именем поля authorization/token — 0. В ОБОИХ бэкендах, nc-a1 и nc-a1-b. В nginx access.log совпадений SYNTH тоже 0.
Важно, почему это доказательство, а не тишина: запрос дошёл, приложение на него отреагировало и написало в журнал операционную запись — и в этой записи заголовков нет. Если бы живой путь логировал заголовки, синтетическая метка была бы видна.
ОСТАТОК, который надо назвать честно: проверен путь НЕаутентифицированного запроса — пробы отсекались на аутентификации до отправки провайдеру. Поведение логирования на аутентифицированном пути этой проверкой не покрыто и остаётся открытым.
ВЫВОД ПО ТИКЕТУ. Срочности нет: секреты в логи на проверенном живом пути не утекают. Исправление 4332 остаётся доказанным для пакета services/realtime-gateway, но этот пакет на проде не исполняется. Отдельным решением остаётся вопрос, нужен ли шлюз Fastify на проде вообще; пока он не запущен, WEB-670 не является блокером безопасности.
2026-09-20T09:05:25.419Z · coordinator[20.09 09:05Z координатор] [WEB-670 ПОЛНАЯ КАРТИНА 20.09 — три разворота, ответ про утечку, состояние 4371]
ПОЛНАЯ КАРТИНА ПО ЭТОМУ ТИКЕТУ НА 20.09 — для агента, который придёт с нуля. Здесь было три разворота, и каждый менял смысл предыдущего.
РАЗВОРОТ 1 — что доказано. Волна 4332 сняла НАСТОЯЩИЕ байты логгера на живом Fastify 5.12.1: на исправленной версии утечек нет во всех 12 случаях, на базовой утечки во всех 12. Негативный контроль не пустой, значит проверка действительно проверяет. Типизация чистая, тесты 18/18. Манифест 14/14, SHA-256 0708bc895a805cfee523684b4824c651b3b060f5d5de46b3bd78ad6b97af53b1. Правка — ровно три файла пакета services/realtime-gateway: src/log-redaction.ts (новый), src/app.ts, test/log-redaction.test.ts. Голова 178271b067c0fc47c2837f91ab1668f35ee4a334, база cc278e1810e1e03ac277b8e3a5fe06a2aebfba30.
РАЗВОРОТ 2 — доказано не там, где думали. Волна 4354 установила: ОТДЕЛЬНОГО ШЛЮЗА FASTIFY НА ПРОДЕ НЕТ. Работают nc-a1.service и nc-a1-b.service, оба next-server v16.2.11 из каталога релиза arm64-l115q-20260915T230431Z, порты 3010 и 3012; Nginx направляет /api/realtime в Next-бэкенд 3010. У пакета services/realtime-gateway есть своя сборка (pnpm build → dist/, node dist/server.js), но на боевой машине нет ни юнита, ни процесса, ни слушателя, ни хука доставки, ни маршрута Nginx; порт 3210 не слушает. Значит сравнение «живые байты шлюза против коммита» даёт N/A, а не SAME или DIFF, и доказательство 4332 относится к ОТДЕЛЬНОМУ пакету и его тестовому окружению, а не к проду.
ОТВЕТ НА ГЛАВНЫЙ ВОПРОС — ТЕЧЁТ ЛИ ЖИВОЙ ПУТЬ. Волна 4357 разобрала живой путь по исходникам и сделала безопасные пробы, но честно вернула NO-GO: у её пользователя нет групп adm и systemd-journal, sudo запрещён политикой no new privileges, поэтому требование наблюдения она закрыть не могла. Проверку доделал координатор, у которого доступ есть.
Факты наблюдения: пробы ДОШЛИ до прода — в access.log за 20/Sep/2026:06:47:52 три запроса GET /api/realtime?__4357_probe=auth_lower|token_upper|token_lower, все 401. Приложение ОТРЕАГИРОВАЛО в ту же секунду и записало в журнал стек маршрута .next/server/app/api/realtime/route.js с code: 'AUTH_REQUIRED' и reason: 'authenticated session is missing'. И при этом за три часа в ОБОИХ бэкендах: строк с SYNTH — 0, строк с Bearer — 0, строк с именем поля authorization или token — 0; в access.log совпадений SYNTH тоже 0.
Почему это доказательство, а не тишина: запрос дошёл, приложение на него отреагировало и написало операционную запись, и в этой записи заголовков нет. Если бы живой путь логировал заголовки, синтетическая метка была бы видна.
ЧЕСТНЫЙ ОСТАТОК: проверен путь НЕаутентифицированного запроса — пробы отсекались на аутентификации до отправки провайдеру. Поведение логирования на аутентифицированном пути этой проверкой НЕ покрыто и остаётся открытым.
РАЗВОРОТ 3 — про ключи, и это была ошибка координатора. Я искал ключи провайдеров и проверил ОДИН файл окружения, после чего заявил, что их нет нигде и что голос на проде не настроен. Владелец опроверг фактом: он позвонил по SIP на 8000 и общался с ассистентом, и получил ответ в чате с тетрадью. Правда: служба грузит семь файлов окружения, ключи лежат в .env.local — OPENAI_API_KEY, GOOGLE_AI_API_KEY, GOOGLE_LIVE_BOOTSTRAP_PROXY_URL. Владелец подтвердил: «Юзайте ключи что вам надо я никогда не запрещал». Вывод «голос не настроен, исключить группу по существу» СНЯТ.
СОСТОЯНИЕ ВОЛНЫ 4371 (полная цепочка realtime с провайдером). Ключи были переданы на стенд без раскрытия: с боевой машины файлом с правами 600 через ноутбук на A2 в /home/ubuntu/waves/4371-secret/provider.env, sha256 ef65ff8fe8cdb904f4dfa3c19c46c751c1f82412946d98304584a6c80602ffcb совпал на обоих концах, промежуточные копии удалены, значения в журнал не попали. Волна запущена, но ОСТАНОВЛЕНА на 6-й минуте по команде владельца «Запускай»: машина A2 понадобилась под стенд замера ёмкости, а realtime в этот замер не входит. Перед остановкой проверено, чем она занята — читала исходники браузерного аудио-сокета, то есть до провайдера не дошла. Расписка 4371-STOPPED.txt: provider_calls_made=0, keys_file_untouched=true. Ключи на месте, хеш не изменился, денег владельца не потрачено. Волну надо будет перезапустить, когда освободится машина.
ЧТО ПРИ ЭТОМ СОБРАНО И ГОДИТСЯ. Волна 4369 (GO, манифест 11/11) собрала транспорт своими силами: свой процесс Node, одноразовая PostgreSQL, синтетическая сессия Auth.js, переменные аренды, флаг MEETING_ROOMS_MROOM1_MULTICHANNEL_ENABLED=1. Наблюдено room-audio:ready с ожидаемым транспортом realtime_fixture_transport_4369_01, расписка готовности записывает matches=true и договор PCM. session-start вернул HTTP 200 с meetingRoomRuntime.status=attached ВО ВСЕХ ДЕСЯТИ независимых циклах, и transport_not_configured не возникал ни разу.
ЧТО ОСТАЛОСЬ ПО ТИКЕТУ. Перезапустить 4371 и провести полную цепочку с провайдером (ключи готовы, транспорт собран, объём ограничен десятью короткими циклами). Отдельно закрыть остаток по логированию на аутентифицированном пути. И отдельным решением — нужен ли шлюз Fastify на проде вообще: сейчас он там не запущен, а исправление 4332 доказано для пакета, который на проде не исполняется.
2026-09-22T18:27:24.016Z · triage-neoРЕШЕНИЕ=in_progress
ОСНОВАНИЕ=Комментарий 5723 от 2026-09-20T09:05Z: 4369 GO по транспорту, 4371 остановлена до вызова провайдера; authenticated-path logging и решение по Fastify остаются открытыми.
ЧТО НУЖНО=Возобновить 4371 после освобождения окна, получить receipt полного пути, закрыть authenticated logging и зафиксировать решение по Fastify; triage-neo 4613
2026-09-23T12:16:46.529Z · coordinator[23.09 12:16Z координатор] ## 4708 (M1, Luna) — в работе: четыре опасные мёртвые защиты (рубильник R14, правила ролей support/timeline, пометка недействительного корпуса телефонии, маскирование токена в URL логов шлюза) — по каждой отрицательный тест (красный на base) + минимальная правка. Три «поспокойнее» — отдельно.
2026-09-23T12:34:05.273Z · coordinator[23.09 12:34Z координатор] ## 4708 (M1, 5/5 OK) — четыре опасные защиты подключены минимальными правками, у каждой отрицательный тест (RED до правки, GREEN после): (1) рубильник R14 читается в `buildRoleEnforcementPlanWithRuntimeGate` (выкл. = прежний rollout, вкл. = принуждение); (2) правила ролей support/timeline (внешние источники запрещены, ПД только по прямому запросу) читаются в политике роли; (3) пометка «настройка корпуса недействительна» → явный отказ/сообщение, а не пустой корпус; (4) токен комнаты маскируется и в URL логов шлюза. Ветка A2 `l115s-web670-dead-guards` (2 коммита). Три «поспокойнее» — отдельно. Независимая приёмка — вместе с WEB-666 (4714). Статус ← review.
2026-09-23T12:50:13.365Z · coordinator[23.09 12:50Z координатор] ## 4714 (M1, независимая приёмка) — **WEB-670 = NO-GO, 3 critical**: защиты подключены на главном пути, но обходятся альтернативными: (1) прямое исполнение инструментов чата без политики роли/приватности (`chat-global/route.ts:951-985`); (2) outbound-prefetch телефонии зовёт внешние инструменты без политики роли (`telephony/outbound/preFetch.ts:297-309`); (3) Signal-привязка корпуса создаёт область без проверки пометки недействительности (`signalCall/binding.ts:101-123`). Маскирование токена и авторские тесты — PASS. Починка — 4719 (M1). Статус ← in_progress.
2026-09-23T13:14:50.314Z · coordinator[23.09 13:14Z координатор] ## 4719 (M1, Luna) — GO: закрыты обходные пути мимо четырёх защит — 24 места исполнения инструментов (все под защитой роли), 10 мест доступа к корпусу (все под корпусным guard); контрольный «подсаженный обход» делает сторожевой тест красным, репродюсер зелёный; целевые наборы role-policy/телефония/chat-global/tool-registry зелёные (5 «падений» = существующие capability-skip в prefetch, не ошибки); изолированный typecheck 0. Патчи (2) наложены на A2 `l115s-web670-dead-guards` поверх 4700. Статус → в ревью, ждёт повторного adversarial-ревью вместе с WEB-666/667.
2026-09-23T13:37:23.167Z · coordinator[23.09 13:37Z координатор] ## 4723 (M1, повторное состязательное ревью трёх наборов) — по WEB-670: **NO-GO**, 2 критичных обхода: (1) `toolRegistry.ts:89-107` спрашивает политику, но `rolePolicyTools.ts:91-97` блокирует только инструменты, у которых в каталоге объявлен `read_external` — новый MCP/динамический инструмент без записи в каталоге исполняется при `allowExternalSources=false` (репродуктор 0001); (2) WhatsApp persisted-session replay `whatsappCall/binding.ts:463-506` собирает ответ из сохранённого JSON без `assertCorpusBindingValid` (у Telegram проверка есть) — невалидная привязка корпуса получает успешный replay (репродуктор 0002). Остальные 16/18 состязательных PASS. WEB-670 → в работу, раунд 3 (4728): default-deny для неизвестных инструментов + ревалидация привязки в WhatsApp replay.
2026-09-23T13:56:40.626Z · coordinator[23.09 13:56Z координатор] ## 4728 (M1, Luna, раунд 3) — GO: оба репродуктора ревью 4723 красные до / зелёные после; каталог инструментов стал allow-list — инструмент без каталожной записи = внешний, default-deny при `allowExternalSources=false` (инструментов без записи в дереве 0); ревалидация привязки корпуса вынесена в общий helper, 11 вызывающих (Telegram, WhatsApp replay и остальные каналы) через него. Область 57/57, typecheck 0. Патчи 0005/0006 наложены на A2 `wt-l115s-web670` поверх 4708+4719. Статус → в ревью; четвёртое независимое ревью — 4730.
2026-09-23T14:12:16.424Z · coordinator[23.09 14:12Z координатор] ## 4730 (M1, 4-е независимое ревью) — WEB-670 р3: **NO-GO**, 1 критичное: `registerTool()` может ПЕРЕЗАПИСАТЬ каталожно-безопасное имя внешней реализацией — политика доверяет записи каталога по имени → deny-external обходится подменой (репродуктор `4730…-evidence/patches/web670-catalog-safe-alias-bypass.test.ts`). → в работу, раунд 4 (4736): регистрация не может заменить каталожное имя; доверие — реализации/источнику, не имени.
2026-09-23T14:32:07.547Z · coordinator[23.09 14:32Z координатор] ## 4736 (M1, Luna, раунд 4) — GO: каталожные имена зарезервированы для bound-регистрации (`catalogId + source` + capability), обычный `registerTool()` их занять/перезаписать не может; политика решает по capability реализации (нет объявления → external/default-deny); единственный явный путь замены `overrideCatalogTool()` с structured warning; повторная регистрация той же реализации idempotent, HMR-замена требует явного override. 39 вызывающих `registerTool` перечислены; репродуктор 4730 красный до / зелёный после; область 146/146; typecheck 0. Патч 0007 наложен на A2 `wt-l115s-web670`. Статус → в ревью (5-е ревью вместе с WEB-682 р2).
2026-09-23T14:52:05.802Z · coordinator[23.09 14:52Z координатор] ## 4740 (M1, 5-е независимое ревью) — WEB-670 р4: **NO-GO**, 1 критичное: у `overrideCatalogTool()` (`toolRegistry.ts:104-110`) нет trust boundary — экспортирован напрямую, источник вызова не проверяет; `registerCatalogTool()` принимает произвольный runtime `source` и capability-объявление, а политика (`rolePolicyTools.ts:99-105`) верит объявлению на слово → плагин/недоверенный модуль подделывает source и объявление (репродуктор `4740…-evidence/patches/web670-override-source-capability-spoof.patch`). Среднее: устаревший sentinel `web4714Adversarial.test.ts:76` (старая сигнатура `enforceRoleToolPolicy`). → в работу, раунд 5 (4742): override только через registrar-authority (токен, выдаваемый при загрузке доверенного модуля регистрации, недоступный плагинам), source provenance канонизировать и аутентифицировать (идентичность модуля, не строка), capability выводить из доверенного реестра реализаций, а не из объявления; sentinel обновить.
2026-09-23T15:15:31.540Z · coordinator[23.09 15:15Z координатор] ## 4742 (M1, Luna, раунд 5) — GO: registrar-authority = приватный Symbol-синглтон в `toolRegistry`, builtin-загрузчик проходит внутренний handshake с фиксированными идентичностями реализаций; публичных экспортов override 0; capability — из реестра реализаций (объявление снаружи игнорируется); sentinel 4714 обновлён и красный на подсаженном обходе; репродуктор 4740 красный до / зелёный после; область 197/197; typecheck 0. Патчи 0008/0009 наложены на A2 `wt-l115s-web670`. Статус → в ревью (6-е ревью 4748 вместе с WEB-439 р2).
2026-09-23T15:32:37.965Z · coordinator[23.09 15:32Z координатор] ## 4748 (M1, 6-е независимое ревью) — WEB-670 р5: **NO-GO**, 2 критичных: (1) `BUILTIN_REGISTRATION_AUTHORITY` достижим через deep-импорт внутреннего модуля — плагин вызывает публичный загрузчик раньше доверенного и регистрирует чужую реализацию; (2) builtin-реализации напрямую импортируемы и исполняемы мимо `executeTool()` (проверки роли/capability обходятся прямым вызовом). → в работу, раунд 6 (4751): authority не экспортируется ни из одного модуля (замыкание при загрузке), реализации — только непрозрачные handle без прямого вызова, прямой импорт реализаций запрещён сторожем импортов.
2026-09-23T15:54:14.269Z · coordinator[23.09 15:54Z координатор] ## 4751 (M1, Luna, раунд 6) — GO: authority не экспортируется ни одним модулем (0), после регистрации builtin-набора реестр «запечатан» (seal необратим в процессе), реализации инструментов не экспортируют исполняемых функций (0) — только описание и handle, исполнение только через `executeTool()`; сторож импортов красный на подсаженном прямом импорте; репродуктор 4748 красный до / зелёный после; область 141/141; typecheck 0. Патчи 0010–0012 наложены на A2 `wt-l115s-web670`. Статус → в ревью (7-е ревью 4757).
2026-09-23T16:11:43.326Z · coordinator[23.09 16:11Z координатор] ## 4757 (M1, 7-е независимое ревью) — WEB-670 р6: **NO-GO** (4 находки, 2 критичных): (1) захват каталога ДО seal — есть entry, где сторонний код исполняется раньше инициализации builtin-набора; (3) provenance политики контролируется вызывающим + обход через helper-функции инструментов. → раунд 7 (4761): builtin-набор регистрируется синхронно при вычислении модуля registry (окна «до seal» нет по построению), контекст политики берётся из аутентифицированной сессии, а не из аргументов вызывающего, helper-ы инструментов — в приватных модулях реестра. Подробности в `4757…-evidence/review.md`.
2026-09-23T16:35:45.917Z · coordinator[23.09 16:35Z координатор] ## 4761 (M1, Luna, раунд 7) — GO: builtin-набор регистрируется синхронно при вычислении модуля реестра (окна «до seal» нет), bootstrap-утверждение seal при старте процесса/worker-а (fail-closed), контекст политики (`rolePrivacy`, provenance) — брендированный, только из аутентифицированной сессии внутри `executeTool()`, 3 side-effect helper-а (`runScheduleAutonomyRun`, `sendListToChannel`, `persistAiSourceContent`) приватизированы, сторож импортов runtime+static; репродуктор 4757 красный до / зелёный после; область 141/141; typecheck 0. Патчи 0013/0014 наложены на A2 `wt-l115s-web670`. Статус → в ревью (8-е ревью 4764).
2026-09-23T16:56:49.948Z · coordinator[23.09 16:56Z координатор] ## 4764 (M1, 8-е независимое ревью) — WEB-670 р7: **NO-GO**, 2 критичных + граница модели угроз: F-1 состояние реестра на строковом ключе `globalThis` (`toolRegistry.ts:70-81`) — preload может подсадить карту описаний и «правильный» хеш, bootstrap-утверждение = изменяемое заявление, не доказательство; F-2 экспортированный builder контекста (`toolContext.ts:83-109`) брендирует любой объект с `userId`, не требуя `TrustedIdentity` → запуск автономии без сессии; F-3 остаются эффектные экспорты вне реестра (уведомления, записи документов/источников). Прошло: порядок barrel, непрозрачная capability, стек-тампер, сторож импортов. **Остаточный риск (вывод ревью):** если недоверенный код исполняется в ТОМ ЖЕ Node-процессе и может грузиться до bootstrap или импортировать внутренние модули, seal/hash/сторожи границу не создают; структурное закрытие = отдельный процесс/worker или capability-модуль. → раунд 8 (4772): F-1 (состояние в module-scope closure, не globalThis; хеш описаний — из самих builtin-модулей), F-2 (builder принимает только `TrustedIdentity`, JSON-копия не проходит), F-3 (перечисленные эффектные экспорты — за реестр); после него — решение владельца по границе (in-process плагинов сегодня нет).
2026-09-23T17:07:29.870Z · coordinator[23.09 17:07Z координатор] ## Решение владельца 23.09 17:06: закрыть WEB-670 после раунда 8 (4772) с комментарием о границе; заведён связанный тикет WEB-685 «Изоляция инструментов в отдельном процессе» (parked, после беты). Модель угроз: снаружи через API/UI код не попадает; только supply chain / доступ к серверу / будущие in-process плагины.
2026-09-23T17:14:42.474Z · coordinator[23.09 17:14Z координатор] ## ЗАКРЫТИЕ (координатор, по решению владельца 23.09 17:06) — 4772 (M1, раунд 8, финальный) GO: состояние реестра — module-scope closure (не `globalThis`), bootstrap сверяет хеш описаний с вшитой константой и с самим статически импортированным barrel, builder контекста принимает только рантайм-брендированный `TrustedIdentity` (JSON-копии отвергаются), 12/12 эффектных экспортов требуют контекст, аутентифицированный реестром; репродукторы 4764 4/4 зелёные; область 157/157; typecheck 0. Патчи 0015/0016 наложены на A2 `wt-l115s-web670` (всего 16 коммитов над l115r — в all7).
**Итог по тикету.** Найденные 7 объявленных-но-мёртвых защит (4 опасных) подключены и восемь раз проверены независимыми состязательными ревью (4714, 4723, 4730, 4740, 4748, 4757, 4764 + авторские раунды 4708–4772). **Граница (threat-model.md 4772):** для модели «недоверенный код НЕ исполняется в том же Node-процессе» защиты закрыты по построению — снаружи (API/UI) обхода нет. При in-process недоверенном коде (заражённая зависимость, доступ к серверу/сборке, будущие плагины) seal/hash/сторожи границу не гарантируют — код до вычисления модулей может подменить loader/конструкторы. Структурное закрытие — отдельный процесс/worker для инструментов: **WEB-685** (parked, после беты). Статус → done с этой оговоркой; посадка кода — в составе l115s (all7).
2026-09-23T20:04:19.179Z · coordinator[23.09 20:04Z координатор] ## СОСТОЯНИЕ НА 23.09 20:2xZ (для нулевого агента)
- Закрыт 23.09 17:06Z решением владельца: 8 раундов заплаток (4708…4772, ветка A2 `l115s-web670-dead-guards` = 8a49919e5, 16 коммитов, вошла в all8) закрыли все найденные обходы, но ревью 4772 показало: при недоверенном коде в том же Node-процессе seal/hash/сторожи границу не создают. Граница угроз зафиксирована в комментарии закрытия; настоящая граница — WEB-685 (отдельный процесс инструментов), связан.
2026-09-24T00:42:56.266Z · coordinator[24.09 00:42Z координатор] Волна 4852 (фикс старта all8): GO. Причина падения стенда 4844 («b is not a function»): WEB-685 фаза 1 убрала assertBuiltinRegistryBootstrap из фасада toolRegistry, а instrumentation (WEB-670) его вызывает. Экспорт возвращён (inproc — проверка через runtime-реестр, process — без загрузки модулей инструментов), плюс тест на все деструктурированные экспорты instrumentation (падает на 5bb221f2). 71/71, WEB-670 15/15, сторож WEB-685 OK, новых ошибок typecheck 0. Патчи → A2 l115s-all8 (6b64d314a4); пересборка all8 — 4855.
Воркер
не проверен
4253:web670-r3-independent-luna
neo
движение в панели: неизвестно
Подключиться и смотреть/перехватить руками. Колесо мыши листает; клавишами — Ctrl-b затем [, выход из прокрутки q. Отсоединиться — Ctrl-b затем d:
Прочитать историю панели без подключения — листается и ищется (/ поиск, q выход), воркеру не помешает:
Обновлён
2026-09-23T17:14:42.811Z