refactor(tools): execute-маппинг в SHARED_TOOL_SPECS + автопроводка обоих хостов (#445) #459
Open
agent_coder
wants to merge 3 commits from
refactor/445-execute-mapping into develop
pull from: refactor/445-execute-mapping
merge into: vvzvlad:develop
vvzvlad:main
vvzvlad:fix/409-invalid-node-validation
vvzvlad:refactor/448-generate-inventory
vvzvlad:refactor/446-derive-client-types
vvzvlad:fix/447-registry-stamp-ci
vvzvlad:fix/444-agent-loop-guards
vvzvlad:fix/396-sendnow-detached-run
vvzvlad:fix/452-immutable-cache-control
vvzvlad:develop
vvzvlad:docs/footnote-authoring-comment-cleanup
vvzvlad:feat/437-error-diagnostics
vvzvlad:fix/442-cursor-pagination
vvzvlad:feat/419-footnote-normalize
vvzvlad:feat/424-drawio-rules
vvzvlad:perf/399-comment-resolve-async
vvzvlad:perf/435-collab-token-cache
vvzvlad:perf/344-background-rerenders
vvzvlad:perf/348-backend-lowhanging
vvzvlad:feat/423-drawio-crud
vvzvlad:perf/401-collab-hotpath
vvzvlad:feat/430-live-reconnect
vvzvlad:perf/400-collab-session
vvzvlad:refactor/414-dedup-node-ops
vvzvlad:feat/417-new-comments-signal
vvzvlad:feat/408-createcomment-hints
vvzvlad:feat/407-persist-tool-errors
vvzvlad:feat/420-footnote-render
vvzvlad:dummy-review/mcp-hang-fix
vvzvlad:dummy-review/mcp-hang-base
vvzvlad:feat/381-resumable-sse-pr1
vvzvlad:feat/git-sync-2
vvzvlad:docs/agents-workspace-build-order
vvzvlad:feature/offline-sync
vvzvlad:perf/342-code-splitting
vvzvlad:perf/346-compression-cache
vvzvlad:feat/196-multi-cursor
vvzvlad:feat/370-page-versioning
vvzvlad:perf/343-typing-latency
vvzvlad:docs/how-to-test
vvzvlad:fix/ai-sdk-partial-output-oom
vvzvlad:test/351-generative-converter
vvzvlad:feat/371-roles-catalog
vvzvlad:refactor/345-server-converter
vvzvlad:refactor/294-spec-registry-cont
vvzvlad:fix/363-migration-order
vvzvlad:fix/e2e-callout-and-gate-build
vvzvlad:fix/docker-re2-toolchain
vvzvlad:feat/git-sync
vvzvlad:fix/media-roundtrip-stability
vvzvlad:fix/340-comment-panel-perf
vvzvlad:fix/332-deferred-tools
vvzvlad:fix/329-ephemeral-suggestions
vvzvlad:fix/330-search-in-page
vvzvlad:fix/328-resolved-anchor-spam
vvzvlad:fix/331-intraline-diff
vvzvlad:fix/324-coverage-gate
vvzvlad:fix/325-mobile-390
vvzvlad:feat/293-A-git-sync-package
vvzvlad:feat/300-avatar-oklch
vvzvlad:fix/321-banner-mobile
vvzvlad:feat/300-avatar-colors
vvzvlad:feat/315-comment-suggestions
vvzvlad:feat/scroll-restore-stable-wait
vvzvlad:feat/300-agent-avatar-stack
vvzvlad:feat/300-avatar-polish
vvzvlad:refactor/294-tool-spec-registry
vvzvlad:feat/scroll-restore-ux
vvzvlad:fix/responsive-tablet-sidebar
vvzvlad:feature/ai-chat-page-change-observability
vvzvlad:image-inline-center
vvzvlad:fix/283-short-remap-title
vvzvlad:fix/283-slash-layout
vvzvlad:image-inline-row
vvzvlad:feat/276-ai-chat-dock
vvzvlad:fix/269-table-menu-refocus
vvzvlad:docs/dev-stand-guide
vvzvlad:feat/266-scroll-position
vvzvlad:fix/260-collab-docname-slugid
vvzvlad:test/244-phase2-tail
vvzvlad:fix/262-reindex-progress-realtime
vvzvlad:fix/258-changelog-compare-links
vvzvlad:fix/244-dataloss-bugs
vvzvlad:feat/246-spoiler
vvzvlad:feat/221-image-captions
vvzvlad:test/244-part-b
vvzvlad:feat/251-intentional-clear
vvzvlad:fix/embeddings-reindex-progress
vvzvlad:refactor/193-tool-spec-registry
vvzvlad:fix/255-ws-redis-adapter-leak
vvzvlad:fix/252-e2e-open-handles
vvzvlad:feat/229-catalog-yaml
vvzvlad:feat/243-blob-sandbox
vvzvlad:feat/228-inline-footnotes
vvzvlad:fix/qa-ui-bugs-216-218
vvzvlad:feature/agent-roles-catalog
vvzvlad:fix/share-alias-rename
vvzvlad:fix/ai-chat-empty-render
vvzvlad:feat/191-chat-doc-binding
vvzvlad:feat/201-temporary-notes
vvzvlad:feat/198-interrupt-agent
vvzvlad:feat/ai-chat-full-history
vvzvlad:feat/199-ai-generate-title
vvzvlad:feat/205-share-aliases
vvzvlad:batch/issues-189-187-170
vvzvlad:feat/170-mcp-test-button
vvzvlad:feat/189-context-badge
vvzvlad:feat/198-interrupt-agent-send-now
vvzvlad:fix/issues-190-159
vvzvlad:fix/ai-chat-new-chat-during-stream
vvzvlad:fix/ai-chat-stream-perf
vvzvlad:batch/issues-2026-06-25
vvzvlad:feat/ai-chat-persistent-history
vvzvlad:fix/ai-chat-copy-chat-wysiwyg
vvzvlad:fix/ai-stream-reset-resilience
vvzvlad:fix/ai-stream-undici-timeout
vvzvlad:fix/footnote-review-1227-followup
vvzvlad:fix/ai-chat-token-counter-realtime
vvzvlad:docs/manual-qa-test-plan
No Reviewers
Labels
Clear labels
epic
needs-human
review/approved
review/changes-requested
review/needs
возможно, баг
Large multi-phase effort spanning many changes
эскалация: нужно решение человека
в последнем ревью нет открытых blocking-находок
последнее ревью оставило открытые blocking-находки
head не ревьюился (head != reviewed_head)
Похоже на баг, но требует подтверждения/воспроизведения; чиним, если повторится
No Label
review/approved
Milestone
No items
No Milestone
Projects
Clear projects
No project
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: vvzvlad/gitmost#459
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "refactor/445-execute-mapping"
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
Ядро Фазы 1б роадмапа #416 — третий линк стопки. closes #445
Реестр
SHARED_TOOL_SPECS(#294) шарил между хостами только метаданные (имя/схема/описание/tier), но НЕ execute-логику: у каждого shared-тула было ДВА рукописных execute-тела с копией маппинга аргументов (внешний MCPregisterSharedвindex.ts; in-appsharedToolвai-chat-tools.service.ts, зеркалящий MCP-транспорт ВРУЧНУЮ). Это корень повторяющихся parity-багов (f46d89eadrawio,f8d26420stashPage,fc9088b7node-args) — добавление одного тула = 7-9 согласованных ручных правок в двух пакетах.SharedToolSpecрасширен: каноническийexecute(client, args)— чистый JS, свободно пересекает zod-мажорную границу (v3 в mcp / v4 на сервере) — плюс оверрайдыmcpExecute/inAppExecute/mcpOnly/inAppOnlyдля ОСОЗНАННЫХ per-layer различий.client: DocmostClientLike(Pick из #446). Канон возвращает СЫРЬЁ, каждый хост накладывает свой конверт (MCPjsonContent, in-app как есть); override владеет результатом хоста целиком.index.tsregisterShared39→0,ai-chat-tools.servicesharedTool~40→1. Добавление спека автоматически регистрирует тул в ОБОИХ хостах — сценарий PR #434 («спек есть, in-app проводки нет») невозможен по построению.How verified
Стенд (symlink
@docmost/mcpвременно на пакет ветки для серверных шагов, восстановлен):pnpm --filter @docmost/mcp build→ чисто.node --test test/unit/* test/mock/*→ 611 pass (вкл. stash-page e2e, server-instructions, schema — mock-тесты гоняют MCP execute-тела).tsc --noEmit -p apps/server→ без новых ошибок.jest ai-chat-tools.service shared-tool-specs.contract tool-tiers comment-signal-inapp→ 260 pass.sharedTool(=1 (было ~40),registerShared(=0 (было 39).Внутренний цикл: 1 проход (APPROVE). Ревьюер сделал ПОСТРОЧНУЮ BEFORE/AFTER-сверку по каждому shared-тулу на ОБОИХ хостах: ни одного изменённого per-host поведения (порядок/дефолты аргументов, guard'ы movePage/createComment/checkNewComments, конверты resource_link/bare-line/single-text, проекции результатов — сохранены), множества тулов побайтово совпадают (48 in-app, 45 MCP), кросс-zod-граница чистая (нет
z.в execute-телах).Порядок мержа
Третий линк Фазы 1б, стоит на #446 (PR #458). Мержить: #457 (#447) → #458 (#446) → этот → #448. См. комментарий с порядком в #416. Следующий #448 (генерация инвентаря) встанет сюда.
Checklist
Ревью — #459
refactor(tools): execute-маппинг в SHARED_TOOL_SPECS + автопроводка обоих хостов (#445)Вердикт: PASS ✅
Полный веер из 9 аспектов по СОБСТВЕННОЙ дельте PR (третий линк стопки, стоит на уже-одобренных #457→#458; ревьюил
fe5b6ecd..8c74659d= 3 файла, +590/−926, net −336). Гейт зелёный в чистой комнате, оба хоста мутационно-пришпилены.Поведение сохранено — построчный BEFORE/AFTER + мутации (клик)
Проблема (#445): у каждого shared-тула было ДВА рукописных execute-тела с копией маппинга аргументов (MCP
registerSharedв index.ts; in-appsharedTool) — корень parity-багов (drawio/stashPage/node-args). PR вводит каноническийexecute(client, args)вSharedToolSpec+ оверрайдыmcpExecute/inAppExecute/mcpOnly/inAppOnly; оба хоста теперь ЦИКЛЯТ по реестру (registerShared39→0,sharedTool~40→1).fe5b6ecd): НИ ОДНОГО изменённого per-host поведения. Сохранены: порядок/дефолты аргументов, гарды (movePage self-cycle +''|'null'→null, deletePage soft-only, createComment selection/suggestedText на обоих хостах, checkNewCommentssince-таймстамп-гард, transformPagedeleteCommentsнедостижим), конверты (MCP jsonContent/resource_link/bare-line vs in-app проекции{title,markdown}/{id,title}/…),parseNodeArg(patchNode/insertNode/updatePageJson), сообщения ошибок. Каноничный возвращает СЫРЬЁ, оверрайд владеет конвертом хоста целиком.z./zod в execute-телах (пересекают v3-mcp/v4-server major-границу как чистый JS).mcpExecute-конверт (uri:result.uri→sha256) →stash-page-mcp-resultmock-тест ПАДАЕТ (MCP-хост реально диспатчит на mcpExecute-оверрайд, не на канон); (2) сломал patchNodeparseNodeArg(node)→node→ 2 in-app jest-теста ПАДАЮТ (coercion + invalid-JSON-throw). Диспатч/оверрайд-выбор — load-bearing на обоих хостах.Объективный гейт (клин-рум /home/claude/gm-ci)
⛔ DROP — кодеру НЕ делать (лог калибровки; downgrade после верификации)
Субагент testcov/arch пометил их HIGH/CRITICAL+ESCALATE — понизил после проверки кода и гейта (severity ≠ escalate; у всех очевидный фикс = максимум DO, не форк; проверка показала — даже не DO):
[below-threshold]high→low[test-coverage] «диспатч mcpExecute/inAppExecute vs канон не тестируется». Опровергнуто: обе мутации выше доказывают, что оверрайд-precedence load-bearing на обоих хостах; проекции getPage/createPage пришпиливают inAppExecute; mock-тесты покрывают mcpExecute (stashPage/createComment/list-comments). Риск-путь (вывод оверрайд-тулов) покрыт; выделенный per-tool dispatch-тест — nice-to-have, не закрывает дефект.[below-threshold]med→low[simplification/conventions]mcpOnly/inAppOnlyне выставлены ни одним спеком. Но флаги ВПАЯНЫ в гейты обоих циклов (if(inAppOnly)return/if(mcpOnly)continue) — forward-scaffolding под задокументированную миграцию inline-тулов (table_get после camelCase #412). Безвредно.[below-threshold]med→low[architecture] MCP-хостspec.execute!(краш при отсутствии тела) vs in-app defensiveif(!run)continue. Защитимо: inAppOnly-спеки скипаются ДО!, так что!бьёт только по кривому non-inAppOnly-спеку без MCP-тела → fail-fast краш на СТАРТЕ (громко в CI, не тихий прод-баг); ни один текущий спек не триггерит;!намеренно кодирует инвариант.DO/ESCALATE нет. Дельта убивает дублированный per-host маппинг (net −336), заменяя единым каноном + осознанными оверрайдами; полный BEFORE/AFTER-аудит + двусторонние адверсариальные мутации подтверждают сохранение поведения и load-bearing диспатч. Гейт зелёный, покрытие не снижено. Approve.
9 аспектов (security+stability, regressions+coherence — полный per-tool BEFORE/AFTER, testcov+conv+docs+simp+arch). Диспатч обоих хостов адверсариально пришпилен (stashPage mcpExecute / patchNode canonical); все гарды/дефолты/конверты/coercion byte-preserved; zod-граница чиста. 3 находки testcov/arch понижены до DROP после верификации. Escalate нет.
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.