Проектные правила для агентов. Bundle-маппинг mode → keys и тексты system-частей (scope=system) живут в декларативном манифесте specs/manifest/throne-system-prompt-parts.yaml — это source для backend runtime и frontend /instructions дерева. Operational layer живёт отдельно как статические skills в skills/ и CLI в bin/: intent, review, dream (см. ADR-0043).
Гейты декларированы в .quality/quality.config.json, бегунок — scripts/quality/verify.py. verify.sh — тонкая bash-обёртка для совместимости.
bash scripts/quality/verify.sh --fast # быстрый цикл (~1 мин, без integration-тестов и audits)
bash scripts/quality/verify.sh # перед сдачей хода (полный)
bash scripts/quality/verify.sh --list # перечень гейтов
bash scripts/quality/verify.sh --only backend-format # один гейт
bash scripts/quality/verify.sh --skip backend-audit # без конкретного гейта
bash scripts/quality/verify.sh --scope backend|frontend # одна сторона--fast пропускает slow: true: backend-test-integration, backend-audit, frontend-audit. Используй --fast в цикле, полный verify.sh — перед сдачей хода. Падает — чинить root cause, не обходить.
Направление зависимостей (диаграмма — канон в readme.md → «Архитектура»): строго внутрь, Api → Application → Domain, Infrastructure → Application → Domain, Api → Infrastructure только в Program.cs / DI wiring.
- Throne.Domain — entities, value objects, доменные правила. Без внешних зависимостей.
- Throne.Application — use cases и порты (
IIntentRepository,IPromptPartRepository). Не знает про конкретный storage. - Throne.Infrastructure — реализация портов (SQLite/EF Core, Git/CLI, terminal adapters).
- Throne.Api — composition root + HTTP transport.
Нарушение направления зависимостей провалит Throne.Architecture.Tests.
Тесты живут в apps/api/tests/Throne.Architecture.Tests/ и запускаются как часть backend-test-unit. Если правило мешает — чинить код, а не тест.
- Layer + whitelist (
LayerDependencyRulesTests): помимо «зависимости только внутрь» — Domain whitelistSystem+Throne.Domain; Application whitelistSystem+Microsoft.Extensions+Throne.Application+Throne.Domain+YamlDotNet. Новый NuGet в Domain/Application = обнови whitelist в тесте + ADR. - ConfigureAwait запрещён в production (
ConfigureAwaitRulesTests): Throne — server-side, нет SynchronizationContext..ConfigureAwait(...)— шум. - Single-operator, owner-оси нет (ADR-0029 § Update): Throne — local-first, один оператор на инстанс. Легаси multi-user слой демонтирован —
owner_user_id/ICurrentUserAccessor, внутренняя авторизация (PAT/JWT/OAuth) и гардOwnerUserIdRulesTestsудалены. Агрегаты не принимаютownerUserId, репозитории не фильтруют по owner. Не вводи owner-/user-дискриминатор в новые сущности и не возвращай auth как продуктовую ось; командные воркспейсы — отдельный сервис, не растягивание локальной модели. - Operational skills (ADR-0043): не генерируй per-intent
SKILL.mdиз C# и не возвращай MCP tools. Новые агентские операции добавляются как статический repo skill +skills/<id>/bin/throne-*CLI поверх HTTP, только если это действительно operational surface. - Inheritance depth / Maintainability Index (Roslyn analyzers
CA1501+CA1505): пороги живут в apps/api/CodeMetricsConfig.txt, severitywarningв apps/api/.editorconfig. Из-заTreatWarningsAsErrors=trueлюбое новое нарушение валитbackend-build. Cyclomatic (CA1502) и class coupling (CA1506) сюда не входят — выведены в.qualitybudget (ADR-0028).
DDD-классификация модулей и зависимостей — общий язык для аргументов «здесь прагматика OK / здесь не OK». Core несёт инварианты и плотные контракты; supporting может быть проще; generic выбирается по impl-volatility (sticky → инвестируем в интеграцию, volatile → прячем за портом). При значимом ADR проверяй классификацию затрагиваемой области и при необходимости обнови таблицу.
| Subdomain | Throne модули / зависимости | Тип | Rationale |
|---|---|---|---|
| Core | Intents, Dreams, PromptParts, PromptPartPatches, IntentLinks, frontier dream flow (ADR-0022), structural patches (ADR-0038) |
core, high volatility | Продуктовая суть Throne; здесь живут rich-DDD агрегаты (ADR-0025) и большая часть итераций по требованиям. |
| Supporting | Tags, Capabilities, Settings, TextVersions history |
supporting | Обслуживают core, своя бизнес-логика мала; допустимы более тонкие модели и прагматичные решения. |
| Generic, impl-volatile | git-провайдеры (gh / GitLab — ADR-0032), terminal vendors (claude / codex / opencode — ADR-0042), IDE openers, tmux, extension axes (ADR-0045, ADR-0046) | generic, высокая impl-volatility | Внешние инструменты меняются и заменяются; обязательно через порт + адаптер, без протечки vendor-специфики в core. |
| Generic, sticky | SQLite/EF Core, OpenAPI / realtime contract-first tooling, .NET ecosystem | generic, низкая impl-volatility | Замена маловероятна; OK инвестировать в идиоматичную интеграцию вместо ещё одного слоя абстракции. |
backend-maintainability — ratchet, blocking на новых нарушениях. Лимиты: .quality/maintainability-budget.json, профиль strict. Baseline: .quality/maintainability-baseline.json. Любое новое нарушение vs baseline = fail без обсуждения. Это единый source-of-truth для cyclomatic (per-method ≤10) и coupling (file fan-out ≤15); калибровка лимитов — ADR-0028.
Baseline регенерируется ТОЛЬКО когда нарушения реально устранены, отдельным коммитом с rationale, не вместе с feature-работой:
bash scripts/quality/maintainability-budget-check.sh \
--config .quality/maintainability-budget.json --profile strict \
--write-baseline-snapshot .quality/maintainability-baseline.jsonbackend-duplicates — advisory-only. Детектор лексический (нормализует identifiers/numbers/strings, скользит окно по логическим строкам, ловит cross-file совпадения). На текущем коде даёт false-positive из-за идиоматических паттернов (EF Core repositories/configurations, Application-handlers, MVC-контроллеры). Поэтому печатает отчёт в выводе verify, но не валит билд и не имеет baseline. Если увидел реальную копи-пасту в отчёте — выноси в общий код по поводу, не «чтобы хэш ушёл».
Чтобы заглушки CA1501/CA1505 (и любых других активных аналайзеров) не накапливались тихо, отдельный гейт scripts/quality/suppression_audit.py сканирует все per-file severity = none в apps/api/.editorconfig и #pragma warning disable в apps/api/**/*.cs, и держит ratchet против .quality/suppress-baseline.json.
Правила для агента:
- Не добавляй новый per-file suppress, чтобы билд прошёл. Сначала рефактор. Если без suppress никак — нужен per-section комментарий с
intent:<id>илиADR-NNNNровно над[section], и отдельный коммит, который пере-снимает baseline с rationale в сообщении. - «Same precedent as ... above» не считается обоснованием — ratchet требует, чтобы intent/ADR-ссылка была в комментарии непосредственно над секцией (lookback 15 строк, разрыв пустой строкой break-ит блок). Это сознательная trение: каждое исключение обязано назвать своё имя.
- Перебаслайнить можно вниз без вопросов (
python3 scripts/quality/suppression_audit.py write-baselineпосле устранения нарушений), и в любую сторону — отдельным коммитом, не вместе с feature-работой.
Запуск гейта изолированно:
bash scripts/quality/verify.sh --only backend-suppressions
python3 scripts/quality/suppression_audit.py list # полный листинг с пометкой OK/???Inheritance depth (CA1501) и Maintainability Index (CA1505) считаются Roslyn-аналайзерами из Microsoft.CodeAnalysis.NetAnalyzers (включён через EnableNETAnalyzers=true). Пороги — apps/api/CodeMetricsConfig.txt. Severity = warning в apps/api/.editorconfig; TreatWarningsAsErrors=true делает их blocking-гейтом на backend-build. Любое новое нарушение валит билд без обсуждения.
Cyclomatic complexity (CA1502) и class coupling (CA1506) выключены (ADR-0028): дублировали .quality budget (per-method CC + file fan-out) и плодили type-level-CC давление на косметические сплиты. Единственный SoT для этих измерений — maintainability budget.
Protected files (ослабление = отдельный коммит с rationale):
- apps/api/CodeMetricsConfig.txt — пороги.
- apps/api/.editorconfig — секции
dotnet_diagnostic.CA15{01,05}.severityи per-file suppress'ы. - apps/api/Directory.Build.props —
<AdditionalFiles Include="...CodeMetricsConfig.txt" />.
- Embedded Run стейджит аттачи в workspace в
.throne/attachments/. - Prompt содержит только имя файла и относительный путь; агент читает файл обычным filesystem read.
- Live add-after-start вне scope: новые аттачи попадают в следующую сессию.
При работе над apps/web или UI-компонентами используй DESIGN.md как источник проектной дизайн-системы.
Server-to-client события описаны в specs/contracts/realtime/events.yaml. Транспорт — SSE на GET /api/v1/realtime/stream. См. ADR-0008.
Handlers Application НЕ публикуют realtime сами. Repository outcome реализует IDomainEventCarrier; декоратор DomainEventDispatchingUnitOfWork после unitOfWork.ExecuteAsync(...) автоматически фанаутит events через IDomainEventDispatcher → RealtimeDomainEventHandler → SSE-broker.
Добавление нового realtime-события (gate realtime падает при «половинной» интеграции):
- Расширь events.yaml: имя, описание,
payloadилиpayload_ref. - Регенерация:
bash scripts/quality/codegen-frontend.shобновитThrone.Contracts/Generated(C# константы) иapps/web/src/shared/realtime/generated. - Добавь record в Throne.Application/Events/IntentEvents.cs (имя — PascalCase от
<event.name>, напримерintent.text_changed→IntentTextChanged). - Сделай так, чтобы соответствующий outcome (или новый wrapper-outcome) возвращал этот event на success-ветке через
Events. - Репозиторий положит event в outcome — никаких publish-вызовов писать не нужно.
- Добавь case в RealtimeDomainEventHandler.cs, маппя domain event →
RealtimeEventNames.<PascalName>+ DTO. - Подпишись через
useRealtimeEvent("<name>", handler)хотя бы в одном местеapps/web/src/.
Для операций вне основной транзакции используй unitOfWork.ExecuteOutsideTransactionAsync(...) — декоратор работает и для неё.
Будущие подписчики на тот же поток (внешний брокер, история, denormalized read-models) подключаются как ещё один IDomainEventHandler в DI — handlers Application не меняются.
- Смена архитектурного стиля или layout слоёв.
- Замена storage / транспорта.
- Включение нового quality pack (coverage, mutation, и т.п.).
- Любой ввод командной/воркспейс-governance, owner-/user-дискриминатора или внутренней авторизации как продуктовой оси. Throne — single-operator local-first (ADR-0029): легаси multi-user слой (
owner_user_id, auth) демонтирован, owner-оси нет. Такие concerns живут в отдельном сервисе со своей governance, а не в локальном ядре.
Шаблон ADR: specs/ADR/.template.md. После добавления — обнови specs/ADR/REGISTRY.md.
Продуктовая постановка приходит вместе с запросом пользователя (например, как приложенный документ или текст в сообщении). В репозитории её не хранится. Не реконструируй намерение из остатков прошлых итераций в коде — спроси, если запрос неполный.