name: vortex-layer-detect description: Determine the correct architectural layer (1, 2, or 3) for a new system in the Vortex framework BEFORE any code is written. Use this skill when the user is planning, designing, or describing a new system/package/subsystem to be added to Vortex (e.g. "сделаем систему X", "добавим подсистему Y", "хочу пакет для Z" in the context of Vortex). MUST run before code generation. If it is not clear that the requested work belongs to Vortex (vs. an unrelated project), the skill MUST ask the user to confirm before proceeding.
Vortex — определение слоя размещения системы
Платформа: Claude Code (CLI от Anthropic). Размещать в
~/.claude/skills/vortex-layer-detect/SKILL.md(user-level) или.claude/skills/vortex-layer-detect/SKILL.md(project-level). Использует инструментыRead,Glob,Grep. На других LLM-платформах требует адаптации.
Скилл определяет архитектурный слой (1, 2 или 3) для новой системы в Vortex Framework до начала генерации кода и накладывает на дальнейшую разработку соответствующие ограничения.
0. Триггер и проверка контекста
Запускается, когда пользователь описывает новую систему/подсистему/пакет в рамках Vortex.
Если нет явной уверенности, что речь о расширении Vortex (а не об отдельном проекте, прототипе, скрипте), — ОБЯЗАТЕЛЬНО уточнить у пользователя:
«Это расширение Vortex Framework, или отдельная разработка? Скилл определения слоя применяется только к Vortex.»
Без подтверждения скилл НЕ выполняется.
1. Понятийная база
Анализ ведётся по двум независимым осям. Код ещё не написан — судим по описанию задачи.
Ось А — платформозависимость
- Платформонезависимая система: всю заявленную функциональность можно реализовать в чистом .NET (System.*, коллекции, async/await, POCO). Unity API не требуется.
- Платформозависимая система: для реализации заявленного функционала требуется API внешнего рантайма.
«Платформа» в контексте Vortex = Unity по умолчанию (если пользователь явно не указал иную). Steam, Naninovel и другие сторонние SDK — это НЕ платформы, а доменные расширения; их обёртки относятся к слою 3, а не 2.
Вопрос ставится в форме: «потребуется ли API Unity, или функциональность полностью укладывается в чистый .NET?»
Ось Б — доменная связность
- Доменноуниверсальная система: не делает предположений о конкретном продукте, жанре или правилах конкретной игры. Может быть переиспользована в любом продукте семейства. Примеры профиля: сохранение, локализация, аудио, ввод, шина данных, реактивные модели.
- Доменносвязанная система: опирается на конкретные игровые механики, формат данных или правила домена. Пример профиля: тайл-карта с биомами, квесты с типами наград, миникарта боевых юнитов, крафт с рецептами.
Между «универсальна для всего» и «уникальна одной игре» — промежуток семейства продуктов. Это область слоя 3.
2. Решающая матрица
| Платформонезависима | Платформозависима | |
|---|---|---|
| Доменноуниверсальна | Layer 1 | Layer 2 |
| Доменносвязана | Layer 3 | Layer 3 |
Layer 3 определяется ИСКЛЮЧИТЕЛЬНО по доменной связности. Платформозависимость для слоя 3 не имеет значения — это распространённая ошибка чтения правил, на ней нужно делать акцент.
Layer 4 в этом скилле не выводится. Всё доменно-связанное по умолчанию = Layer 3. Демоция в Layer 4 (вынос за периметр фреймворка как код конкретного проекта) — отдельное решение пользователя по итогам ревью качества, не задача этого скилла.
Особый случай — математические/абстрактные системы со внешними данными
Если система представляет собой математическую/алгоритмическую абстракцию, оперирующую неизвестными ей данными извне (граф связей, топологическая сортировка, машина состояний без знания смысла состояний) — она остаётся Layer 1 целиком, без выделения драйвера. Канонический пример: LoaderSystem — жонглирует процессами, не зная их природы.
3. Канонические образцы (для калибровки)
- Чистый Layer 1:
DatabaseSystem,SaveSystem(ядро),LoaderSystem,LogicChainsSystem,ReactiveValue,App/AppModel(ядро). - Чистый Layer 2:
CoreAssetsSystem,InputBusSystem— реализация настолько привязана к конкретному рантайму, что попытка вынести универсальное ядро даёт оверинжиниринг. Camera в качестве образца НЕ используется (была расщеплена не идеально). - Связка Layer 1 + Layer 2:
Settings(ядро) +SettingsDriver,Audio(ядро) +AudioDriver. Шина/контракт в L1, конкретная реализация в L2. - Layer 3:
Sdk.Quests,Sdk.MiniGames,Sdk.GameCore, всеNaniExtensions.*,Steam.*.
4. Правило расщепления системы
Расщепление осмысленно только если итог = «более низкий слой с абстрактной частью» + «более высокий слой с конкретной частью». Иначе это либо дублирование (перепридумывание уже существующей системы), либо потеря смысла.
«Использует» ≠ «пересекает»: если система просто потребляет SaveSystem или UI — это не повод расщеплять. Quest зависит от Save и UI, но сам Quest — целостная Layer 3 система.
Признаки потенциала к расщеплению (триггеры предложения)
- Внутри системы есть абстракция более общая, чем её прикладное применение (граф условий пригоден не только для квестов; машина состояний — не только для миниигр).
- Чётко разделимы «как хранить/обрабатывать данные» и «как применить эти данные к конкретной механике».
- Конкретные правила оформлены как набор расширений, а каркас их вызова — общий и переиспользуемый.
Критерий оправданности расщепления (тест полиморфизма)
Расщепление на L1 + L_N имеет смысл только если подтверждён полиморфизм по реализации:
- Назван минимум один второй домен с идентичной логикой управления, помимо рассматриваемого.
- Гипотетических «может быть пригодится» — недостаточно: нужно реально применимое использование, которое можно назвать прямо сейчас.
Простота L1-ядра сама по себе НЕ является аргументом против выделения. Канонический контрпример — LocalizationSystem: ядро структурно тонкое (словарь + события), но полиморфизм по реализациям подтверждён, и это делает выделение в L1 правильным. Определяющий критерий ровно один — наличие второго реального домена.
Если полиморфизм не подтверждён — рекомендованный вариант = монолит в L_N (без L1). Если подтверждён — рекомендован вариант с расщеплением.
ОБЯЗАТЕЛЬНО
При наличии хотя бы одного признака потенциала к расщеплению скилл в обязательном порядке:
- Предлагает альтернативы явно («А: монолит на Layer N», «Б: расщепить с L1»).
- Прогоняет вариант Б через тест полиморфизма и показывает результат.
- Выдаёт обоснованную рекомендацию скилла с одной строкой обоснования.
Молча отбрасывать предложение нельзя — но и навязывать без обоснования тоже. Финальное решение принимает пользователь.
5. Накладываемые ограничения по слоям
После определения слоя скилл фиксирует ограничения дальнейшей разработки:
Layer 1 (Core)
- Только чистый C# (
System.*, коллекции, async/await, POCO). - Запрещено:
using UnityEngine,MonoBehaviour,ScriptableObject, корутины, Editor API. - Запрещены доменные предположения о продукте.
- Шинные классы (статические синглтоны) — в подпапке
Bus/. - Реактивные данные через
ReactiveValue<T>/IReactiveData. - Если нужна платформенная реализация — выделяется через
IDriver-интерфейс, реализация уйдёт в Layer 2.
Layer 2 (Unity-адаптация)
- Может использовать Unity API.
- Запрещены доменные предположения о продукте.
- Если есть парная Layer 1 шина/контракт — реализуется как драйвер (
SystemController<T, TD>+IDriver). - Чисто Unity-системы без ядра допустимы (как
InputBusSystem,CoreAssetsSystem), но требуют обоснования: «расщепление дало бы оверинжиниринг».
Layer 3 (AppSDK)
- Может использовать любые слои ниже, любые внешние SDK (Naninovel, Steam, и т.д.).
- Допускает доменные предположения семейства продуктов.
- НЕ допускает уникальной логики одного конкретного проекта (это будет триггером демоции в Layer 4 на ревью).
- Не дублирует функционал нижних слоёв — потребляет его.
6. Формат ответа скилла
Скилл выдаёт ответ строго в следующем формате:
## Определение слоя: Layer N
### Анализ
- Платформо-зависимость: <да/нет> — <одна строка обоснования>
- Доменная связность: <универсальна / связана> — <одна строка обоснования>
### Вердикт
Layer N. <одна строка пояснения>
### Накладываемые ограничения
<список релевантных пунктов из раздела 5 для выбранного слоя>
### Альтернативы расщепления (если применимо)
- А: <вариант без расщепления — монолит на Layer N>
- Б: <вариант с расщеплением — что в L1, что в LN>
- (опц.) В: <иная декомпозиция>
### Тест полиморфизма для варианта с расщеплением
- Полиморфизм: <да/нет> — <если да, назвать второй домен с идентичной логикой; если нет — указать, что не найден>
### Рекомендация скилла
Вариант <А или Б>. <одна строка обоснования по итогам теста полиморфизма.>
Финальный выбор — за вами.
Если признаков расщепления нет — секции «Альтернативы», «Тест полиморфизма» и «Рекомендация» опускаются полностью.
7. Граничные случаи
- Описание неоднозначно — задать уточняющие вопросы по двум осям (что-нибудь вроде «нужен ли просчёт без Unity?», «применима ли к любой игре или специфична для X?»). Не выдавать вердикт на догадках.
- Пользователь явно указывает слой сам — всё равно прогнать анализ; если совпадает — подтвердить, если нет — изложить расхождение и попросить решение.
- Система-обёртка над сторонним SDK (Naninovel, Steam, аналитика) — почти всегда Layer 3, даже если сама обёртка тонкая. Сторонний SDK = доменное предположение.
- «Универсальна для семейства» vs «уникальна одной игре» — на этом этапе различать не нужно; всё доменно-связанное идёт в Layer 3 по умолчанию.