# Сборка: собрать своё Дополнение к SKILL.md — методика для сборки С НУЛЯ. Разбор ЧУЖОЙ сборки (пришедшей STEP/импортом) — `reference/import-playbook.md`. Плейбук: **создать → вставить → ЗАФИКСИРОВАТЬ базовую → сопрячь → rebuild → проверить.** 1. **Детали сначала сохрани в файлы.** Компонент вставляется ссылкой на `.m3d`/`.a3d`, поэтому несохранённую деталь вставить нельзя. 2. **`document_create assembly` → `assembly_add_component(filePath, x, y, z, rx, ry, rz)`.** Углы — в градусах, вокруг СОБСТВЕННЫХ осей компонента и по очереди X→Y→Z: второй угол считается уже от повёрнутого положения. Пока задан один угол, разницы с мировыми осями нет. 3. **Зафиксируй базовую деталь СРАЗУ: `assembly_fix_component(componentIndex=0, fixedState=true)`.** КОМПАС не закрепляет никого сам, включая первый компонент, и решатель двигает того, кого сочтёт нужным — в том числе основание, вокруг которого ты собираешь всё остальное. Это самая частая причина «сопряжение верное, а сборка расползлась». 4. **Сопрягай:** `assembly_add_mate(mateType, …)` — семь типов, адресация гранью и смысл `orientation` в `help(topic="assembly-mates")`. Что решаешь ты, а не справочник: - **Грань адресуй индексом, а не координатами:** `list_faces(component=N)` → пара `faceIndex`+`componentIndex`. Точки на бумаге считать не нужно, и сервер сам проверит, что грань принадлежит этому компоненту. - **Сторону зазора у `distance` задаёт ВЫБОР ПАРЫ ГРАНЕЙ, и от стартового положения она не зависит.** «Closest» — не «ближайшее»: при сонаправленных нормалях объект 1 садится со стороны −n относительно объекта 2 (замерено двойным прогоном). Практическое правило: бери пару граней, которые смотрят ДРУГ НА ДРУГА. Вышло зеркально — меняй грань, а не `orientation`. - **Первое сопряжение вешай на зафиксированную деталь.** Пока в цепочке нет ни одного закреплённого звена, решатель волен двигать любое; связка «каждый новый компонент — к уже стоящему на месте» разваливается вдвое реже, чем связка «все ко всем». 5. **`rebuild`,** если авто-валидация написала «ℹ Требуется перестроение». Это НЕ ошибка построения: так помечает себя свежий компонент или только что наложенная связь. Бросать работу здесь не надо — правило «не продолжай при ⚠» касается строки со знаком ⚠, а не этой. **Исключение из правила «⚠ = стоп».** После КАЖДОГО сопряжения авто-валидация пишет «⚠ N операц. в ошибке: „Сопряжения“ (код 0: ошибки нет)». Это то же «требуется перестроение», только под знаком ⚠: код 0 и имя операции «Сопряжения» означают, что ломаться нечему. Делай `rebuild` и иди дальше. Настоящая беда со связью видна не здесь, а в `describe_model(sections=mates)` — по пометке `valid:false`. 6. **Проверь:** - `describe_model(sections=components)` — origin, поворот ЧИСЛАМИ (`rx/ry/rz` в градусах, та же семантика, что у вставки) и «зафиксирован/свободен» у каждого: этим и видно, КОГО и НА СКОЛЬКО подвинул решатель; - `describe_model(sections=mates)` — что с чем связано, с каким значением и не выродилось ли. Это ключевой детектор: `assembly_add_mate` может ответить успехом, а связь окажется вырожденной; - `measure(kind1=face, index1=…, componentIndex1=…, kind2=face, index2=…, componentIndex2=…)` — зазор между деталями напрямую, без арифметики по габаритам; - `assembly_check_interference(componentIndex1, componentIndex2)` — **не налезли ли детали друг на друга.** Проверяй все пары, которые должны идти впритирку. **Неудачную связь не нужно пересобирать с нуля:** `assembly_delete(target="mate"|"component", index)` снимает сопряжение или компонент вместе с опирающимися на него связями. Индексы после удаления сдвигаются — иди от больших к меньшим и перечитывай `describe_model(sections=mates)`. **Пересечение деталей не видно НИГДЕ, кроме `assembly_check_interference`.** Сборка складывается из готовых тел, и КОМПАС их не вычитает: две детали могут занимать общий объём, а сопряжения при этом останутся `valid`, раздел `errors` — пустым, объём экспорта — простой суммой компонентов. `measure` тоже не спасает: нулевой зазор одинаково означает и касание, и взаимопроникновение. Проверяй все пары, которые должны идти впритирку. **«Тела: 0» в сборке означает не «пусто», а «спрошено не то»:** тела принадлежат компонентам (`describe_model(component=N, …)`), а `box` и `mass` без `component` честно дают габарит и МЦХ сборки целиком. Про разные системы координат внутри паспорта компонента — `help(topic="model-inspection")`; про локальные координаты граней и `pointOnFace` — `help(topic="face-addressing")`.