feat: параметрика — переменные модели (create/set/delete_variable) через API5
- VariableService: CreateVariableAsync/SetVariableAsync/DeleteVariableAsync/GetVariableValueAsync - создание ТОЛЬКО на ksFeature.VariableCollection (ksPart — только внешние); RebuildModel + re-fetch - Expression — ведущее поле (константа/формула со ссылками); value пересчитывается - list_variables (ModelInspectionService) исправлен: читает feature-коллекцию (все переменные) - инструменты create_variable/set_variable/delete_variable (VariableTools) + DI - интеграционный тест CRUD round-trip (создание, формула width*2, удаление по зависимостям) - ОГРАНИЧЕНИЕ: переменные драйвят геометрию лишь в параметрической модели (эскизы на литералах — нет) - 116 тестов; спек docs/superpowers/specs/2026-05-27-parametrics-design.md
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
# Дизайн: параметрика (пакет D) — переменные модели
|
||||
|
||||
**Дата:** 2026-05-27
|
||||
**Статус:** реализовано и проверено (тест зелёный); на ревью (ревьюер — Codex)
|
||||
|
||||
## Цель
|
||||
|
||||
Дать запись параметрики: **создание, изменение и удаление переменных модели** (`list_variables`
|
||||
уже читает). Это фундамент управляемых моделей: пользовательские переменные, формулы со ссылками,
|
||||
внешние переменные для сборок.
|
||||
|
||||
## Сигнатуры (рефлексия interop + справка)
|
||||
|
||||
```
|
||||
ksVariableCollection:
|
||||
object AddNewVariable(string name, double value, string note) // создать (ТОЛЬКО на ksFeature!)
|
||||
object GetByName(string name, bool testFullName, bool testIgnoreCase)
|
||||
bool RemoveVariable(string name)
|
||||
int GetCount(); object GetByIndex(int)
|
||||
ksVariable:
|
||||
string name; string Expression; double value; bool external; bool Information; string note
|
||||
ksPart: bool RebuildModel() // применить изменения переменных
|
||||
ksFeature: object VariableCollection // СВОЙСТВО (не метод), все переменные детали
|
||||
```
|
||||
|
||||
## Ключевые факты (исследование + эмпирика spike)
|
||||
|
||||
1. **Создавать переменные можно только на коллекции корневого `ksFeature`**
|
||||
(`ksPart.GetFeature().VariableCollection`), НЕ на `ksPart.VariableCollection()` (та — только
|
||||
внешние). `AddNewVariable` на ksPart-коллекции не создаёт пользовательскую переменную.
|
||||
2. **`Expression` — ведущее поле**, `value` — вычисленный результат. Менять значение надо через
|
||||
`Expression` (константа «30» или формула «width*2»); прямое `value=` ненадёжно (перезапишется).
|
||||
3. **Изменения вступают в силу после `ksPart.RebuildModel()`**; `value` пересчитывается из
|
||||
`Expression`. RCW переменной после RebuildModel «застревает» на старом значении — **перечитывать**
|
||||
переменную из свежей коллекции (`ReadValueFresh`).
|
||||
4. **`list_variables` исправлен**: читал `ksPart.VariableCollection()` (только внешние) → теперь
|
||||
`ksPart.GetFeature().VariableCollection` (все, включая созданные), с фолбэком. Иначе созданная
|
||||
переменная не была бы видна агенту.
|
||||
5. **Удаление**: нельзя удалить переменную, на которую ссылаются другие (RRemoveVariable→FALSE);
|
||||
удалять в порядке зависимостей.
|
||||
6. **ОГРАНИЧЕНИЕ (важно для контракта):** переменная управляет геометрией только в
|
||||
**параметрической** модели (размеры эскизов связаны с именами переменных). Наши эскизы строятся
|
||||
литеральными координатами — у них нет именованных размеров, поэтому set_variable хранит/считает
|
||||
значение, но геометрию не меняет. Привязка размеров эскиза к переменным (параметрические эскизы)
|
||||
— отдельный большой пласт (будущее). Поэтому тест проверяет CRUD/вычисление через чтение, а не
|
||||
изменение геометрии.
|
||||
|
||||
## MCP-инструменты (новая группа, `VariableTools`)
|
||||
|
||||
| Инструмент | Параметры | Поведение |
|
||||
|---|---|---|
|
||||
| `create_variable` | `name`, `value`, `note?`, `external=false` | Создать переменную. Возвращает значение. |
|
||||
| `set_variable` | `name`, `expression` | Задать выражение (константа/формула), перестроить, вернуть значение. |
|
||||
| `delete_variable` | `name` | Удалить (нельзя, если есть зависимые). |
|
||||
|
||||
Чтение — существующий `list_variables` (теперь видит все переменные).
|
||||
|
||||
## Реализация
|
||||
|
||||
- **`src/Kompas.Mcp.Core/Modeling/VariableService.cs`** (новый): `CreateVariableAsync`,
|
||||
`SetVariableAsync`, `DeleteVariableAsync`, `GetVariableValueAsync` (read-back) на STA-потоке.
|
||||
Хелпер `RootVariables()` → (`ksPart`, feature-коллекция); `ReadValueFresh(name)` после RebuildModel.
|
||||
Валидация: имя не пусто, value конечно, выражение не пусто.
|
||||
- **`VariableTools.cs`** (новый): 3 инструмента; DI `AddSingleton<VariableService>()`.
|
||||
- **`ModelInspectionService.ReadVariables`**: источник → feature-коллекция (фолбэк на ksPart).
|
||||
- Транзитные RCW не освобождаем точечно — консистентно (долг v2-2).
|
||||
|
||||
## Тестирование (Integration, `VariableTests`)
|
||||
|
||||
CRUD round-trip: построить коробку (дерево построения) → `create_variable("width",40)` (значение 40;
|
||||
видна в `list_variables`) → `set_variable("width","12+8")` → 20 → создать `height`, `set "width*2"` →
|
||||
40 (формула со ссылкой) → удалить `height`, затем `width` (порядок зависимостей) → обе исчезли
|
||||
(`GetVariableValueAsync` бросает `KeyNotFoundException`). ✓
|
||||
Reference in New Issue
Block a user