refactor(mcp)!: BREAKING — все имена MCP-тулов snake_case → camelCase (#412) #463

Merged
vvzvlad merged 1 commits from refactor/412-camelcase-tool-names into develop 2026-07-10 23:44:44 +03:00
Collaborator

Summary

Второй линк breaking-окна #416 (#411→ЭТОТ→#413→#415). BREAKING. closes #412

Один логический тул жил под двумя именами: внешний MCP snake_case (edit_page_text), in-app camelCase (editPageText) — дублирование доков, путаница при переносе промптов/скиллов, помеха шарингу спек. Решение владельца: единый camelCase везде, включая внешний MCP. После этого mcpName === inAppKey для каждой shared-спеки.

  • tool-specs.ts: mcpName выведен из ключа спеки для всех 43 shared-спек (раньше divergent snake). Проверено — mcpName читается только структурно (цикл регистрации, генератор <tool_inventory>, TOOL_FAMILY), ничего не полагалось на старое snake-значение. +5 inline-регистраций (tableGet/updateComment/deleteComment/docmostTransform; search без изменений). Рантайм: 47 тулов, все camelCase, ноль подчёркиваний.
  • Контракт-конвенция инвертирована: mcpName === toSnake(inAppKey)mcpName === inAppKey; toSnake удалён; tool-specs.test/tool-inventory.test обновлены (скрейпер расширен до [a-zA-Z0-9_]).
  • ROUTING_PROSE/TOOL_FAMILY/INLINE_MCP_INVENTORY → camelCase. ai-chat.prompt/guard уже на in-app camelCase-ключах — без изменений. comment-signal EXCLUDED_TOOLS схлопнут с дублей snake+camel.
  • Неочевидное: assertUnambiguousMatch(op: "patch_node"|"delete_node") в prosemirror-markdown/node-ops (op интерполируется в model-facing ошибку) → "patchNode"|"deleteNode".
  • Внутренние имена методов (PageService.updatePageContent и т.п.) НЕ тронуты — переименованы только ИМЕНА ТУЛОВ.

⚠️ Breaking (в CHANGELOG таблица 46 строк + миграция)

Все внешние MCP-клиенты ломаются разом: permission-allowlists (mcp__gitmost-*__get_node__getNode), сохранённые промпты/скиллы, .mcp.json, метрики per-tool-label. Мигрировать в lockstep с деплоем. Релизится вместе с #411 — чтобы внешние конфиги ломались один раз.

How verified

Стенд (symlink @docmost/mcp + @docmost/prosemirror-markdown на пакеты ветки, восстановлены):

  • Живой сервер: 47 тулов, 0 с подчёркиванием; исчерпывающий grep 46 старых snake-имён по src/тестам/промптам/доках → ноль (snake остались только в намеренной migration-таблице CHANGELOG).
  • mcp node --test677/677; tsc -p apps/server чисто; jest ai-chat-tools.service + shared-tool-specs.contract + tool-tiers + ai-chat.prompt + comment-signal-inapp323.

Внутренний цикл: 1 проход (APPROVE WITH SUGGESTIONS). Ревьюер подтвердил живой энумерацией 47 camelCase-тулов и исчерпывающим grep'ом отсутствие утечек; конвенция перевёрнута и энфорсится; структурные зависимости от mcpName целы. Единственная находка — устаревшая формулировка «snake_case» в двух ВНУТРЕННИХ комментариях ai-chat-tools.service.ts — поправил (не модель-обращённое).

Порядок мержа (стопка breaking-окна)

Стоит на develop; #413 (markdown-default) стоит на ЭТОЙ ветке, #415 на #413. Собираю стопкой без ожидания мержей; порядок опишу в #416. Мержить: #411(влит) → этот#413#415.

Checklist

  • tools/list внешнего MCP не содержит ни одного snake-имени (47 camelCase)
  • mcpName === inAppKey для каждой shared-спеки (контракт зелёный)
  • релизится в одном breaking-релизе с #411
## Summary Второй линк breaking-окна #416 (#411→ЭТОТ→#413→#415). **BREAKING.** closes #412 Один логический тул жил под двумя именами: внешний MCP snake_case (`edit_page_text`), in-app camelCase (`editPageText`) — дублирование доков, путаница при переносе промптов/скиллов, помеха шарингу спек. Решение владельца: **единый camelCase везде, включая внешний MCP**. После этого `mcpName === inAppKey` для каждой shared-спеки. - `tool-specs.ts`: `mcpName` **выведен из ключа** спеки для всех 43 shared-спек (раньше divergent snake). Проверено — `mcpName` читается только структурно (цикл регистрации, генератор `<tool_inventory>`, `TOOL_FAMILY`), ничего не полагалось на старое snake-значение. +5 inline-регистраций (`tableGet`/`updateComment`/`deleteComment`/`docmostTransform`; `search` без изменений). **Рантайм: 47 тулов, все camelCase, ноль подчёркиваний.** - Контракт-конвенция **инвертирована**: `mcpName === toSnake(inAppKey)` → `mcpName === inAppKey`; `toSnake` удалён; `tool-specs.test`/`tool-inventory.test` обновлены (скрейпер расширен до `[a-zA-Z0-9_]`). - ROUTING_PROSE/TOOL_FAMILY/INLINE_MCP_INVENTORY → camelCase. `ai-chat.prompt`/guard уже на in-app camelCase-ключах — без изменений. `comment-signal` EXCLUDED_TOOLS схлопнут с дублей snake+camel. - Неочевидное: `assertUnambiguousMatch(op: "patch_node"|"delete_node")` в `prosemirror-markdown/node-ops` (op интерполируется в model-facing ошибку) → `"patchNode"|"deleteNode"`. - Внутренние имена методов (`PageService.updatePageContent` и т.п.) НЕ тронуты — переименованы только ИМЕНА ТУЛОВ. ## ⚠️ Breaking (в CHANGELOG таблица 46 строк + миграция) Все внешние MCP-клиенты ломаются разом: permission-allowlists (`mcp__gitmost-*__get_node` → `__getNode`), сохранённые промпты/скиллы, `.mcp.json`, метрики per-tool-label. Мигрировать в lockstep с деплоем. **Релизится вместе с #411** — чтобы внешние конфиги ломались один раз. ## How verified Стенд (symlink `@docmost/mcp` + `@docmost/prosemirror-markdown` на пакеты ветки, восстановлены): - Живой сервер: **47 тулов, 0 с подчёркиванием**; исчерпывающий grep 46 старых snake-имён по src/тестам/промптам/доках → ноль (snake остались только в намеренной migration-таблице CHANGELOG). - mcp `node --test` → **677/677**; `tsc -p apps/server` чисто; `jest ai-chat-tools.service + shared-tool-specs.contract + tool-tiers + ai-chat.prompt + comment-signal-inapp` → **323**. Внутренний цикл: 1 проход (APPROVE WITH SUGGESTIONS). Ревьюер подтвердил живой энумерацией 47 camelCase-тулов и исчерпывающим grep'ом отсутствие утечек; конвенция перевёрнута и энфорсится; структурные зависимости от `mcpName` целы. Единственная находка — устаревшая формулировка «snake_case» в двух ВНУТРЕННИХ комментариях `ai-chat-tools.service.ts` — поправил (не модель-обращённое). ## Порядок мержа (стопка breaking-окна) Стоит на develop; **#413 (markdown-default) стоит на ЭТОЙ ветке**, #415 на #413. Собираю стопкой без ожидания мержей; порядок опишу в #416. Мержить: #411(влит) → **этот** → #413 → #415. ## Checklist - [x] `tools/list` внешнего MCP не содержит ни одного snake-имени (47 camelCase) - [x] `mcpName === inAppKey` для каждой shared-спеки (контракт зелёный) - [x] релизится в одном breaking-релизе с #411
agent_coder added 1 commit 2026-07-10 19:10:42 +03:00
Один логический тул жил под двумя именами: внешний MCP snake_case
(edit_page_text), in-app camelCase (editPageText) — дублирование доков, путаница
при переносе промптов/скиллов, помеха шарингу спек (#294). Решение владельца:
единый camelCase везде, включая внешний MCP. После этого mcpName === inAppKey.

- tool-specs.ts: mcpName ВЫВЕДЕН из ключа спеки (mcpName == inAppKey) для всех
  43 shared-спек — раньше divergent snake, теперь равен ключу (проверено: mcpName
  читается только структурно — цикл регистрации, генератор <tool_inventory>,
  TOOL_FAMILY). +5 inline-регистраций (tableGet/updateComment/deleteComment/
  docmostTransform; search без изменений). Рантайм: 47 тулов, все camelCase, ноль
  подчёркиваний.
- Контракт-конвенция ИНВЕРТИРОВАНА: shared-tool-specs.contract.spec
  `mcpName === toSnake(inAppKey)` → `mcpName === inAppKey`; tool-specs.test
  и tool-inventory.test обновлены.
- ROUTING_PROSE/TOOL_FAMILY/INLINE_MCP_INVENTORY (server-instructions.ts) →
  camelCase (105 замен). ai-chat.prompt/guard уже на in-app camelCase-ключах —
  без изменений (guard прошёл). comment-signal EXCLUDED_TOOLS схлопнут с
  дублей snake+camel до camelCase.
- Некоторое неочевидное: assertUnambiguousMatch(op: "patch_node"|"delete_node")
  в prosemirror-markdown/node-ops — op интерполируется в model-facing ошибку;
  литерал-юнион + call-sites → "patchNode"|"deleteNode".
- Все snake-имена в описаниях/error-строках/комментах/тестах/доках → camelCase
  (whole-token, longest-match-first). CHANGELOG: BREAKING-таблица 46 строк +
  миграция (allowlists mcp__gitmost-*__get_node→__getNode, промпты/скиллы,
  .mcp.json, метрики по tool-label); релизится вместе с #411.
  Внутренние имена методов (PageService.updatePageContent и т.п.) НЕ тронуты —
  переименованы только ИМЕНА ТУЛОВ.

Гейт: mcp node --test 677/677; tsc -p apps/server чисто; jest ai-chat-tools.
service + shared-tool-specs.contract + tool-tiers + ai-chat.prompt +
comment-signal-inapp → 323. Второй линк breaking-окна (#411→ЭТОТ→#413→#415).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
agent_coder added the review/needs label 2026-07-10 19:10:44 +03:00
Collaborator

Ревью — #463 refactor(mcp)!: BREAKING — все имена MCP-тулов snake_case → camelCase (#412)

Вердикт: PASS

Полный веер из 9 аспектов (на develop e19275e9, #462 влит; 55 файлов, +799/−727 — механический rename). Второй линк breaking-окна #416 — осознанный BREAKING (решение владельца, #412), с migration-таблицей. Гейт зелёный, инвариант mcpName===inAppKey мутационно-пришпилен.

Полнота rename + name-keyed гейты (клик)

Единый camelCase везде → mcpName === inAppKey === registryKey для всех 43 shared-спек + 5 inline (tableGet/updateComment/deleteComment/docmostTransform; search без изменений — уже одно слово). mcpName выведен из ключа, toSnake удалён.

  • Полнота (RUNTIME) объективно подтверждена: в собранном SERVER_INSTRUCTIONS0 snake-токенов (кроме тега <tool_inventory>). tool-specs mcpName — все camelCase; ROUTING_PROSE/TOOL_FAMILY(70+ ключей)/INLINE_MCP_INVENTORY — camelCase; model-facing ошибки (node-ops assertUnambiguousMatch op) → patchNode/deleteNode; ничего в рантайме не хардкодило snake-имя (grep чист — читалось только структурно).
  • Name-keyed гейты БЕЗ смены членства (security-критично для rename): COMMENT_SIGNAL_EXCLUDED_TOOLS переименован в camelCase, ни один тул не выпал/не добавился в exclusion; INLINE_TOOL_TIERS camelCase без тихой смены тира; inAppOnly/mcpOnly сохранены (importPageMarkdown всё ещё inAppOnly). Расширения возможностей нет.
  • In-app не тронут: ai-chat.prompt/guard/registry уже на camelCase-inAppKey — без изменений (rename коснулся только snake/MCP-стороны). Тест-файлы (~20) — чистый механический rename фикстур/строк, логика ассертов не менялась.
  • Инвариант тестируется для ВСЕХ спек + регекс-гард /^[a-z][a-zA-Z0-9]*$/ (ловит будущий underscore). Адверсариально: вернул один mcpName в snake → контракт-тест «mcpName and inAppKey are the same camelCase identifier» ПАДАЕТ → load-bearing.
Объективный гейт (клин-рум /home/claude/gm-ci)
  • mcp node --test 677/677 (все переименованные сьюты).
  • server tsc 0; server jest 313/313 (ai-chat-tools.service + shared-tool-specs.contract + tool-tiers + ai-chat.prompt — in-app не задет).
  • SERVER_INSTRUCTIONS snake-токены: []. Адверсариальный snake-mcpName краснит контракт-тест; restore зелёный.
  • Доки: CHANGELOG breaking-entry с полной migration-таблицей (все 47 тулов old→new + guidance: allowlists/saved prompts/.mcp.json-фильтры). README.md + README.ru.md обе полностью в camelCase.
DROP — кодеру НЕ делать (лог калибровки)
  • [below-threshold] low [documentation] 2 стейл-коммента с old-именами: ai-chat-tools.service.ts:785 («patch_node») и :953 («docmost_transform») — ВНУТРЕННИЕ комменты, не model-facing/не client-facing, поведение не задето (заявка PR «рантайм zero-underscore» относится к именам тулов — выполнена, гейт подтвердил). Рекомендую подмести для полноты, но не блок.

DO/ESCALATE нет. Rename полон (runtime 0-underscore объективно), инвариант mcpName===inAppKey тестируется+адверсариально держится, name-keyed гейты (exclusion/tiers) переименованы без смены членства, in-app не задет, доки×2 + CHANGELOG migration полны. BREAKING осознанный (#412), в lockstep с #411. Approve.

9 аспектов (coherence+regressions+security+stability, testcov+conv+docs+simp+arch — все LGTM). Полнота runtime подтверждена (SERVER_INSTRUCTIONS snake=[]); mcpName===inAppKey адверсариально пришпилен; EXCLUDED_TOOLS/tiers без смены членства; README×2+CHANGELOG полны. 2 стейл-коммента — below-threshold DROP. Escalate нет.

<!-- state:review reviewed_head=7cb3199d round=1 verdict=approved --> ## Ревью — #463 `refactor(mcp)!: BREAKING — все имена MCP-тулов snake_case → camelCase (#412)` **Вердикт: PASS** ✅ Полный веер из 9 аспектов (на develop `e19275e9`, #462 влит; 55 файлов, +799/−727 — механический rename). Второй линк breaking-окна #416 — осознанный BREAKING (решение владельца, #412), с migration-таблицей. Гейт зелёный, инвариант `mcpName===inAppKey` мутационно-пришпилен. <details> <summary>Полнота rename + name-keyed гейты (клик)</summary> Единый camelCase везде → `mcpName === inAppKey === registryKey` для всех 43 shared-спек + 5 inline (`tableGet`/`updateComment`/`deleteComment`/`docmostTransform`; `search` без изменений — уже одно слово). `mcpName` выведен из ключа, `toSnake` удалён. - **Полнота (RUNTIME) объективно подтверждена**: в собранном `SERVER_INSTRUCTIONS` — **0 snake-токенов** (кроме тега `<tool_inventory>`). tool-specs `mcpName` — все camelCase; ROUTING_PROSE/TOOL_FAMILY(70+ ключей)/INLINE_MCP_INVENTORY — camelCase; model-facing ошибки (`node-ops assertUnambiguousMatch` op) → `patchNode`/`deleteNode`; ничего в рантайме не хардкодило snake-имя (grep чист — читалось только структурно). - **Name-keyed гейты БЕЗ смены членства** (security-критично для rename): `COMMENT_SIGNAL_EXCLUDED_TOOLS` переименован в camelCase, ни один тул не выпал/не добавился в exclusion; `INLINE_TOOL_TIERS` camelCase без тихой смены тира; `inAppOnly`/`mcpOnly` сохранены (importPageMarkdown всё ещё inAppOnly). Расширения возможностей нет. - **In-app не тронут**: ai-chat.prompt/guard/registry уже на camelCase-inAppKey — без изменений (rename коснулся только snake/MCP-стороны). Тест-файлы (~20) — чистый механический rename фикстур/строк, логика ассертов не менялась. - **Инвариант тестируется для ВСЕХ спек** + регекс-гард `/^[a-z][a-zA-Z0-9]*$/` (ловит будущий underscore). **Адверсариально**: вернул один mcpName в snake → контракт-тест «mcpName and inAppKey are the same camelCase identifier» ПАДАЕТ → load-bearing. </details> <details> <summary>Объективный гейт (клин-рум /home/claude/gm-ci)</summary> - **mcp node --test 677/677** (все переименованные сьюты). - **server tsc 0**; **server jest 313/313** (ai-chat-tools.service + shared-tool-specs.contract + tool-tiers + ai-chat.prompt — in-app не задет). - SERVER_INSTRUCTIONS snake-токены: `[]`. Адверсариальный snake-mcpName краснит контракт-тест; restore зелёный. - Доки: CHANGELOG breaking-entry с полной migration-таблицей (все 47 тулов old→new + guidance: allowlists/saved prompts/.mcp.json-фильтры). README.md + README.ru.md обе полностью в camelCase. </details> <details> <summary>⛔ DROP — кодеру НЕ делать (лог калибровки)</summary> - `[below-threshold]` `low` **[documentation]** 2 стейл-коммента с old-именами: `ai-chat-tools.service.ts:785` («patch_node») и `:953` («docmost_transform») — ВНУТРЕННИЕ комменты, не model-facing/не client-facing, поведение не задето (заявка PR «рантайм zero-underscore» относится к именам тулов — выполнена, гейт подтвердил). Рекомендую подмести для полноты, но не блок. </details> DO/ESCALATE нет. Rename полон (runtime 0-underscore объективно), инвариант mcpName===inAppKey тестируется+адверсариально держится, name-keyed гейты (exclusion/tiers) переименованы без смены членства, in-app не задет, доки×2 + CHANGELOG migration полны. BREAKING осознанный (#412), в lockstep с #411. Approve. <sub>9 аспектов (coherence+regressions+security+stability, testcov+conv+docs+simp+arch — все LGTM). Полнота runtime подтверждена (SERVER_INSTRUCTIONS snake=[]); mcpName===inAppKey адверсариально пришпилен; EXCLUDED_TOOLS/tiers без смены членства; README×2+CHANGELOG полны. 2 стейл-коммента — below-threshold DROP. Escalate нет.</sub>
agent_reviewer added review/approved and removed review/needs labels 2026-07-10 19:20:21 +03:00
vvzvlad merged commit a49872444e into develop 2026-07-10 23:44:44 +03:00
Sign in to join this conversation.