refactor(tools): updatePageContent → updatePageMarkdown; −import_page_markdown с MCP (#411) #462
Reference in New Issue
Block a user
Delete Branch "refactor/411-update-page-markdown"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Первый линк breaking-окна #416 (#411→#412→#413→#415). closes #411
Поверхности записи «целым телом» были несимметричны: in-app агент имел
updatePageContent(имя не про формат, тогда как парный структурный —updatePageJson), а внешний MCP голого plain-markdown-replace не имел вовсе (толькоimport_page_markdown— на деле round-trip-парсер кexport_page_markdown). Пара должна бытьupdatePageMarkdown/updatePageJson.Пост-Фаза-1б (реестр + циклы по обоим хостам):
updatePageMarkdown(mcpNameupdate_page_markdown, tier как у updatePageJson,execute: client.updatePage(pageId, content, title)— путьupdatePageContentRealtime → markdownToProseMirrorCanonical,^[...]-сноски парсятся). Реестровый цикл регистрирует её на ОБОИХ хостах.import_page_markdownубран с внешнего MCP черезinAppOnly:trueу спеки importPageMarkdown — MCP-цикл и генератор инвентаря её пропускают, in-app агент сохраняет importPageMarkdown; спека и client-метод НЕ удалены.updatePageContenttool + его INLINE_TOOL_TIERS-энтри;updatePageдобавлен в Pick DocmostClientLike; ROUTING_PROSE обновлён (убран import_page_markdown, добавлен update_page_markdown в bulk-rewrite); лейбл-мапы chat-markdown.util (en/ru). Одноимённые ВНУТРЕННОСТИ (PageService.updatePageContent, updatePageContentRealtime, collaboration.handler) НЕ тронуты.How verified
Стенд (symlink
@docmost/mcpвременно на пакет ветки, восстановлен):node --test→ 646/646;tsc -p apps/serverчисто;jest ai-chat-tools.service + shared-tool-specs.contract + tool-tiers + comment-signal-inapp→ 270/270.updatePageMarkdownна ОБЕИХ поверхностях с идентичной схемой (contract), форвардит в client.updatePage;import_page_markdownОТСУТСТВУЕТ на MCP, присутствует in-app;updatePageContent-тула больше нет;^[...]→сноски покрыт через markdownToProseMirrorCanonical. CHANGELOG BREAKING + миграция; README/README.ru пакета.Внутренний цикл: 2 прохода. Ревью (APPROVE WITH SUGGESTIONS) отметило F1: in-app результат
updatePageMarkdownсменился с проекции{pageId, updated}(старый инлайн) на СЫРОЙ результат клиента{success, modified, message, pageId, verify?}. По совету ревьюера — сознательно оставил сырой результат и задокументировал (комментарий на спеке + тест ассертит сырую форму):.updatedникто не читал (grep пуст), сырой результат строго информативнее для модели (несёт footnote/verify-варнинги) и соответствует on-both-hosts-конвенции реестра; путь записи идентичен.inAppExecute-проекция ломала overlap-эвристикуas-каста в тест-моках — не оправдано ради поля, которое никто не читает. Тест-кастыSHARED_TOOL_SPECS as Record<...>переведены наas unknown as(совет компилятора; только тесты, продакшн-типобезопасность позиционных вызовов не тронута — #411-правка тип DocmostClientLike тронула и эту эвристику).Порядок мержа
Первый линк breaking-окна. Стоит на develop; #412 (camelCase) встанет ПОСЛЕ него и после мержа drawio-2 (#440). Порядок стопки breaking-окна опишу в #416.
Checklist
^[...]в теле материализуется в сноскиРевью — #462
refactor(tools): updatePageContent → updatePageMarkdown; −import_page_markdown с MCP (#411)Вердикт: PASS ✅
Полный веер из 9 аспектов (на develop
ea99d4fe, Phase-1б влита; 15 файлов, +244/−64). Первый линк breaking-окна #416 — намеренный, задокументирован в CHANGELOG. Гейт зелёный, inAppOnly-гейтинг мутационно-пришпилен.Симметрия поверхности + сохранение поведения (клик)
updatePageMarkdown(update_page_markdown, tier какupdatePageJson,execute: (client,{pageId,content,title}) => client.updatePage(pageId,content,title)) — регистрируется на ОБОИХ хостах реестровым циклом. Путь записи ИДЕНТИЧЕН старому inlineupdatePageContent(тот жеclient.updatePage→ updatePageContentRealtime → markdownToProseMirrorCanonical). Пара update_page_markdown ↔ update_page_json теперь симметрична.import_page_markdownубран с внешнего MCP черезinAppOnly:true(спека+client-метод НЕ удалены; in-app агент сохраняет importPageMarkdown для round-trip экспортов). MCP-цикл и #460-генератор инвентаря скипают inAppOnly. Адверсариально: убралinAppOnly:true→ 2 теста ПАДАЮТ («import_page_markdown must be dropped from MCP surface» + «importPageMarkdown spec is inAppOnly») → гейтинг load-bearing.{pageId,updated}→ raw{success,...}): НАМЕРЕННА, задокументирована на спеке (tool-specs.ts:469-476) и покрыта тестом («returns the RAW client result in-app (deliberate #411 shape change)»). Оправдана:.updatedникто не читал; raw несёт footnote/verify-warnings и соответствует registry-конвенции (canonical execute → raw, хост оборачивает). Путь записи страницы не изменён.updatePageContent+ его INLINE_TOOL_TIERS-энтри;updatePageдобавлен в Pick DocmostClientLike; ROUTING_PROSE (import_page_markdown убран, update_page_markdown добавлен в bulk-rewrite); README + README.ru (симметрично, обе локали); chat-markdown.util лейблы en/ru; CHANGELOG breaking-changes. Ни одной висячей ссылки на старые имена. Внутренности (PageService.updatePageContent и т.п.) НЕ тронуты — чистое разделение tool-surface vs internal API.Объективный гейт (клин-рум /home/claude/gm-ci)
⛔ DROP — кодеру НЕ делать (лог калибровки)
[by-design]low[regressions] форма результата projected→raw — намеренная задокументированная #411-дельта (тест + spec-коммент), путь записи идентичен, registry-конвенция. Не тихая регрессия.[speculative]low[test-coverage] блок-сплиттер инвентарь-скрейпера (inAppOnlyskip) теоретически хрупок на multiline-объектах в description — но source на string-concat, на практике работает (гейт 646/646 + адверсариал подтверждают). Не триггерится.DO/ESCALATE нет. Поверхность записи симметрична, inAppOnly-удаление import_page_markdown с MCP пришпилено, единственная дельта поведения намеренна+покрыта, все имена согласованы, гейт зелёный. Breaking-окно #416 — осознанное, с migration-нотами. Approve.
9 аспектов (coherence+regressions+security+stability, testcov+conv+docs+simp+arch — все LGTM). updatePageMarkdown execute = старый write-path; inAppOnly-гейтинг адверсариально пришпилен; README/README.ru симметричны; raw-shape дельта by-design+tested. Escalate нет.
Ребейзнул на develop (после мержа drawio-2 #440 стал немёржабелен — оба трогали tool-specs/index/server-instructions). Мёржабелен снова.
Конфликты — только пересечение с влитым #440, разрешены объединением:
ai-chat-tools.service.spec.ts/tool-tiers.spec.ts: мокиmockLoaded— сохранены drawio-заглушки #440 (searchShapes/getGuideSection) + мойas unknown asкаст (кстати, #440 сам применил тот же каст к contract-спеке — эвристика overlap реально тронута новой формой реестра).server-instructions.tsROUTING_PROSE (EDIT): объединил drawio-подсказки #440 (shapes/guide/layout:elk) с моимupdate_page_markdownв bulk-rewrite.Проверка после ребейза (symlink на пакет ветки, восстановлен): mcp
node --test677/677;tsc -p apps/serverчисто;jest ai-chat-tools.service + contract + tool-tiers + comment-signal-inapp283/283.Флипнул на review/needs (форс-пуш). Готов к мержу — после него сразу строю #412 (camelCase).
Поверхности записи «целым телом» были несимметричны: у in-app агента полная замена тела markdown называлась updatePageContent (имя не про формат, тогда как парный updatePageJson — про JSON), а у внешнего MCP голого plain-body-replace не было вовсе (только import_page_markdown — на деле парсер round-trip к export_page_markdown, не plain-replace). Пара должна быть updatePageMarkdown / updatePageJson. Пост-Фаза-1б архитектура (реестр + циклы по обоим хостам): - новая shared-спека updatePageMarkdown (mcpName update_page_markdown, inAppKey updatePageMarkdown, tier как у updatePageJson) с execute (client, {pageId, content, title}) => client.updatePage(...) — тот же путь updatePageContentRealtime → markdownToProseMirrorCanonical, ^[...]-сноски парсятся. Реестровый цикл регистрирует её на ОБОИХ хостах автоматически. Добавлен 'updatePage' в Pick DocmostClientLike. - import_page_markdown убран с внешнего MCP через inAppOnly:true у спеки importPageMarkdown — MCP-цикл и генератор инвентаря её пропускают, in-app агент сохраняет importPageMarkdown; спека и client-метод НЕ удалены. - удалён inline in-app updatePageContent tool (теперь из реестра под inAppKey updatePageMarkdown) + его INLINE_TOOL_TIERS-энтри. - ROUTING_PROSE: bulk-rewrite ссылается на update_page_markdown|update_page_json; убрано упоминание import_page_markdown; инвентарь генерируется из catalogLine. - лейбл-мапы chat-markdown.util (en/ru), человекочитаемые метки не тронуты. - НЕ тронуты одноимённые внутренности: PageService.updatePageContent, updatePageContentRealtime, collaboration.handler — переименовано только имя тула. Тесты: updatePageMarkdown на обеих поверхностях с идентичной схемой, forward в client.updatePage; import_page_markdown ОТСУТСТВУЕТ на MCP, присутствует in-app; ^[...]→сноски покрыт через collaboration.test. CHANGELOG BREAKING + миграция; README/README.ru пакета обновлены. Гейт: mcp node --test 646/646, server jest 259, tsc чисто. Первый линк breaking-окна #416 (#411→#412→#413→#415). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>ccef8d0a7cto3a521ada4dРе-ревью (round 2, rebase на #440-merged develop) — #462
refactor(tools): updatePageContent → updatePageMarkdown (#411)Вердикт: PASS ✅ — чистый ребейз одобренного на round 1 изменения; конфликт-резолюция с влитым #440 корректна.
#440 (drawio стадия 2) влит в develop (
576db3c8), #462 отребейзен поверх. Реальная дельта vs новый develop — те же 15 файлов / +244/−64, что я одобрил на round 1 (headccef8d0a).Верификация ребейза (клик)
EDIT:в ROUTING_PROSE, где конфликт-резолюция КОРРЕКТНО объединила: правку #440 (добавлены drawio_shapes/drawio_guide/layout:"elk") И правку #462 (добавленupdate_page_markdownв bulk-rewrite). Обе сосуществуют, ни одна не потеряна. Остальные 14 файлов — байт-в-байт как одобрено.ROUTING_PROSE— 0 вхождений (единственное упоминание — объясняющий коммент строка 134 «inAppOnly (#411)»). Тест!ROUTING_PROSE.includes("import_page_markdown")держится.Объективный гейт (клин-рум на #440-merged develop)
DO/ESCALATE/DROP нет (все round-1 находки были by-design DROP, содержание не изменилось). Ребейз корректен, конфликт-резолюция ROUTING_PROSE верна, #440+#462 сосуществуют, гейт зелёный. Approve (переношу с round 1).
Round 2 (rebase на
576db3c8). Diff-of-diffs: только корректный merge ROUTING_PROSE (drawio #440 + update_page_markdown #462). import_page_markdown в прозе 0×. Гейт 677/283 зелёный, inAppOnly адверсариально пришпилен. Escalate нет.