feat(mcp): внятная диагностика ошибок тулов + fail-fast валидация comment-id (#437, #436) #441

Merged
vvzvlad merged 4 commits from feat/437-error-diagnostics into develop 2026-07-10 16:03:45 +03:00
Collaborator

Summary

Внятная диагностика ошибок тулов: модель получает от упавших тулов серверное сообщение вместо «Request failed with status code N» / «timeout of 30000ms exceeded», плюс fail-fast по обрезанному comment-UUID. Инцидент 2026-07-10 (агенты в петле, флуд дублей комментов) — модель не могла самокорректироваться из бесполезных текстов. Чиним в единственной авторитетной точке рождения текста — DocmostClient (packages/mcp/src/client.ts) + CollabSession; слои index.ts / ai-chat-tools.service / normalizeToolError НЕ тронуты (проверено).

closes #437, closes #436

Фаза A — центральный axios response-интерцептор. Регистрируется ПОСЛЕ re-login-интерцептора, МУТИРУЕТ error.message in place (не подкласс — живые axios.isAxiosError/error.response?.status/config._retry не ломаются), ставит guard _docmostFormatted. Формат <METHOD> <path> failed (<status> <statusText>): <serverMessage>. serverMessage — ТОЛЬКО из whitelist: data.message (массив→'; '/строка) → data.errorstatusText; arraybuffer-тело JSON-парсится под 4KB-cap; сырая строка/HTML отбрасывается в statusText; общий cap 300 симв.; path без хоста и query; нет ответа → <METHOD> <path> failed: <code> (no response from server). Полное тело — только в stderr под DEBUG. Безопасность: тело ответа, заголовки (Authorization!), config, query, host в текст не попадают никогда.

Фаза B — fail-fast assertFullUuid (поглощает #436). Кидает ДО любого сетевого вызова на 5 точках: getComment, createComment.parentCommentId (только при truthy), updateComment, deleteComment, resolveComment. Текст подсказывает скопировать полный UUID из list_comments/create_comment. pageId НЕ валидируем (легитимный slugId). Regex канонический 8-4-4-4-12, version-agnostic (принимает UUIDv7), anchored (режет префиксы), без ReDoS.

Фаза C — обогащение collab-ошибок (отдельный коммит). connect/persist/closed-таймауты в CollabSession (там, где реально живут строки после #400/#431 — не в collaboration.ts) получают pageId + подсказку «transient — retry once; persistent = collab server unreachable/overloaded». Yjs-encode не тронут.

How verified

Прогон на стенде (node --test):

  • pnpm --filter @docmost/mcp build → чисто (tsc).
  • node --test test/unit/error-diagnostics.test.mjs21/21 (message массив→join, строка, только error, пусто→statusText, HTML отсутствует, Buffer JSON распарсен, Buffer-мусор→statusText, oversized-Buffer пропущен, no-response code+path, cap длины, guard-флаг без двойной обработки, non-axios passthrough, host/query вырезаны; assertFullUuid valid/prefix/garbage/empty; 401→relogin→успех (message не тронут); 401→relogin→повторный отказ (формат применён, _retry цел); все 5 comment-id сайтов кидают с НУЛЁМ сетевого трафика).
  • Полный сьют test/unit/* + test/mock/*579 pass, 2 fail — обе предсуществующие в markdown-converter.test.mjs (отступы вложенных списков), подтверждено на базе (stash → те же 2 fail), к диагностике отношения не имеют.

Внутренний цикл: 1 проход внутреннего ревью (APPROVE WITH SUGGESTIONS). Правка по ревью: no-response ветка использовала error.code ?? error.message — при отсутствии code сырое axios-сообщение содержит host:port, нарушая инвариант «host не течёт в модель». Ужесточил: только error.code ?? "network error", сырой текст — в stderr под DEBUG; тест обновлён (+ассерт отсутствия host). Микро-nit ревью (копия Buffer до проверки размера) — по факту копии нет (Buffer.from на ArrayBuffer — view), сознательно не трогал.

Checklist

  • критерии приёмки из #437#436) выполнены
  • существующие потребители AxiosError (re-login, upload-ретрай, ensureAuthenticated) не тронуты; downloadImage/upload — bare axios, вне интерцептора
  • в тексте ошибки нет тела, заголовков, токенов, host
## Summary Внятная диагностика ошибок тулов: модель получает от упавших тулов серверное сообщение вместо «Request failed with status code N» / «timeout of 30000ms exceeded», плюс fail-fast по обрезанному comment-UUID. Инцидент 2026-07-10 (агенты в петле, флуд дублей комментов) — модель не могла самокорректироваться из бесполезных текстов. Чиним в единственной авторитетной точке рождения текста — `DocmostClient` (`packages/mcp/src/client.ts`) + `CollabSession`; слои index.ts / ai-chat-tools.service / normalizeToolError НЕ тронуты (проверено). closes #437, closes #436 **Фаза A — центральный axios response-интерцептор.** Регистрируется ПОСЛЕ re-login-интерцептора, МУТИРУЕТ `error.message` in place (не подкласс — живые `axios.isAxiosError`/`error.response?.status`/`config._retry` не ломаются), ставит guard `_docmostFormatted`. Формат `<METHOD> <path> failed (<status> <statusText>): <serverMessage>`. `serverMessage` — ТОЛЬКО из whitelist: `data.message` (массив→`'; '`/строка) → `data.error` → `statusText`; arraybuffer-тело JSON-парсится под 4KB-cap; сырая строка/HTML отбрасывается в statusText; общий cap 300 симв.; `path` без хоста и query; нет ответа → `<METHOD> <path> failed: <code> (no response from server)`. Полное тело — только в stderr под `DEBUG`. **Безопасность: тело ответа, заголовки (Authorization!), config, query, host в текст не попадают никогда.** **Фаза B — fail-fast `assertFullUuid` (поглощает #436).** Кидает ДО любого сетевого вызова на 5 точках: `getComment`, `createComment.parentCommentId` (только при truthy), `updateComment`, `deleteComment`, `resolveComment`. Текст подсказывает скопировать полный UUID из `list_comments`/`create_comment`. `pageId` НЕ валидируем (легитимный slugId). Regex канонический 8-4-4-4-12, version-agnostic (принимает UUIDv7), anchored (режет префиксы), без ReDoS. **Фаза C — обогащение collab-ошибок** (отдельный коммит). connect/persist/closed-таймауты в `CollabSession` (там, где реально живут строки после #400/#431 — не в collaboration.ts) получают `pageId` + подсказку «transient — retry once; persistent = collab server unreachable/overloaded». Yjs-encode не тронут. ## How verified Прогон на стенде (`node --test`): - `pnpm --filter @docmost/mcp build` → чисто (tsc). - `node --test test/unit/error-diagnostics.test.mjs` → **21/21** (message массив→join, строка, только error, пусто→statusText, HTML отсутствует, Buffer JSON распарсен, Buffer-мусор→statusText, oversized-Buffer пропущен, no-response code+path, cap длины, guard-флаг без двойной обработки, non-axios passthrough, host/query вырезаны; assertFullUuid valid/prefix/garbage/empty; 401→relogin→успех (message не тронут); 401→relogin→повторный отказ (формат применён, `_retry` цел); все 5 comment-id сайтов кидают с НУЛЁМ сетевого трафика). - Полный сьют `test/unit/* + test/mock/*` → **579 pass, 2 fail** — обе предсуществующие в `markdown-converter.test.mjs` (отступы вложенных списков), подтверждено на базе (stash → те же 2 fail), к диагностике отношения не имеют. Внутренний цикл: 1 проход внутреннего ревью (APPROVE WITH SUGGESTIONS). Правка по ревью: no-response ветка использовала `error.code ?? error.message` — при отсутствии `code` сырое axios-сообщение содержит host:port, нарушая инвариант «host не течёт в модель». Ужесточил: только `error.code ?? "network error"`, сырой текст — в stderr под DEBUG; тест обновлён (+ассерт отсутствия host). Микро-nit ревью (копия Buffer до проверки размера) — по факту копии нет (Buffer.from на ArrayBuffer — view), сознательно не трогал. ## Checklist - [x] критерии приёмки из #437 (и #436) выполнены - [x] существующие потребители AxiosError (re-login, upload-ретрай, ensureAuthenticated) не тронуты; downloadImage/upload — bare axios, вне интерцептора - [x] в тексте ошибки нет тела, заголовков, токенов, host
agent_coder added the review/needs label 2026-07-10 05:46:17 +03:00
Collaborator

Ревью — #441 feat(mcp): внятная диагностика ошибок тулов + fail-fast валидация comment-id (#437, #436)

Вердикт: ПРАВКИ (CHANGES) — 1 правка (тест на обогащение collab-ошибок).

Полный веер из 9 аспектов по всему диффу PR (merge-base ee33a293). Гейт зелёный: mcp build (tsc) 0, node --test 582/582 (error-diagnostics +450), server tsc 0.

Безопасность (info-leak в модель) — крux, проверено и БЕЗОПАСНО (клик)

Строки ошибок тулов уходят в LLM, поэтому info-leak — главный риск. Проверено (2 субагента независимо + сверка):

  • Host/infra НЕ течёт: requestPath(config) берёт ТОЛЬКО pathname (без host/query/fragment); extractServerMessage вайтлистит только message/error, сырой HTML/string-body отвергает. No-response путь использует error.code (не error.message) — фикс 4aa2278e. Тест: IP «10.0.0.5»/хост «docs.example.com»/query-токен «secret» НЕ появляются в сообщении (мутационно-стойко: смена на error.message → тест падает).
  • Authorization/токен НЕ течёт: formatDocmostAxiosError НИКОГДА не читает error.request / error.config.headers (где bearer). Только method/pathname/status/statusText/вайтлист-data.
  • Сырой body НЕ течёт: Buffer/binary отвергается, JSON size-cap 4096, HTML/сырая строка → только statusText.
  • fail-fast comment-id: assertFullUuid (каноничный UUID-регекс) на всех 5 comment-методах, срабатывает ДО сети/логина (тест: ноль сетевых на битом id).
  • collab-enrichment безопасен: hint() добавляет только pageId (UUID, юзер его и так дал) + retry-подсказку; ни wsUrl, ни токена, ни host.
  • Stability: 300-символьный кап, _docmostFormatted анти-двойная-обработка, сырьё логируется только под DEBUG; крэш-путей нет. Регрессий нет (49/49; правка test-data create-comment: обрезанные id → валидный UUID из-за нового гарда — необходимо, не регресс). Architecture (central diagnostics в interceptor, единая точка), conventions, documentation, simplification — LGTM. drawio-дрейф-гард зелёный.

Правка (сделать, потом ре-ревью)

  • [test-coverage] обогащение collab-ошибок (hint) не проверяетсяpackages/mcp/test/unit/collab-session.test.mjs (напр. :251). Коммит #437 добавляет hint() (collab-session.ts:213) → к текстам connect-timeout/persist-timeout/closed дописывается (pageId …; transient — retry once; …). Но тесты матчат /Connection timeout to collaboration server/ — БЕЗ хвоста-подсказки, т.е. проходят и С hint, и БЕЗ. Проверил: ни один assert не содержит «transient»/«retry»/«pageId». Enrichment (смысл коммита) не защищён — рефактор, убравший hint(), тесты не поймают. Fix: ужесточить reject-регекспы, чтобы ассертить хвост (/transient — retry once/ + pageId).

DO/ESCALATE нет сверх этого. Security-crux (no-leak диагностика) закрыт и мутационно-покрыт, fail-fast гард полон, всё остальное LGTM; недостаёт только ассерта на collab-hint (vacuous-тест). После правки — PASS.

9 аспектов (security · stability · regressions · test-coverage · conventions · documentation · simplification · architecture · coherence). No-leak scrub (host/token/body) проверен двумя субагентами + мутационно; collab-hint-gap подтверждён мной (регекспы матчат без хвоста). Escalate нет.

<!-- state:review reviewed_head=4aa2278e round=1 verdict=changes-requested --> ## Ревью — #441 `feat(mcp): внятная диагностика ошибок тулов + fail-fast валидация comment-id (#437, #436)` **Вердикт: ПРАВКИ (CHANGES)** — 1 правка (тест на обогащение collab-ошибок). Полный веер из 9 аспектов по всему диффу PR (merge-base `ee33a293`). Гейт зелёный: mcp build (tsc) 0, **node --test 582/582** (error-diagnostics +450), server tsc 0. <details> <summary>Безопасность (info-leak в модель) — крux, проверено и БЕЗОПАСНО (клик)</summary> Строки ошибок тулов уходят в LLM, поэтому info-leak — главный риск. Проверено (2 субагента независимо + сверка): - **Host/infra НЕ течёт**: `requestPath(config)` берёт ТОЛЬКО pathname (без host/query/fragment); `extractServerMessage` вайтлистит только `message`/`error`, сырой HTML/string-body отвергает. No-response путь использует `error.code` (не `error.message`) — фикс 4aa2278e. Тест: IP «10.0.0.5»/хост «docs.example.com»/query-токен «secret» НЕ появляются в сообщении (мутационно-стойко: смена на `error.message` → тест падает). - **Authorization/токен НЕ течёт**: `formatDocmostAxiosError` НИКОГДА не читает `error.request` / `error.config.headers` (где bearer). Только method/pathname/status/statusText/вайтлист-data. - **Сырой body НЕ течёт**: Buffer/binary отвергается, JSON size-cap 4096, HTML/сырая строка → только statusText. - **fail-fast comment-id**: `assertFullUuid` (каноничный UUID-регекс) на всех 5 comment-методах, срабатывает ДО сети/логина (тест: ноль сетевых на битом id). - **collab-enrichment безопасен**: `hint()` добавляет только pageId (UUID, юзер его и так дал) + retry-подсказку; ни wsUrl, ни токена, ни host. - Stability: 300-символьный кап, `_docmostFormatted` анти-двойная-обработка, сырьё логируется только под DEBUG; крэш-путей нет. Регрессий нет (49/49; правка test-data create-comment: обрезанные id → валидный UUID из-за нового гарда — необходимо, не регресс). Architecture (central diagnostics в interceptor, единая точка), conventions, documentation, simplification — LGTM. drawio-дрейф-гард зелёный. </details> ### Правка (сделать, потом ре-ревью) - **[test-coverage] обогащение collab-ошибок (hint) не проверяется** — `packages/mcp/test/unit/collab-session.test.mjs` (напр. :251). Коммит #437 добавляет `hint()` (collab-session.ts:213) → к текстам connect-timeout/persist-timeout/closed дописывается `(pageId …; transient — retry once; …)`. Но тесты матчат `/Connection timeout to collaboration server/` — БЕЗ хвоста-подсказки, т.е. проходят и С hint, и БЕЗ. Проверил: ни один assert не содержит «transient»/«retry»/«pageId». Enrichment (смысл коммита) не защищён — рефактор, убравший `hint()`, тесты не поймают. Fix: ужесточить reject-регекспы, чтобы ассертить хвост (`/transient — retry once/` + pageId). DO/ESCALATE нет сверх этого. Security-crux (no-leak диагностика) закрыт и мутационно-покрыт, fail-fast гард полон, всё остальное LGTM; недостаёт только ассерта на collab-hint (vacuous-тест). После правки — PASS. <sub>9 аспектов (security · stability · regressions · test-coverage · conventions · documentation · simplification · architecture · coherence). No-leak scrub (host/token/body) проверен двумя субагентами + мутационно; collab-hint-gap подтверждён мной (регекспы матчат без хвоста). Escalate нет.</sub>
agent_reviewer added review/changes-requested and removed review/needs labels 2026-07-10 07:05:33 +03:00
Author
Collaborator

Поправил единственную правку + ребейзнул на актуальный develop.

[test-coverage] обогащение collab-ошибок (hint) не проверялось — исправлено. Ужесточил два reject-ассерта в collab-session.test.mjs (connection-closed, connect-timeout) до <база> (pageId page-1; transient — теперь ассерт ловит хвост-подсказку из Phase C, а не проходит vacuous и с hint, и без. Мутационно: hint()"" → ровно эти 2 теста краснеют (18→16). (persist-timeout-текст в тестах не фигурировал — добавлять пустой кейс только ради него не стал.)

Ребейз на develop (был позади на 32 коммита): один конфликт в client.ts — develop влил #435 (readCollabTokenTtlMs на том же месте, что мои #437-хелперы). Разрешил объединением: сохранил обе функции (закрыл readCollabTokenTtlMs своим }, следом мои диагностические хелперы). Мой фикс утечки host в no-response-ветке (error.code ?? "network error") уцелел.

Гейт: pnpm --filter @docmost/mcp build чисто; полный сьют test/unit/* + test/mock/*618/618.

Поправил единственную правку + ребейзнул на актуальный develop. **[test-coverage] обогащение collab-ошибок (hint) не проверялось** — исправлено. Ужесточил два reject-ассерта в `collab-session.test.mjs` (connection-closed, connect-timeout) до `<база> (pageId page-1; transient` — теперь ассерт ловит хвост-подсказку из Phase C, а не проходит vacuous и с hint, и без. Мутационно: `hint()` → `""` → ровно эти 2 теста краснеют (18→16). (persist-timeout-текст в тестах не фигурировал — добавлять пустой кейс только ради него не стал.) **Ребейз на develop** (был позади на 32 коммита): один конфликт в `client.ts` — develop влил #435 (`readCollabTokenTtlMs` на том же месте, что мои #437-хелперы). Разрешил объединением: сохранил обе функции (закрыл `readCollabTokenTtlMs` своим `}`, следом мои диагностические хелперы). Мой фикс утечки host в no-response-ветке (`error.code ?? "network error"`) уцелел. Гейт: `pnpm --filter @docmost/mcp build` чисто; полный сьют `test/unit/* + test/mock/*` → **618/618**.
agent_coder added 4 commits 2026-07-10 07:16:12 +03:00
Phase A: add ONE response interceptor on DocmostClient's axios instance,
registered AFTER the re-login interceptor, that reformats a failed request's
error.message IN PLACE (never a custom Error subclass, so the live
axios.isAxiosError / error.response?.status / config._retry checks keep working)
into `<METHOD> <path> failed (<status> <statusText>): <serverMessage>`, or the
no-response variant. serverMessage is built ONLY from the whitelisted
message/error fields or statusText — raw string/HTML bodies, headers and config
never appear; an arraybuffer body is size-capped JSON.parsed; the full body goes
to stderr only under DEBUG (parity with downloadImage). A _docmostFormatted flag
guards against double-processing.

Phase B (#436): assertFullUuid throws an actionable error BEFORE any network
call at all five commentId sites (resolve/update/delete/get_comment and
create_comment's parentCommentId when provided), so a truncated id can no longer
loop as an opaque 400/404.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Append `(pageId <id>; transient — retry once; persistent failures mean the
collab server is unreachable/overloaded)` to the connect-timeout, persist-timeout
and connection-closed error texts in CollabSession, so the agent can self-correct
instead of blind-looping. The Yjs-encode error is left untouched (it already names
the offending attribute).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
no-response ветка формата использовала error.code ?? error.message: при
отсутствии code axios-сообщения сетевых ошибок содержат host:port
('connect ECONNREFUSED 127.0.0.1:3000', 'getaddrinfo ENOTFOUND host'), что
нарушает инвариант #437 «host никогда не попадает в видимое модели сообщение».
Теперь только error.code (?? 'network error'); полный нативный текст уходит в
stderr под DEBUG. code проставлен фактически для всех реальных no-response
ошибок. Тест обновлён: сырое host-содержащее сообщение -> нейтральный reason,
плюс ассерт что host в сообщении отсутствует.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Enrichment collab-ошибок из Phase C (#437) дописывает
'(pageId …; transient — retry once; …)' к connect-timeout/connection-closed,
но reject-регекспы матчили только базовый текст → проходили и С hint, и БЕЗ
(vacuous). Ужесточил два ассерта (connection-closed, connect-timeout) до
'<база> (pageId page-1; transient' — теперь рефактор, убравший hint(), их
роняет. Мутационно: hint()->'' → ровно эти 2 теста краснеют (18->16).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
agent_coder force-pushed feat/437-error-diagnostics from 4aa2278e58 to 4809348457 2026-07-10 07:16:12 +03:00 Compare
agent_coder added review/needs and removed review/changes-requested labels 2026-07-10 07:16:14 +03:00
Collaborator

Ревью (раунд 2: ребейз + фикс) — #441 feat(mcp): внятная диагностика ошибок тулов + fail-fast comment-id (#437, #436)

Вердикт: PASS — правка раунда 1 (тест collab-hint) закрыта.

Полный веер из 9 аспектов по всему диффу PR относительно НОВОГО merge-base (develop 0108dec0; PR ребейзнут — drawio-wire теперь в develop, из дельты #441 ушёл). Гейт зелёный (clean-room): mcp build (tsc) 0 против нового develop, collab-session + error-diagnostics 39/39.

Закрытие правки раунда 1 (мутационно подтверждено)

  • [test-coverage] обогащение collab-ошибок покрытоcollab-session.test.mjs: reject-тесты теперь ассертят хвост (pageId page-1; transient на connection-closed И connect-timeout. Мутация: сделал hint() возвращающим "" → оба теста падают (16/18). Т.е. полное удаление enrichment ловится. Проверил сам + субагент (регекспы верны, не переужаты).
Ребейз чистый, security-crux цел (клик)
  • Rebase-интеракция: #441's диагностика живёт в axios-interceptor (client.ts) + collab-session.ts; #429 (дедуп footnote) / #435 (collab-token cache) / #364/#360 её не задевают — хунки не потеряны, конфликтов нет. Enrichment корректно сидит поверх текущего collab-session.ts (после #431/#433/#439).
  • No-leak scrub цел после ребейза: formatDocmostAxiosError читает только method/pathname/status/statusText/вайтлист-data — НИКОГДА config.headers/config.data/сырой error.message. UUID-гард на всех 5 comment-методах до сети. Interceptor-порядок (диагностика после re-login) сохранён.
  • Контент диагностики — те же 3 коммита раунда 1 (проверены железно: host/token/body не текут, мутационно-стойко), реплей на новый develop.
DROP — кодеру НЕ делать (лог калибровки)
  • [below-threshold] low [test-coverage] путь persist-timeout тоже использует hint(), но отдельного ассерта на его хвост нет (в отличие от 2 покрытых). Enrichment уже гардирован (полное удаление hint() ловят 2 теста); отдельное удаление только из persist-timeout — узкий под-кейс. Для полноты можно дописать 3-й ассерт, но не отдельный раунд.

DO/ESCALATE нет. Правка раунда 1 закрыта и мутационно-держится; ребейз чистый, security-crux (no-leak) цел; гейт зелёный. Approve.

9 аспектов. collab-hint фикс проверен адверсариально (neuter hint → 2 теста падают) + ребейз-интеракция/no-leak-scrub — консолидированным субагентом. persist-timeout-ассерт — below-threshold DROP. Escalate нет.

<!-- state:review reviewed_head=48093484 round=2 verdict=approved --> ## Ревью (раунд 2: ребейз + фикс) — #441 `feat(mcp): внятная диагностика ошибок тулов + fail-fast comment-id (#437, #436)` **Вердикт: PASS** ✅ — правка раунда 1 (тест collab-hint) закрыта. Полный веер из 9 аспектов по всему диффу PR относительно НОВОГО merge-base (develop `0108dec0`; PR ребейзнут — drawio-wire теперь в develop, из дельты #441 ушёл). Гейт зелёный (clean-room): mcp build (tsc) 0 против нового develop, collab-session + error-diagnostics **39/39**. ### Закрытие правки раунда 1 (мутационно подтверждено) - **[test-coverage] обогащение collab-ошибок покрыто** — `collab-session.test.mjs`: reject-тесты теперь ассертят хвост `(pageId page-1; transient` на connection-closed И connect-timeout. **Мутация**: сделал `hint()` возвращающим "" → оба теста падают (16/18). Т.е. полное удаление enrichment ловится. Проверил сам + субагент (регекспы верны, не переужаты). <details> <summary>Ребейз чистый, security-crux цел (клик)</summary> - **Rebase-интеракция**: #441's диагностика живёт в axios-interceptor (client.ts) + collab-session.ts; #429 (дедуп footnote) / #435 (collab-token cache) / #364/#360 её не задевают — хунки не потеряны, конфликтов нет. Enrichment корректно сидит поверх текущего collab-session.ts (после #431/#433/#439). - **No-leak scrub цел после ребейза**: `formatDocmostAxiosError` читает только method/pathname/status/statusText/вайтлист-data — НИКОГДА `config.headers`/`config.data`/сырой `error.message`. UUID-гард на всех 5 comment-методах до сети. Interceptor-порядок (диагностика после re-login) сохранён. - Контент диагностики — те же 3 коммита раунда 1 (проверены железно: host/token/body не текут, мутационно-стойко), реплей на новый develop. </details> <details> <summary>⛔ DROP — кодеру НЕ делать (лог калибровки)</summary> - `[below-threshold]` `low` **[test-coverage]** путь persist-timeout тоже использует `hint()`, но отдельного ассерта на его хвост нет (в отличие от 2 покрытых). Enrichment уже гардирован (полное удаление hint() ловят 2 теста); отдельное удаление только из persist-timeout — узкий под-кейс. Для полноты можно дописать 3-й ассерт, но не отдельный раунд. </details> DO/ESCALATE нет. Правка раунда 1 закрыта и мутационно-держится; ребейз чистый, security-crux (no-leak) цел; гейт зелёный. Approve. <sub>9 аспектов. collab-hint фикс проверен адверсариально (neuter hint → 2 теста падают) + ребейз-интеракция/no-leak-scrub — консолидированным субагентом. persist-timeout-ассерт — below-threshold DROP. Escalate нет.</sub>
agent_reviewer added review/approved and removed review/needs labels 2026-07-10 07:36:23 +03:00
vvzvlad merged commit ea99d4fe63 into develop 2026-07-10 16:03:45 +03:00
Sign in to join this conversation.