Files
mikhail 5d51b9e1af docs: выноска — TODO, README, ARCHITECTURE, OPEN_QUESTIONS, presentation, CLAUDE.md
Инкремент 9. 83 инструмента, 331 тест. + заметка о ревью реализации в спеке
(Codex + pi/glm-5.1 + pi/kimi-k2.6).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 00:33:33 +03:00

377 lines
61 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Архитектура MCP-сервера КОМПАС-3D (предлагаемый вариант)
> Статус: **реализовано и работает** (v1+v2+STEP/assembly+direct-edit+inspection+package-A «богатые эскизы»+package-B «shell+rib+sweep+loft»+package-C «массивы и зеркало»+package-D start «переменные»+package-E «offset plane»+`hole`+`hole_counterbore`+`hole_countersink`+`hole_conic`+`draft`+`assembly_add_component`+`assembly_add_mate`+`drawing_create_standard_views`+`drawing_fill_title_block`+`drawing_add_linear_dimension`+`drawing_add_diametral_dimension`+`drawing_add_radial_dimension`+`drawing_add_angular_dimension`+`drawing_add_rough`+`drawing_add_text`+`drawing_set_technical_requirements`+ассоциативная привязка диаметрального/радиального к окружности (веха «2D-чертёж», инкремент 7)+`drawing_set_sheet_format` (формат и ориентация листа, инкремент 8)+`drawing_add_leader` (линия-выноска с текстом, инкремент 9)). Актуализировано по коду.
> Сопутствующий контекст по COM API КОМПАС — в [`../CLAUDE.md`](../CLAUDE.md).
> Имена интерфейсов и перечислений сверены со справкой SDK по MD-базе знаний `docs/Kompas3D_SDK/` (субагент `kompas-sdk-research`).
---
## 1. Назначение и контекст
Строим **MCP-сервер**, который даёт LLM управлять CAD-системой **КОМПАС-3D** (АСКОН):
создавать/открывать документы, строить 2D-геометрию, 3D-детали и сборки, читать/писать
параметры, запускать команды.
Жёсткие рамки, заданные природой API:
- **Только Windows, только x64** — КОМПАС автоматизируется через **COM Automation API**;
разрядность сервера должна совпадать с разрядностью установленного КОМПАС.
- **КОМПАС должен быть установлен и запускаем на той же машине.** Сервер — это **COM-клиент**,
а не самостоятельный геометрический движок. Без работающего экземпляра КОМПАС инструменты
бесполезны.
- Целевая среда — **КОМПАС-3D v24 Home** (LT-редакция); часть возможностей полной редакции
может быть недоступна.
Две сосуществующие версии API (подробнее — `CLAUDE.md`):
| | Точка входа | Namespace (C#) | Когда |
|---|---|---|---|
| **API5** (legacy) | `KompasObject` | `Kompas6API5` | bootstrap-подключение, построение 3D через `ksPart` |
| **API7** (современный) | `IApplication` | `KompasAPI7` | всё новое: документы, параметры, операции |
---
## 2. Выбранный стек
| Решение | Выбор | Обоснование |
|---|---|---|
| Язык / платформа | **.NET 8 (LTS), C#, `win-x64`** | COM-интероп первого класса; SDK поставляет именно C#-примеры и `.tlb` |
| MCP SDK | **`ModelContextProtocol`** (официальный C# SDK) | хостинг через `Microsoft.Extensions.Hosting`, DI, готовый stdio-транспорт |
| Транспорт | **stdio** | локальный клиент (Claude Desktop / IDE) запускает сервер дочерним процессом на машине с КОМПАС — проще и безопаснее всего |
| COM-интероп | COM-references на `.tlb` из `SDK\lib` | строгая типизация интерфейсов API7 (`IApplication`, `IPart7`, …) на этапе компиляции |
| Логи | `Microsoft.Extensions.Logging`**stderr** | **stdout занят протоколом MCP** — туда писать нельзя |
| Сериализация | `System.Text.Json` | штатно в .NET, без зависимостей |
Подключаемые типобиблиотеки (`C:\Program Files\ASCON\KOMPAS-3D v24 Home\SDK\lib`):
`kAPI5.tlb`, `kAPI7.tlb`, `ksConstants.tlb`, `ksConstants3D.tlb`, `kAPI2D5COM.tlb`, `kAPI3D5COM.tlb`.
Namespaces: `Kompas6API5`, `KompasAPI7`, `Kompas6Constants`, `Kompas6Constants3D`, `KAPITypes`.
### Почему C#, а не Python
Python (comtypes/pywin32) технически способен управлять COM, но КОМПАС-API активно использует
конструкции, болезненные для динамического интеропа: `out`/`ref`-параметры (например,
`ExecuteKompasCommand(commandID, post, &retval)`), `SAFEARRAY`/динамические массивы
(`ksDynamicArray`, `ksLtVariant`), мосты API5↔API7 (`ksGetApplication7`, `TransferInterface`) и
обязательный STA + насос сообщений. В C# всё это покрыто строго типизированным interop, что
снижает риск и стоимость поддержки.
---
## 3. Модель процесса и потоков (ключевой раздел)
COM-объекты КОМПАС живут в **STA (Single-Threaded Apartment)**, экземпляр приложения —
**единственный** и **однопоточный**. Отсюда — центральное архитектурное ограничение:
- Сервер держит **один выделенный STA-поток**, который **владеет всеми без исключения
COM-вызовами**. Асинхронные обработчики MCP-инструментов (поток-пул) **маршалят** работу в этот
поток через очередь/диспетчер (например, `BlockingCollection<Func<…>>` или собственный
`SynchronizationContext`). Это автоматически **сериализует** доступ к КОМПАС.
- STA-поток крутит **насос сообщений Windows** и периодически вызывает
`IApplication.PumpWaitingMessages()` / при необходимости `EnableTaskAccess(false)` на время
пакетных операций — чтобы диалоги и колбэки КОМПАС не приводили к взаимоблокировке.
```
MCP client ──stdio──> Host (поток-пул, async)
│ ставит задачу в очередь
┌─────────────────────────┐
│ STA-поток (COM owner) │ ← насос сообщений + PumpWaitingMessages
│ KompasObject / IApplication
└─────────────────────────┘
│ COM
КОМПАС-3D.exe
```
### Подключение к КОМПАС
1. Разрешить ProgID. На целевой машине (v24 Home) **проверено**: зарегистрированы
`KOMPAS.Application.7` и `KOMPAS.Application.5`, а `KOMPASLT.*` **отсутствует** — то есть
Home-редакция использует обычные ProgID, а не LT. Порядок попыток:
`KOMPAS.Application.7` (прямой API7) → `KOMPAS.Application.5` (+ `ksGetApplication7()`) →
`KOMPASLT.Application.5` (запасной, для других инсталляций). Выбранный ProgID фиксировать в логе.
2. **Attach** к запущенному экземпляру: `Marshal.GetActiveObject(progId)`.
Если не запущен — **launch**: `Activator.CreateInstance(Type.GetTypeFromProgID(progId))`.
3. Если зашли через API5 — получить современное приложение:
`IApplication appl = (IApplication)kompas.ksGetApplication7();` (через `KOMPAS.Application.7` `IApplication` уже на руках).
4. `appl.Visible = true;` — показать окно КОМПАС; дальше работать через интерфейсы API7.
### Жизненный цикл COM
- Корневые RCW (`KompasObject`, `IApplication`) держим на всё время жизни сервера.
- Временные объекты освобождаем (`Marshal.ReleaseComObject`) в обратном порядке создания.
- `appl.Quit()` вызываем **только если экземпляр запустили мы сами** (флаг «launched-by-us»);
к чужому запущенному КОМПАС не применяем.
---
## 4. Слои решения
Проекты solution `KompasMcp.slnx` (спайк-проекты ConnectSpike/ReconSpike удалены; их механика покрыта тестами):
| Проект | Ответственность |
|---|---|
| **Kompas.Mcp.Host** | Точка входа. Сборка MCP-сервера (stdio), DI (в т.ч. `ConversionService`), логи в stderr, старт и владение STA-потоком, graceful shutdown. Определения инструментов по категориям (System / Documents / Sketch / Features / Query / Conversion). **Тонкий слой**: валидация аргументов → постановка задачи на STA-поток → форматирование результата/ошибки в MCP-ответ. |
| **Kompas.Mcp.Core** | COM-слой. Менеджер соединения, менеджер документов, построитель эскизов и операций, `ConversionService` (STEP импорт/экспорт), `QueryService` (МЦХ, грани, рёбра, компоненты), `ModelInspectionService` (дерево операций, тела, переменные, drill-down, измерения), `AssemblyService` (вставка компонентов в сборку, namespace `Kompas.Mcp.Core.Assemblies`), `DrawingService` (стандартные виды чертежа, namespace `Kompas.Mcp.Core.Drawings`), снимок. Все паттерны API5/API7 живут здесь. |
| **Kompas.Mcp.Tests** | Юнит (без COM) + интеграционные (требуют КОМПАС). 331 тест (201 unit + 130 integration). Все интеграционные классы наследуют `IntegrationTestBase` (`IAsyncLifetime`), который вызывает `DocumentService.CloseAllAsync` после каждого теста. |
Принцип: **только `Core` знает про COM**. `Host`/Tools оперируют доменными DTO и вызывают `Core`; `Host` не содержит бизнес-логики.
Архитектурный принцип: **MCP транслирует возможности SDK КОМПАС в общие инструменты** (не под конкретную задачу). Методический слой поверх MCP — навык `.claude/skills/kompas-3d/` (playbook'и, эвристики). Полигон отработки подходов — `usecases/` (в .gitignore). Отдельный навык `.claude/skills/kompas-fdm-design/` — DFM-методика для FDM/FFF 3D-печати (нависания, толщины, teardrop-отверстия, посадки, ориентация под прочность, elephant foot, бобышки/инсёрты/защёлки) с лёгким гео-аудитом через существующие Inspection-инструменты; работает поверх `kompas-3d`, слайсер вне границ.
---
## 5. Карта инструментов (83 инструмента)
Сгруппированы вокруг центрального цикла «эскиз ↔ операция». Имена — `snake_case`.
**System**
- `kompas_connect` — attach/launch, возвращает версию и редакцию (`GetSystemVersion`, `ApplicationName`).
- `kompas_set_visible` — показать/скрыть окно (`IApplication.Visible`).
- `kompas_status` — состояние соединения, активный документ.
**Documents** (`IApplication.Documents``IDocuments`)
- `document_create` — тип `part | assembly | drawing | fragment` (`DocumentTypeEnum`: Part=4, Assembly=5, Drawing=1, Fragment=2).
- `document_open` / `document_save` / `document_close` / `document_active`.
**Sketch** (2D-геометрия внутри 3D-эскиза)
- `sketch_create` — на базовой плоскости (`o3d_planeXOY` / `XOZ` / `YOZ`) или на выбранной грани.
- `sketch_create_on_offset_plane` — эскиз на плоскости, смещённой от базовой (XOY/XOZ/YOZ) на `offset` мм; вспомогательная геометрия через `o3d_planeOffset=14` / `ksPlaneOffsetDefinition`. Разблокирует `loft` (параллельные сечения на разной высоте). Начало пакета E «вспомогательная геометрия».
- `sketch_add_line` / `sketch_add_circle` / `sketch_add_arc` / `sketch_add_arc_3points` / `sketch_add_rectangle`.
- `sketch_add_ellipse` (centre, semi-axes A/B, rotation angle) / `sketch_add_polyline` (point chain, closed) / `sketch_add_polygon` (regular, inscribed/circumscribed) / `sketch_add_spline` (cubic NURBS, closed) / `sketch_add_point`.
- `sketch_close` — завершить редактирование.
- Жизненный цикл: `NewEntity(o3d_sketch)``SetPlane(plane|face)``BeginEdit()`
`ksLineSeg` / `ksCircle` / `ksArcBy3Points` / `ksArcByAngle` / `ksEllipse` / `ksRegularPolygon` / `ksNurbs` / … → `EndEdit()`.
- `PartModeler` split into partial classes: `PartModeler.cs` (core), `PartModeler.Sketch.cs`, `PartModeler.Features.cs`. Static `SketchGeometry` class holds mappings and validators. Point lists use `record SketchPoint(X, Y)` (JSON `x`/`y`). All angles in degrees.
- `CoordinateAxis.cs` (`src/Kompas.Mcp.Core/Modeling/`) — enum `CoordinateAxis {X,Y,Z}` + `CoordinateAxes.ToObj3dType/Parse` (→ `o3d_axisOX/OY/OZ = 71/72/73`), analogous to `BasePlane.cs`.
**Features** (3D-операции)
- `extrude_boss` / `extrude_cut` — sketch, depth, direction, endType.
- `revolve_boss` / `revolve_cut` — угол.
- `shell` — превратить тело в оболочку: открыть грани по индексам (`faceIndices`, ≥1, из `list_faces`), задать толщину стенки (`thickness` мм), направление (`outward`, по умолчанию внутрь). Реализовано через API5 `ksPart.NewEntity(o3d_shellOperation=43)``ksShellDefinition``FaceArray()``Create()`. Маппинг: `thinType = !outward`.
- `rib` — построить ребро жёсткости от разомкнутого контура эскиза до тела. Параметры: `sketchId`, `thickness` (мм), `side` (`left|right|up|down` → 0/1/2/3), `symmetric` (толщина симметрична плоскости), `angle` (уклон стенок, °). Реализовано через `ksPart.NewEntity(o3d_ribOperation=44)``ksRibDefinition` (`SetSketch`, `SetThinParam`). `symmetric=true`: `SetThinParam(dtBoth, t/2, t/2)`; иначе `SetThinParam(dtNormal, t, 0)`. Контур должен не касаться тела концами — КОМПАС дотягивает полотно сам.
- `sweep` — кинематическая операция: перемещение замкнутого профиля (эскиз `profileSketchId`) вдоль траектории (эскиз `pathSketchId`), образуя сплошное тело. Профиль и траектория на разных (обычно перпендикулярных) плоскостях. Реализовано через `ksPart.NewEntity(o3d_baseEvolution=45)``ksBaseEvolutionDefinition` (`SetSketch(профиль)``PathPartArray().Add(траектория)``sketchShiftType=0``SetThinParam(false)`) → `Create()`. Валидация: `profileSketchId != pathSketchId`.
- `loft` — операция по сечениям: построить сплошное тело по ≥2 закрытым эскизам-сечениям на параллельных плоскостях. Реализовано через `ksPart.NewEntity(o3d_baseLoft=30)``ksBaseLoftDefinition` (`Sketchs().Add(каждое сечение)``SetLoftParam(closed=false,false,true)``SetThinParam(false)`) → `Create()`. Для сечений не на базовых плоскостях использовать `sketch_create_on_offset_plane`.
- `linear_pattern` — линейный массив операций вдоль координатной оси (`o3d_meshCopy=35`, `ksMeshCopyDefinition`); параметры: `featureIds[]`, `axis` (X/Y/Z), `count` (включает исходный, ≥2), `step` (мм). `SetAxis1` + `SetCopyParamAlongAxis(true,0,count,step,false)` + `count2=1` (выключает 2-е направление).
- `circular_pattern` — круговой массив вокруг координатной оси (`o3d_circularCopy=36`, `ksCircularCopyDefinition`); параметры: `featureIds[]`, `axis`, `count`, `step` (угол° между соседними), `reverse`, `geometric`. Свойства `count1=1`/`count2=count`/`step2=angle°`/`factor2=false`/`inverce=reverse` задаются напрямую; `GetOperationArray()`.
- `mirror_operation` — зеркальная копия операций (`o3d_mirrorOperation=48`, `ksMirrorCopyDefinition`); параметры: `featureIds[]`, `plane` (XOY/XOZ/YOZ). `SetPlane` + `GetOperationArray()`.
- `mirror_body` — зеркало всего тела (`o3d_mirrorAllOperation=49`, `ksMirrorCopyAllDefinition`); параметр: `plane`. `ChooseBodies()` не приводится к `ksChooseBodies` и не нужен — операция отражает все тела, сохраняя оригинал (объём удваивается).
- `hole` — цилиндрическое отверстие (сквозное или глухое) на грани, найденной по мировой точке (x,y,z). Параметры: `diameter` (мм), `depth` (мм, для глухого), `throughAll`. Реализовано через **API7** (`HoleService`, `src/Kompas.Mcp.Core/Modeling/HoleService.cs`) — в API5 интерфейс `ksHoleDefinition` отсутствует в interop. Паттерн: `(IModelContainer)part7``Points3D.Add()` (центр, `IPoint3D`) → `Holes3D.Add()``IHole3D` (`HoleType=ksHTBase`, `Diameter`, `DepthType`, `Depth`, `EndFaceType=ksEFFlat`) → `(IHoleDisposal)hole` (`BaseSurface=грань` через `FindObjectsByPoint`, `Perpendicular=true`, `AssociationVertex=point`) → `Update()``RebuildDocument()`. Направление сверления определяется **по факту убыли объёма**: `Direction=true` → Rebuild → сравнить объём (API5 `CalcMassInertiaProperties`); если не убыл → `Direction=false`. При неуспехе — откат через `IFeature7.Delete()`. Возвращает подтверждение без id (отверстие не попадает в реестр `_features` API5).
- `hole_counterbore` — отверстие с цековкой (цилиндрическое уширение сверху, под винт с цилиндрической головкой). Параметры: `x,y,z`, `diameter`, `spotfaceDiameter` (>diameter), `spotfaceDepth`, `depth=0`, `throughAll=false`. `HoleType=ksHTCounterbore`; `HoleParameters` приводится к `ISpotfacingHoleParameters` (`SpotfacingDiameter`, `SpotfacingDepth`) — настройка через `configure`-колбэк после фиксации типа. Для глухого: валидируется `depth>spotDepth`.
- `hole_countersink` — отверстие с зенковкой (коническое уширение сверху, под винт с потайной головкой). Параметры: `x,y,z`, `diameter`, `sinkDiameter` (>diameter), `sinkAngle` (0<angle<180, типично 90°), `depth=0`, `throughAll=false`. `HoleType=ksHTCountersinking`; `HoleParameters``ICountersinkHoleParameters` (`CountersinkType=ksCTDiameterAngle`, `CountersinkDiameter`, `CountersinkAngle`). Все три инструмента отверстий используют общую логику размещения и подбора направления (`HoleCore`).
- `hole_conic` — коническое (конусное) отверстие, сужающееся вглубь. Параметры: `x,y,z`, `diameter` (диаметр у основания/поверхности), `conicAngle` (угол конуса, 0<angle<180°), `depth=0`, `throughAll=false`. `HoleType=ksHTConic`; `HoleParameters``IConicHoleParameters` (`ConicType=ksCNAngle`, `ConicAngle`). Завершает набор типов отверстий (простое, цековка, зенковка, коническое).
- `draft` — уклон граней на угол `angle` (°, строго 0–90) относительно нейтральной координатной плоскости `neutralPlane` (XOY/XOZ/YOZ). `outward=true` — расширение (добавляет материал), `false` — сужение. Реализовано через **API5** `ksInclineDefinition` (`o3d_incline=42`) — операция называется Incline в API5, а не Draft. Паттерн: `ksPart.NewEntity(o3d_incline)``GetDefinition() as ksInclineDefinition``FaceArray()` (грани по индексам из `list_faces`) → `SetPlane(базовая координатная плоскость)``angle``direction=!outward``Create()` → регистрация в `_features`. Эмпирика: `direction=false`=расширение, `direction=true`=сужение — **обратно справке** → маппинг `def.direction = !outward`. Валидация: `RequireDraftAngle(0<angle<90)`. Регистрируется в `_features` → применимы массивы и зеркало (пакет C).
- `rebuild` — перестроить деталь.
**Edit** (прямое редактирование)
- `move_face` — сдвинуть грань по мировой точке (x,y,z, мм) на distance мм вдоль нормали; distance>0 — наружу (добавить материал), <0 — внутрь. Работает на импортированной B-rep. Реализовано через API7 `IPart7.FindObjectsByPoint` + `FaceMover`; контейнеры `ISurfaceContainer`/`IModelContainer` получаются COM-QI от `IPart7` в рантайме. Проверено: top_spacer 39.45→41.45 мм.
- `split_solid_by_plane` — рассечь тело плоскостью (по грани или базовой плоскости).
- `move_body` — переместить тело на заданный вектор (dx/dy/dz, мм).
- `boolean_union` — булева операция объединения тел.
**Selection / Query**
- `get_part_info` — МЦХ через API5 `ksPart.CalcMassInertiaProperties(ST_MIX_MM|ST_MIX_KG)`.
- `get_bounding_box` — габарит (`ksPart.GetGabarit`).
- `list_faces` / `list_edges` — перечислить грани и рёбра детали с классификацией и мерами.
- `list_components` — перечислить компоненты верхнего уровня сборки (индекс, имя, обозначение, признак детали, габарит) через `TopPart → IParts7`.
**Conversion** (`ConversionTools.cs`, `ConversionService.cs`)
- `import_step` — импорт .step/.stp в новый документ через встроенный конвертер КОМПАС (код `ksConverterFromSTEP=-3`); параметры `type` (assembly|part), `createComponentFiles`.
- `export_step` — экспорт активного 3D-документа в STEP; `format` = auto|ap203|ap214|ap242.
**Inspection — структурный осмотр модели (приоритетный над снимком)**
- `describe_model` — структурный «паспорт» детали одним вызовом: габарит, МЦХ, тела, сводка топологии (грани/рёбра по типам), дерево построения с параметрами, переменные. **Предпочитать перед `model_snapshot`** — не тратит токены изображения.
- `list_features` — дерево построения с параметрами (глубина/радиус/катеты), имена узлов локализованы КОМПАС.
- `list_bodies` — тела детали: тип (твёрдое/поверхность) и число граней.
- `list_variables` — переменные модели (имя/выражение/значение, флаги external/информационная).
- `describe_face` — drill-down грани по индексу: тип, площадь, нормаль, радиус, число рёбер.
- `describe_edge` — drill-down ребра по индексу: тип, длина, смежные грани, концевые вершины.
- `measure` — расстояние и угол между двумя объектами (face|edge|vertex по индексам), единица `ST_MIX_MM`.
Реализовано через `ModelInspectionService` (`src/Kompas.Mcp.Core/Query/ModelInspectionService.cs`),
рендер текста — `InspectionText` (`InspectionText.cs`, юнит-тестируем без COM).
Ключевые API-паттерны: `ksPart.GetFeature()``ksFeatureCollection` (дерево); `BodyCollection()``ksBody`; `ksPart.GetFeature().VariableCollection``ksVariable` (все переменные; `ksPart.VariableCollection()` — только внешние); `GetMeasurer()``ksMeasurer`.
«Импорт STEP без истории» определяется структурно: `bodyCount > 0 && нет формообразующих операций && features.Count <= bodyCount+1`.
**Variables — управление переменными модели (package D start)**
- `create_variable` — создать переменную (имя, начальное значение, примечание, флаг внешней).
- `set_variable` — задать выражение (константа `"30"` или формула `"width*2+5"`); десятичный разделитель — точка; модель перестраивается, зависимые переменные пересчитываются.
- `delete_variable` — удалить переменную (нельзя при наличии зависимых).
Реализовано через `VariableService` (`src/Kompas.Mcp.Core/Modeling/VariableService.cs`, API5), инструменты — `VariableTools` (`src/Kompas.Mcp.Host/Tools/VariableTools.cs`). DI: `AddSingleton<VariableService>()` в `Program.cs`.
Ключевые API-паттерны: создание — ТОЛЬКО через `ksPart.GetFeature().VariableCollection` (свойство корневого `ksFeature`), а НЕ `ksPart.VariableCollection()` (та возвращает только внешние); Expression — ведущее поле, Value — вычисленный результат; изменение через Expression + `ksPart.RebuildModel()`; после rebuild RCW переменной стал; значение перечитывается через свежую коллекцию (`ReadValueFresh`).
**Ограничение:** переменная управляет геометрией только в параметрической модели, где размеры эскизов привязаны к именам переменных. Наши эскизы строятся литеральными координатами — `set_variable` хранит и вычисляет значение, но геометрию не меняет. Связь размеров эскизов с переменными (параметрические эскизы через API2D) — не реализована (package D продолжение).
**Assembly — построение сборок (`AssemblyService`, `AssemblyTools`, namespace `Kompas.Mcp.Core.Assemblies`)**
- `assembly_add_component` — вставить компонент (.m3d деталь или .a3d подсборка) из файла в активную сборку; задать положение origin (x,y,z мм, мировая СК сборки). Возвращает индекс и имя вставленного компонента. Реализовано через API7: `IParts7.AddFromFile(path, ExternalFile=true, Redraw=true)``IPart7``IPlacement3D.SetOrigin(x,y,z)``UpdatePlacement(true)``RebuildModel(true)`. `RequireActiveAssembly` проверяет `doc.DocumentType == ksDocumentAssembly` до обращения к `TopPart`. Откат при неуспехе через `IFeature7.Delete`. DI: `AddSingleton<AssemblyService>()` в `Program.cs`.
- `assembly_add_mate` — наложить сопряжение между гранями двух компонентов активной сборки по мировым точкам. Параметры: `mateType` (`coincidence` — грани заподлицо | `distance` — зазор `value` мм), `x1,y1,z1`, `x2,y2,z2`, `value=0`. Решатель позиционирует компоненты; возвращает статус `valid`. Реализовано через API7: `top.MateConstraints` (`IMateConstraints3D`) → `Add(MateConstraintType)``BaseObject1/2` (грани через `top.FindObjectsByPoint(x,y,z,FirstLevel=false)`) → `ParamValue``Update()``RebuildModel(true)`; проверка `mate.Valid` (false → ошибка + откат `mate.Owner.Delete`). Enum `MateType { Coincidence, Distance }` в `src/Kompas.Mcp.Core/Assemblies/MateType.cs`; маппинг на `MateConstraintType` (`mc_Coincidence=0`, `mc_Distance=5`). Scope: `coincidence`/`distance` проверены вживую; прочие типы (`parallel`, `concentric`, …) — будущие инкременты.
**Drawing — 2D-чертёж (`DrawingService`, `DrawingTools`, namespace `Kompas.Mcp.Core.Drawings`)**
- `drawing_create_standard_views(partFilePath, scale, x, y)` — создать стандартные ассоциативные виды (спереди/сверху/слева, `ksPtFront/ksPtUp/ksPtLeft`) сохранённой 3D-модели (.m3d/.a3d) на активном чертеже. Реализовано через API7 `IKompasDocument2D.ViewsAndLayersManager.Views.AddStandartViews(path, "#Спереди", object[]{1,3,5}, x, y, scale, dx=20, dy=20)``object[]` передаётся как SAFEARRAY VT_I4. Проверки: `created==3` строго; непустота — сумма `IView.ObjectCount` новых видов (по разнице `IView.Number`) `>0`, иначе ошибка + откат (`IView.Delete`). Возвращает `DrawingViewsResult{Created,Total,ViewNumbers}``ViewNumbers` содержит номера созданных видов (для адресации при простановке размеров). Модель должна быть сохранена до вызова.
- `drawing_fill_title_block(designation?, name?, material?)` — заполнить графы основной надписи (штампа) активного чертежа. `designation` = обозначение документа (графа 2), `name` = наименование изделия (графа 1), `material` = материал (графа 3); нужно хотя бы одно поле. Реализовано: `doc2d.LayoutSheets.ItemByNumber[1].Stamp` (`IStamp`) → `stamp.Text[columnId].Str = text` (индексированное свойство; `IText.Str` замещает содержимое без `Clear`) → `stamp.Update()`. Номера граф `ksStampEnum`: обозначение=2, наименование=1, материал=3. Свой enum `StampField` + `StampFields.ColumnId/Collect` в `src/Kompas.Mcp.Core/Drawings/StampField.cs`. Возвращает число заполненных граф.
- `drawing_add_linear_dimension(x1,y1,x2,y2,x3,y3, orientation, viewNumber)` — поставить линейный размер на виде активного чертежа. Координаты (x1,y1)-(x2,y2) — выносные точки в **локальной СК вида** (мм); (x3,y3) — положение размерной линии; `orientation`: `horizontal`|`vertical`|`parallel`; `viewNumber` — номер вида (0=первый). Значение измеряется автоматически (`AutoNominalValue=true`). Реализовано: `(ISymbols2DContainer)view` (COM-QI от конкретного `IView`, не от листа — размер попадает именно в этот вид) → `LineDimensions.Add()``ILineDimension``Update()``Valid``((IDimensionText)dim).NominalValue`. Ключевая находка: **размеры не входят в `IView.ObjectCount`** (он считает геометрию `IDrawingContainer`); проверять через `ISymbols2DContainer.LineDimensions.Count`. Откат через `dim.Delete()` при ошибке или нулевом значении. Свой enum `DimensionOrientation {Horizontal, Vertical, Parallel}` + `DimensionOrientations.Parse/ToKompas`. Валидаторы `RequireFiniteCoords` + `RequireDistinctPoints`. Новые файлы: `DimensionOrientation.cs`, `DrawingDimensionResult.cs`; инструмент в `DrawingTools.cs`.
- `drawing_add_diametral_dimension(xc,yc,radius, angle, viewNumber, associate=false)` — поставить диаметральный размер (Ø) окружности на виде активного чертежа. `xc,yc` — центр, `radius` — радиус (мм, локальная СК вида); `angle` — направление выноски (градусы → радианы через `DimensionAngles.ToRadians`); `viewNumber` — номер вида (0=первый). `associate=false` — «свободный» размер без привязки (значение = 2·radius); `associate=true`**ассоциативный режим**: `xc/yc/radius` служат ключом для поиска спроецированной окружности на виде (`IDrawingContainer.Circles`, поиск по центру+радиусу с допуском 1 мм) через `CircularObjectMatch`; найденная окружность присваивается `dim.BaseObject`, значение (Ø) читается из геометрии и обновляется вместе с моделью. Реализовано: `RequireSymbols2DContainer(viewNumber)` + `RequireViewContainers``DiametralDimensions.Add()``IDiametralDimension``Update()``Valid``((IDimensionText)dim).NominalValue`. Валидатор `DrawingValidation.RequirePositiveRadius`.
- `drawing_add_radial_dimension(xc,yc,radius, angle, viewNumber, associate=false)` — поставить радиальный размер (R) окружности/дуги на виде активного чертежа. `xc,yc` — центр, `radius` — радиус (мм, локальная СК вида); `angle` — направление выноски (°, по умолчанию 0); `viewNumber` — номер вида. Возвращаемое значение равно **радиусу** (не диаметру). `associate=false` — «свободный» размер (значение = radius); `associate=true`**ассоциативный режим**: поиск окружности по `xc/yc/radius` в `IDrawingContainer.Circles` (допуск 1 мм) через `CircularObjectMatch`, привязка `dim.BaseObject`, значение из геометрии. Реализовано: `RequireSymbols2DContainer(viewNumber)` + `RequireViewContainers``RadialDimensions.Add()``IRadialDimension` (`Xc`, `Yc`, `Radius`, `Angle` в радианах, `DimensionType=true`, `AutoNominalValue=true`) → `Update()``Valid``NominalValue`. Переиспользует `RequirePositiveRadius` и `DimensionAngles.ToRadians`.
- `drawing_add_angular_dimension(xc,yc, x1,y1, x2,y2, x3,y3, angleType, viewNumber)` — поставить угловой размер между двумя сторонами на виде активного чертежа. `xc,yc` — вершина угла; `x1,y1` — точка на стороне 1; `x2,y2` — точка на стороне 2; `x3,y3` — положение размерной дуги (задаёт её радиус); `angleType` = `"min"` (острый) | `"max"` (тупой, 180°-min) | `"more"` (рефлексный >180°); `viewNumber` — номер вида. Значение в градусах измеряется автоматически. Реализовано: `RequireSymbols2DContainer(viewNumber)``AngleDimensions.Add(ksDrADimension)``IAngleDimension` (`Xc`, `Yc`, `X1`, `Y1`, `X2`, `Y2`, `X3`, `Y3`, `DimensionType=ksAngleDimTypeEnum`, `AutoNominalValue=true`) → `Update()``Valid``NominalValue`. Новый enum `AngleDimensionType {Min, Max, More}` + `AngleDimensionTypes.Parse/ToKompas` в `DimensionOrientation.cs`; 9 unit-тестов для маппинга. Размер «свободный» (без `BaseObject`). Валидаторы `RequireFiniteCoords` + `RequireDistinctPoints`.
- `drawing_add_rough(x,y, value?, signType, angle, viewNumber)` — поставить знак шероховатости на виде. `x,y` — положение знака в локальной СК вида (мм); `value` — текст параметра (напр. `"Ra 1.6"`; пусто = знак без значения); `signType`: `"delete"` (с удалением слоя материала) | `"without"` (без удаления) | `"none"` (без указания); `angle` — угол наклона оси знака (°, по умолч. 0); `viewNumber` — номер вида. Реализовано: `ISymbols2DContainer.Roughs.Add()``IRough` (`BranchX0/Y0/Angle`) → `(IRoughParams)rough` (`SignType=ksRoughSignEnum`, `RoughParamText.Str = value`) → `Update()``Valid`. Новый enum `RoughSignType {NoProcessing, DeleteMaterial, WithoutDeleteMaterial}` + `RoughSignTypes.Parse/ToKompas` в `Drawings/RoughSignType.cs`. Возвращает `DrawingAnnotationResult { Value, ViewNumber }`.
- `drawing_add_text(x,y, text, angle, viewNumber)` — свободная текстовая надпись на виде стилем по умолчанию. `x,y` — точка привязки (СК вида, мм); `text` — содержимое (`\n` — многострочно); `angle` — угол (°, по умолч. 0); `viewNumber` — номер вида. Реализовано: `(IDrawingContainer)view.DrawingTexts.Add()``IDrawingText` (`X/Y/Angle`) → `(IText)dt.Str = text``Update()``Valid`. ВАЖНО: текст живёт в `IDrawingContainer` (контейнер геометрии вида), НЕ в `ISymbols2DContainer`; попадание проверяется через `DrawingTexts.Count`. Возвращает `DrawingAnnotationResult { Value, ViewNumber }`.
- `drawing_set_technical_requirements(text)` — технические требования чертежа (единый текстовый блок, уровень документа, не вида). `text` — строки через `\n`. Реализовано: `(IDrawingDocument)doc.TechnicalDemand``td.Text.Str = text``td.Update()`. Перезаписывает прежние (не добавляет). Возвращает число строк.
- `drawing_set_sheet_format(format, landscape, width?, height?, sheetNumber=1)` — задать формат и ориентацию листа активного чертежа. `format`: `"A0"|"A1"|"A2"|"A3"|"A4"|"A5"|"user"`; `landscape`: `false`=книжная/`true`=альбомная; `width`/`height` только для `format=user` (мм, >0, для стандартного должны быть 0). Для `format=user` КОМПАС выводит ориентацию из соотношения сторон, флаг `landscape` игнорируется. Возвращает итоговые формат, ширину, высоту, ориентацию (read-back из COM). Реализовано: `ILayoutSheet.Format` (`ISheetFormat`: `Format=ksDocumentFormatEnum`, `VerticalOrientation`, `FormatWidth/Height`) → `sheet.Update()`. Новые: enum `PaperFormat {A0,A1,A2,A3,A4,A5,User}` + `PaperFormats.Parse/ToKompas/FromKompas`; record `SheetFormatResult {Format,Width,Height,Landscape}`; валидатор `DrawingValidation.ValidateFormatDimensions`; хелпер `RequireLayoutSheet`. API7, `DrawingService`.
- `drawing_add_leader(x,y, textX,textY, text, shelfDirection, viewNumber)` — поставить линию-выноску с текстом на виде активного чертежа. `x,y` — остриё (точка, куда указывает стрелка); `textX,textY` — положение полки/якоря текста; `text` — надпись на полке; `shelfDirection`: `"auto"|"right"|"left"|"up"|"down"` (направление полки; `auto` = по умолчанию КОМПАС); `viewNumber` — номер вида (0 = первый). Координаты в локальной СК вида (мм). Точка острия должна отличаться от точки полки. Возвращает `DrawingAnnotationResult { Value, ViewNumber }`. Реализовано: `ISymbols2DContainer.Leaders.Add(ksDrLeader)``IBaseLeader`; `(IBranchs)bl.AddBranchByPoint(0,x,y)` (остриё — обязательно до `Update`, иначе `RPC_E_SERVERFAULT`); `SetBranchTextPosition(textX,textY)`; `(ILeader)bl.TextOnShelf.Str = text`; опционально `ShelfDirection`; `Update()`. Новый enum `ShelfDirection {Auto,Right,Left,Up,Down}` + `ShelfDirections.Parse/ToKompas` в `Drawings/ShelfDirection.cs`; переиспользует `DrawingAnnotationResult`. API7, `DrawingService`.
**Vision — визуальная обратная связь (fallback)**
- `model_snapshot` — отрендерить активный 3D-документ в PNG и вернуть **как image-контент MCP**,
чтобы мультимодальный агент *увидел* промежуточный результат. Использовать для визуально-пространственных
вопросов, когда структурный осмотр (`describe_model`) недостаточен.
- `set_view` — задать ориентацию вида (`iso` / `front` / `top` / `right` / …), zoom-to-fit и режим
отображения (`ShadedWireframe`) перед снимком — иначе снимок берётся со случайного текущего ракурса.
> **Механизм.** `ksDocument3D.RasterFormatParam()` → `IRasterFormatParam` рендерит документ в растр;
> свойство **`resultArrayBytes`** возвращает изображение как **массив байт в память** (без временного
> файла). Альтернатива — экспортные функции `ksSaveAsToRasterFormat[W]`. Полученные байты сервер
> упаковывает в image-контент MCP-ответа (C# SDK `ModelContextProtocol` это поддерживает).
> Параметры: формат (PNG/JPEG/BMP/TIFF), разрешение, цвет/`greyScale`.
> Снимки делать после значимых операций (не после каждой линии) — каждый кадр расходует
> токены изображения в контексте агента. На v24 Home качество/доступность рендера проверить на прототипе.
**Escape hatch (опционально)**
- `run_kompas_command``IApplication.ExecuteKompasCommand(commandID, post)` для команд,
ещё не обёрнутых в типизированные инструменты. Доступность проверять через
`IsKompasCommandEnable`.
### Замечание об API5 vs API7 для 3D-операций
API7 создаёт операции через `IPart7` → (QueryInterface) `IModelContainer``IExtrusions.Add()`
`IExtrusion`. Примеры SDK при этом активно используют **API5-путь** (`ksPart.NewEntity(o3d_…)`
`ksBossExtrusionDefinition.SetSideParam/SetSketch``Create()`), который хорошо документирован.
**Стратегия v1:** предпочитать API7 там, где он покрывает операцию; падать на API5 `ksPart`-путь
там, где он проще/надёжнее (мост — `kompas.TransferInterface`). Выбор фиксировать в `Core`.
---
## 6. Центральный сценарий: цикл «эскиз → операция → эскиз»
Основной пользовательский поток v1 — итеративное параметрическое моделирование.
```
document_create(part)
sketch_create(plane = XOY) ──► sketch_add_circle(...) ──► sketch_close
extrude_boss(sketch, depth=…, dir=dtNormal, end=etBlind) → цилиндр
set_view(iso, fit) → model_snapshot 👁 агент СМОТРИТ на результат и решает следующий шаг
select_face_by_point(x,y,z) ← выбираем верхнюю грань
sketch_create(face = выбранная) ──► sketch_add_circle(...) ──► sketch_close
extrude_cut(sketch, depth=…) → отверстие
model_snapshot 👁 проверка результата
└──────────► повторять: смотрим → новая грань → новый эскиз → новая операция
```
Соответствие API (на STA-потоке, через `Core`):
1. `Document3D()` / `IKompasDocument3D``IPart7` (вершинная деталь, `pTop_Part`).
2. `part.NewEntity(o3d_sketch)``GetDefinition()``SetPlane(базовая_плоскость | грань)`
`Create()`; `BeginEdit()` → рисование примитивов (`ksLineSeg`, `ksCircle`, `ksArcByPoint`, …) →
`EndEdit()`.
3. `part.NewEntity(o3d_bossExtrusion)``ksBossExtrusionDefinition`
`SetSideParam(direction, ksEndTypeEnum, depth, …)``SetSketch(эскиз)``Create()`.
Для выреза — `o3d_cutExtrusion`; для вращения — `o3d_bossRotated`/`o3d_cutRotated`.
4. Выбор грани для следующего эскиза:
`part.EntityCollection(o3d_face)``SelectByPoint(x, y, z)` → элемент коллекции как плоскость
эскиза.
5. Снимок результата: `set_view` (ориентация + fit) → `ksDocument3D.RasterFormatParam()`
`IRasterFormatParam.resultArrayBytes` → image-контент MCP. Агент анализирует кадр и выбирает
следующий шаг.
Используемые перечисления: `ksDirectionTypeEnum` (`dtNormal`/`dtReverse`/`dtBoth`/`dtMiddlePlane`),
`ksEndTypeEnum` (`etBlind`/`etThroughAll`/`etUpTo…`), `Obj3dType` (`o3d_sketch`, `o3d_bossExtrusion`,
`o3d_cutExtrusion`, `o3d_face`, `o3d_planeXOY`, …).
---
## 7. Обработка ошибок и безопасность
- **Трансляция ошибок COM** в структурированные MCP-ошибки: проверять HRESULT каждого вызова и
опрашивать `kompas.ksGetLastError()` / `IApplication.KompasError`; возвращать клиенту код + текст.
- **Null-чек после каждого приведения** COM-интерфейса (любой каст может вернуть `null`).
- **`.Init()` на param-структурах** перед использованием (`GetParamStruct(...)``.Init()`).
- **Гарантированный `EndEdit`** для эскизов через `try/finally` — незакрытый эскиз ломает документ.
- **Подтверждение деструктивных операций**: закрытие без сохранения, перезапись файла, `Quit`
только по явному флагу в аргументах инструмента.
- **Модель состояния**: инструменты по умолчанию работают с «активным документом»; опционально —
явный хэндл/идентификатор документа.
---
## 8. Сборка и запуск
```powershell
dotnet build -c Release -r win-x64 # сборка
# → kompas-mcp.exe (self-contained, win-x64)
```
Регистрация stdio-сервера у клиента (пример для конфигурации Claude Desktop):
```json
{
"mcpServers": {
"kompas3d": { "command": "C:\\path\\to\\kompas-mcp.exe", "args": [] }
}
}
```
**Ручная проверка (smoke):** запустить КОМПАС (или дать серверу запустить его) → через инструменты
построить простую деталь (выдавить окружность в цилиндр, затем `extrude_cut` — отверстие) →
убедиться визуально в окне КОМПАС → сохранить `.m3d`.
---
## 9. Стратегия тестирования
- **Интеграционные тесты** (требуют установленного КОМПАС): xUnit, категория `Integration`,
гейтятся (не идут в обычном CI без КОМПАС). Покрывают связку Core↔COM и центральный цикл.
- **Unit-тесты** чистой логики **без COM**: маппинг строк↔перечислений, валидация аргументов,
форматирование результатов/ошибок.
- **Smoke MCP**: проверка протокола через **MCP Inspector** или тестовый клиент (list tools, вызов
`kompas_connect`/`document_create`).
---
## 10. Дорожная карта
**Реализовано (v1+v2+STEP/assembly+direct-edit+inspection+package-A+package-B+package-C+package-D start+package-E start+hole+hole_counterbore+hole_countersink+hole_conic+draft+assembly_add_component+assembly_add_mate+drawing_create_standard_views+drawing_fill_title_block+drawing_add_linear_dimension+drawing_add_diametral_dimension+drawing_add_radial_dimension+drawing_add_angular_dimension+drawing_add_rough+drawing_add_text+drawing_set_technical_requirements+associate для диаметрального/радиального+drawing_set_sheet_format+drawing_add_leader):** документы, эскизы (полный набор 2D-примитивов: линия, окружность, дуга, дуга по 3 точкам, прямоугольник, эллипс, ломаная, правильный многоугольник, сплайн NURBS, точка), **вспомогательная геометрия (`sketch_create_on_offset_plane`)**, выдавливание/вырез, вращение, скругление/фаска, **оболочка (`shell`)**, **ребро жёсткости (`rib`)**, **кинематическая операция (`sweep`)**, **операция по сечениям (`loft`)**, **линейный/круговой массив и зеркало (`linear_pattern`, `circular_pattern`, `mirror_operation`, `mirror_body`)**, **отверстие (`hole`, API7)**, **цековка (`hole_counterbore`, API7)**, **зенковка (`hole_countersink`, API7)**, **коническое отверстие (`hole_conic`, API7)**, **уклон (`draft`, API5 `ksInclineDefinition`)**, снимок; `get_part_info`, `get_bounding_box`, `list_faces`, `list_edges`; `import_step`, `export_step`, `list_components`; **`move_face`**, **`split_solid_by_plane`**, **`move_body`**, **`boolean_union`** (прямое редактирование и булевы операции); **`describe_model`, `list_features`, `list_bodies`, `list_variables`, `describe_face`, `describe_edge`, `measure`** (структурный осмотр модели); **`create_variable`, `set_variable`, `delete_variable`** (управление переменными, package D start); **`assembly_add_component`** (вставка компонента в сборку, API7, `AssemblyService`); **`assembly_add_mate`** (сопряжения `coincidence`/`distance`, API7, `IMateConstraints3D`); **`drawing_create_standard_views`** (стандартные ассоциативные виды чертежа, API7, `DrawingService`); **`drawing_fill_title_block`** (заполнение основной надписи/штампа: обозначение, наименование, материал; `IStamp.Text[id].Str`, API7, `DrawingService`); **`drawing_add_linear_dimension`** (линейный размер на виде чертежа: `ISymbols2DContainer`/`LineDimensions.Add`/`ILineDimension`, координаты в локальной СК вида, API7, `DrawingService`); **`drawing_add_diametral_dimension`** (диаметральный размер Ø: `ISymbols2DContainer.DiametralDimensions.Add`/`IDiametralDimension`, Xc/Yc/Radius/Angle в радианах, API7, `DrawingService`; **`associate=true`** — ассоциативная привязка к спроецированной окружности через `dim.BaseObject`, `CircularObjectMatch`); **`drawing_add_radial_dimension`** (радиальный размер R: `ISymbols2DContainer.RadialDimensions.Add`/`IRadialDimension`, значение = радиус, API7, `DrawingService`; **`associate=true`** — ассоциативная привязка аналогично диаметральному); **`drawing_add_angular_dimension`** (угловой размер: `ISymbols2DContainer.AngleDimensions.Add`/`IAngleDimension`, `angleType`=min/max/more, значение в градусах, API7, `DrawingService`); **`drawing_add_rough`** (знак шероховатости: `ISymbols2DContainer.Roughs.Add`/`IRough`/`IRoughParams`, `signType`=delete/without/none, API7, `DrawingService`); **`drawing_add_text`** (свободная текстовая надпись на виде: `IDrawingContainer.DrawingTexts.Add`/`IDrawingText`/`IText`, API7, `DrawingService`); **`drawing_set_technical_requirements`** (технические требования чертежа: `IDrawingDocument.TechnicalDemand`/`ITechnicalDemand`/`IText`, уровень документа, API7, `DrawingService`); **`drawing_set_sheet_format`** (формат и ориентация листа: `ILayoutSheet.Format`/`ISheetFormat`, `ksDocumentFormatEnum`, `VerticalOrientation`/`FormatWidth`/`FormatHeight`, `PaperFormat` enum, API7, `DrawingService`); **`drawing_add_leader`** (линия-выноска с текстом на виде: `ISymbols2DContainer.Leaders.Add(ksDrLeader)`/`IBaseLeader`/`IBranchs.AddBranchByPoint`/`ILeader.TextOnShelf.Str`, `ShelfDirection` enum, API7, `DrawingService`). Класс «2D-чертёж» (инкремент 6): стандартные виды, основная надпись, размеры (линейный, диаметральный, радиальный, угловой), текстовые обозначения (шероховатость, свободный текст, технические требования). **Инкремент 7**: ассоциативная привязка диаметрального и радиального размеров к спроецированной окружности (`IDrawingContainer.Circles`, поиск по центру+радиусу с допуском 1 мм, `CircularObjectMatch`, `dim.BaseObject = circle`); первый шаг к «умному» чертежу. **Инкремент 8**: задание формата и ориентации листа (`drawing_set_sheet_format`); для `format=user` ориентация определяется КОМПАС из соотношения сторон. **Инкремент 9**: линия-выноска с текстом (`drawing_add_leader`); ключевая тонкость: `AddBranchByPoint` обязателен до `Update` (без ответвления — `RPC_E_SERVERFAULT`).
**Следующие приоритеты:**
1. Пакет D «параметрика» (продолжение) — связь размеров эскизов с переменными (параметрические эскизы через API2D). ⚠️ **Исследовано**: `ksCDimWithVariable` недоступен из внешней автоматизации — см. `docs/superpowers/specs/2026-05-27-parametric-sketch-findings.md`.
2. Пакет E «вспомогательная геометрия» (продолжение) — ось, точка, плоскость по трём точкам / по углу.
3. Рассечение/перемещение тела как MCP-инструменты (`SplitSolids`/`BodyRepositions`) — механика есть, продуктизация не закончена.
4. Свойства документа: `IPropertyMng` / `IPropertyKeeper`.
5. **2D-чертёж (продолжение):** инкременты 8–9 добавили формат листа и линию-выноску. Нереализовано: рамка по ГОСТ-стилю (`LayoutLibraryFileName`/`LayoutStyleNumber`), несколько листов; привязка к дуге (`Arcs`), ассоциативный угловой размер (BaseObject1/2, отрезки), ассоциативная шероховатость (`IRough.BaseObject`); обозначения баз (`Bases`), допуски формы (`Tolerances`); специальные выноски (позиция, клеймо, маркер); шероховатость в условиях окончательной обработки.
6. Сборки — продолжение: дополнительные типы сопряжений (`parallel`, `perpendicular`, `concentric`, `angle`, `tangency`; `coincidence`/`distance` реализованы); авто-позиционирование компонентов; спецификации (`ISpecification`).
7. Транспорт **HTTP/SSE** — как опция для удалённых клиентов.
---
## 11. Открытые вопросы
- **Прямое редактирование B-rep, перемещение грани**: решено — `move_face` (`FaceEditService`) работает через `IPart7.FindObjectsByPoint` + `FaceMover`; проверено на импортированной B-rep. Рассечение/перемещение тела (`SplitSolids`/`BodyRepositions`) — механика есть, инструменты не реализованы (потенциальная следующая опция).
- **Дерево операций, тела, переменные, геометрические запросы**: решено — `ModelInspectionService` + `InspectionTools` (7 инструментов); юнит-тестируемый рендер через `InspectionText`.
- **Утечки транзитных RCW** в `PartModeler` (унаследованный паттерн): `EntityCollection`, `GetTopPart()` не освобождаются, накапливаются за длинную сессию.
- **Насос сообщений / CancellationToken**: `CancellationToken` не прерывает идущий COM-вызов; зависший модальный диалог КОМПАС блокирует всю очередь.
- **Embed Interop Types vs вендорские interop-сборки**: выбраны вендорские DLL из SDK `Samples/Common`; менять не планируется.