name: applied-quality description: Оценка ПРИКЛАДНОГО качества Unity-кода (пакета/системы/подсистемы) по канону «Сценарная прочность» — трассировка логических нитей вход→выход, их прочность, ступенчатость, спутанность и рекурсия. Дополняет code-quality: тот меряет ФОРМУ кода в покое (метрики/формулы), этот — ПОВЕДЕНИЕ в динамике (нить от входа к выходу, что рвётся при повторном входе/сбое/гонке). Триггеры — как у code-quality, но БЕЗ слова «качество»: вместо него корректность/логичность/адекватность/правильность. Примеры: «оцени корректность пакета», «проверь систему на логичность», «оцени адекватность кода», «прогони на правильность», «оцени корректность/логичность/адекватность/правильность системы X». Слово «качество» → это code-quality, не этот скилл. Развилка по LOC: моно (≤2000), шардинг с реконструкцией графа (2000–10000), частичный (>10000).
Прикладное качество кода — «Сценарная прочность» (Unity)
Скилл самодостаточен: канон, оси, рубрики, формула, формат — всё ниже.
На вход — целевой пакет/система/подсистема (или конкретная фича/дифф). На выходе — оценка прочности логических нитей: балл по осям + множитель спутанности + потолок катастроф, с доказательствами в виде сценариев отказа, а не абстрактных счётчиков.
Граница с code-quality (не дублировать)
| code-quality | applied-quality (этот) | |
|---|---|---|
| Меряет | форму: метрики, структуру, паттерны | пригодность в работе: поведение нити вход→выход |
| Единица доказательства | посчитанное нарушение (grep/формула) | сценарий отказа (прогон в голове) |
| Метод | детерминированный | семантический (чтение + рассуждение о рантайме) |
| Пример | Fat Interface, DIT, аллокации | dangling-ссылки, гонки, утечки на re-entry, over-fetch, ступенчатость |
Пересекающиеся термины разводятся: «атомарность» здесь — НЕ размер модели (это code-quality 2.2), а over-fetch по нити; «однонаправленность» здесь — реальная спутанность нитей в рантайме, а не статичный счётчик зависимостей.
0. Триггер и проверка контекста
⚠️ Подтверждение направления (ПЕРЕД запуском, обязательно)
Этот скилл меряет ПРИКЛАДНУЮ ЛОГИКУ / поведение: корректность логических нитей вход→выход, спутанность, ступенчатость, рекурсию — код «в движении», что рвётся на re-entry/сбое/гонке.
Рядом — скилл-близнец code-quality: он меряет ФОРМУ / архитектуру (метрики, структуру, паттерны, связность) — код «в покое».
Триггеры близнецов похожи, поэтому до анализа убедиться, что пользователь хочет именно прикладную логику/корректность. Если формулировка неоднозначна (или могла относиться к архитектуре/форме) — задать ОДИН вопрос и дождаться ответа:
«Оценить прикладную корректность (нити, спутанность, что порвётся в рантайме — applied-quality), или архитектуру/форму (метрики, паттерны, связность — code-quality)?»
- Явно «корректность / логичность / адекватность / правильность / спутанность / что рвётся» → продолжать без вопроса.
- Явно «качество / архитектура / метрики / паттерны» → предложить переключиться на code-quality.
- Просят и то, и другое («качество и корректность») → НЕ пинг-понг между близнецами: выполнить applied-quality и предложить вторым проходом прогнать code-quality (или наоборот), уточнив объём.
Запускается, когда просят оценить прикладное качество / прочность / спутанность конкретного пакета.
Если цель не указана — уточнить:
«Какой пакет/система/фича оценивается? Канон точен на одном пакете ≤2000 LOC; больше — шардинг с предупреждением о деградации.»
Без цели скилл НЕ выполняется.
1. Шаг 0 — измерение размера (всегда)
Измерить LOC всех релевантных .cs (исключить *.Designer.cs, // <auto-generated>, *Tests*, .meta). wc -l достаточно для гейтинга.
bash:
find <target> -name "*.cs" -not -name "*.Designer.cs" -not -path "*/Tests/*" -not -path "*Tests*" -exec wc -l {} + | tail -1
Делегирование: подсчёт LOC + инвентарь (файлы, типы, точки входа/выхода-кандидаты) — через
Agentsubagent_type=Exploreилиgeneral-purposemodel=haiku. Основной контекст не занимать инвентаризацией.
2. Развилка по LOC
Пороги ниже, чем в code-quality: трассировка нитей дороже формул.
| Ветка | LOC | Протокол |
|---|---|---|
| A — моно | ≤ 2000 | весь граф нитей в одном контексте → раздел 8 |
| A+ — шардинг с реконструкцией графа | 2000–10000 | 2–4 шарда по естественным швам (asmdef/системы), каждый ≤ ~2500 LOC → раздел 9 |
| B — частичный (предупреждение) | >10000 или деление неестественное | по-шардовый анализ + швы выборочно, дисклеймер → раздел 10 |
Границы шардов — по швам asmdef/систем, чтобы внутришардовые нити были самодостаточны, а межшардовые рёбра — редкими и явными (проходят через шов). Соотношение размеров max/min ≤ 3, не более 4 групп.
3. Модель анализа: сценарная нить
Единица — логическая нить: путь от точки входа до точки выхода.
Точки входа (нить начинается):
- ввод:
AddActionUser(,performed +=, Unity-input; - события/шины:
On[A-Z]\w+ +=,OnUpdateData +=,OnGameStateChanged; - публичный API, вызываемый другими: методы контроллера,
Run(,Executeкоманд; - Unity-lifecycle с логикой:
OnEnable/Awake/Update/spine-events.
Точки выхода (нить заканчивается):
- представление:
switcher.Set(,ChangeVisibility(,SetActive(, запуск анимации/spine,image.sprite=; - мутация общего состояния: реактив
.Set(, запись модели, смена game-state; - персист:
SaveGlobal, запись сейва; - отдача наружу:
?.Invoke(),LoadAndPlay,PlaySound,return.
Протокол выделения:
- Инвентарь кандидатов вход/выход — делегируется Haiku (grep сигнатур).
- Для каждого входа — трассировка вперёд до выхода(ов): трансформации, ветвления,
await, поднятые события, тронутое общее состояние, пересечения границ. Не делегируется — семантика. - Таблица нитей:
{id, вход→выход, длина(хопы), ветвление, S, пересечения}.
Единица доказательства — нить, не счётчик: «нить #2 от Run() до LoadAndPlay рвётся на fake-null», а не «1 нарушение».
4. Оси (рубрика 0–3)
Балл по каждой оси — с доказательством файл:метод / id нити.
Ось 1 — Атомарность носителя
Меряет НЕ размер модели (толщину игнорировать — это code-quality 2.2). God-модель, замкнутая в своём домене, — норма. Меряет:
- Over-fetch: нить получает полновесный агрегат (
GetData<FatModel>), а читает/пишет малую часть → минус. Метрика:потреблено_полей / получено_полей. Низкое отношение при толстом носителе = over-fetch (ещё и ложная связность: нить привязана к полям, которых не касается). - Right-fetch: нить, которой по существу нужна вся модель (сборщик/сериализатор/оркестратор), тянет её целиком — норма, даже если модель God-типа.
- Доменная замкнутость: агрегат не течёт за границу своего домена. Вынос в чужой домен = минус (пересекается с Ось 4 boundary — учитывать один раз).
| 3 | аппетит ≈ потреблению у всех нитей; толстые модели тянут только законные потребители; ничего не течёт за домен | | 2 | 1–2 нити over-fetch | | 1 | систематический over-fetch: толстая модель раздаётся как «шина», потребители берут крохи | | 0 | агрегат протекает за домен / все тянут всё ради всего |
Ось 2 — Чистота паттернов в динамике
Держат ли паттерны при повторном входе (replay / close→open / reload):
| 3 | relink, owner-lock реактива, сброс кэша/полей, штатные примитивы Vortex; ничего не течёт на re-entry | | 2 | чисто в покое, 1–2 протечки на re-entry | | 1 | протекают: «сбросили одно поле, забыли соседнее»; relink-кэш не обнуляется; утечки ресурсов (спрайты/подписки/токены/таймеры/IDisposable); велосипеды вместо примитивов | | 0 | паттерн-фасад, в динамике разваливается |
Частые маркеры: DeInit/OnDisable обнуляет не все кэши; relink-кэш источника не сброшен в Unsubscribe; статик-состояние без сброса; Dispose() IDisposable не зовётся; новый ресурс присвоен без Dispose() старого.
Ось 3 — Прочность нити (вход→выход)
| 3 | все нити доходят до корректного выхода на всех входах (границы, null, идемпотентность); деградация явная; путь трассируем | | 2 | границы покрыты, но лог/трассировка местами теряются | | 1 | часть нитей рвётся на штатных входах (null/пусто/replay), сбой глотается молча / тихая порча | | 0 | рвутся на штатных входах, тихая порча общего состояния |
Маркеры: NRE на misconfig-путях (незащищённые OnDisable/GetData), деление на ноль, IndexOutOfRange после инкремента, тихий return вместо fail-loud, метод всегда возвращает одно значение (мёртвая ветвь результата).
Ложная точка расширения в динамике (мутация интерфейса в concrete). Нить получает/декларирует абстракцию (IX — параметр, GetData<IX>(), GetService<IX>(), поле-интерфейс), но в теле приводит её к конкретному типу (as Concrete, (Concrete)x, is Concrete c) и зовёт concrete-only логику. Сценарий отказа: подставили валидную альтернативную реализацию IX (mockup / вариант актёра / тестовый двойник) → as→null→NRE ниже, (Concrete)→InvalidCastException, либо тихая потеря поведения. Нить рвётся на штатном «входе» — а входом здесь является какая реализация интерфейса подключена.
- Отличие от code-quality: там downcast штрафуется структурно (сам факт
as Concrete). Здесь — разрыв только при реальном пути подмены реализации. Pre-check (как в code-quality): есть ли уIXиные реализации / mockup / точка инъекции? Нет подмены → латентный смелл, не разрыв (пометить, балл Ось 3 не ронять). Есть → нить рвётся: Ось 3 низко. - ДВА ОРТОГОНАЛЬНЫХ ПОД-ЧЕКА (не путать):
- (a) Тихий разрыв — нить молча возвращает null/no-op при неверном типе (
as … ?.). Это Ось 3, и звонкий гард (if(x==null) throw) его СМЯГЧАЕТ (громкий отказ вместо тихого). - (b) Ложная точка расширения — компонент загружен через абстракцию (
GetService<IX>,AddUI()→IManagedUI, конфиг-префаб, IA-seam), затемas Concrete, иConcreteреализует IB → декларированная расширяемость фиктивна (заместитель обязан БЫТЬ этим concrete). Это Ось 4 (скрытое ×0.6) и гард на неё НЕ влияет:throwлишь меняет режим отказа, а шов остаётся ложным.
- (a) Тихий разрыв — нить молча возвращает null/no-op при неверном типе (
- Не давать «эталон» за звонкий гард. Гард закрывает только (a). Дискриминатор (b) из code-quality: «Есть ли у B интерфейс IB в системе, и загружен ли B через абстракцию?» Да+да → ложная точка (флаг, ×0.6). У B нет интерфейса и это endpoint (Image/Button) → честная связка (ОК).
Ось 5 — Экономность нитей
| 3 | число нитей/ветвлений = задаче; ничего лишнего |
| 2 | небольшой избыток (пара спекулятивных веток / мёртвых полей) |
| 1 | заметный over/under-engineering нитей; спекулятивные/дублирующие НИТИ (одна логика раскопирована на несколько входов); мёртвые ветви результата на пути нити; поллинг-Update без dirty-check |
| 0 | клубок спекулятивных путей / «умные» решения без нужды |
Граница с формой: чисто статическое — закомментированные файлы, мёртвый код, дублирование типов/структур — это форма → code-quality, здесь НЕ считать. Ось 5 меряет избыточность в ДИНАМИКЕ: лишние нити/ветки/поллинг, а не мёртвый текст в покое.
5. Ступенчатость нити (S — счётная характеристика)
Идеал — нить считает в памяти и фиксирует результат один раз на выходе (single-commit). Минус — промежуточные фиксации/коррекции/ожидания на пути.
| Подтип | Вес | Признак |
|---|---|---|
| Ожидание-ответа | 0 если вынужденное (внешний round-trip: LoadAsync/сеть/ввод); +1 если самонаведённое (ждём свой же отложенный шаг / поллинг вместо готового события) |
|
| Промежуточная фиксация | +1 | пишет наблюдаемый результат (реактив/состояние/вью/сейв) до финального выхода |
| Коррекция | +2 | позже перезаписывает/отменяет свой же результат (set A → set !A, откат) |
S_i = взвешенная сумма самонаведённых точек нити.
Заряжается через две оси (без нового члена формулы):
- Ось 3 (рубрика):
S=0→возможно 3; самонаведённое ожидание/фиксация (S≥1)→не выше 2; коррекция→не выше 1. - Ось 4 (эскалация): промежуточная фиксация, чей half-state наблюдаем другими нитями до коррекции, — точка пересечения (
tangle); если связь не видна из сигнатур — скрытая (×0.6).
Частый маркер: замена события завершения (AnimationState.Complete, OnStop) на самонаведённый таймер/NextFrame-перепроверку.
Пример двойного заряда (одна точка → две оси, НЕ дубль): нить OnPointerDown пишет State.Set(Pressed) [промежуточная фиксация, +1], а отложенная NextFrame-перепроверка при драге откатывает State.Set(Free) [коррекция, +2]. Заряд идёт в две оси разного смысла:
- Ось 3 (база) — своя нить негладкая:
S≥1+ коррекция → потолок оси 1; - Ось 4 (множитель) — если half-state
Pressedуспевает прочитать нить визуала ДО отката, это наблюдаемая утечка → +1 tangle (скрытый ×0.6, если связь не видна из сигнатур).
Это не двойной счёт: Ось 3 меряет прочность СВОЕЙ нити, Ось 4 — сцепку с ЧУЖОЙ (разный вред). Запрет двойного счёта действует только ВНУТРИ множителя — ту же точку не заряжать в Ось 4 дважды.
6. Ось 4 — Спутанность (множитель)
Насколько нити переплетены. Три канала пересечения:
| Канал | Признак |
|---|---|
| Общее состояние/событие | нить пишет поле / поднимает событие, которое читает/слушает другая |
| Время/порядок/async | корректность нити B зависит от того, что A отработала раньше (init-order, one-frame, порядок await) |
| Границы пакета/слоя | нить лезет в чужой concrete/внутренности мимо контракта (as Concrete, GetService<Concrete>, прямой static-доступ в обход инжектируемого контракта); сюда же мутация интерфейса в concrete — downcast СВОЕЙ декларированной абстракции (IX → Concrete), когда за ним реальный путь подмены реализации |
| Ложная точка расширения | компонент загружен через абстракцию (AddUI()→IManagedUI, GetService<IX>, конфиг-префаб, IA-seam), затем as Concrete (где Concrete реализует IB) → заявленная сменяемость фиктивна. Всегда скрытое ×0.6, гард не смягчает (в code-quality это arch-маркер ×0.5). Отсеивать по дискриминатору: нет IB у B / B — endpoint движка → честная связка, не флаг |
Разделение по опасности:
- скрытое пересечение — не видно из сигнатур входа/выхода обеих нитей (через статик/глобал/общее событие). Тяжёлый класс → ×0.6.
- явное пересечение — видимая зависимость (переданная ссылка, задокументированный порядок). Лёгкий класс → ×0.9.
НЕ штрафовать как спутанность: чистый fan-out события (один продюсер → N независимых потребителей без взаимного порядка) — это штатная событийная развязка. Owner-locked реактив (поле под owner-ключом: единственный писатель — владелец-контроллер, N независимых читателей) — тот же fan-out, а НЕ общий мутабельный пивот: писать может только владелец, гонки за поле нет → не спутанность. Это санкционированный примитив Vortex, не штрафуется. Штраф Ось 4 — за НЕ-owner-locked общую мутацию: несколько писателей одного поля / гонка за него / порядок записи. Правило: избыточно-но-безопасно → Ось 5; окно рассинхрона / не-owner-locked общий пивот → Ось 4.
Метрики (диагностические, в формулу НЕ входят): N нитей · L длина · B ветвление · X пересечений; сигнальный индекс X/N. Балл двигают счётчики tangle_hidden/tangle_visible (§11), а X/N лишь ориентирует, где клубок:
| X/N | Клубок |
|---|---|
| 0–0.5 | нити почти независимы |
| 0.5–1.5 | умеренная связность |
| >1.5 | спутанный клубок — правка одной нити рвёт другие |
7. Ярус катастроф — рекурсия (hard-cap)
Класс дефектов, обрушивающих живучесть (hang / stack-overflow / event-storm / фриз кадра). Не множитель, а потолок.
Первый член — возможная неконтролируемая рекурсия / цикл нитей: нить через свой выход/промежуточную фиксацию снова запускает свой вход (прямо или по цепочке A→B→A) без гарантированного стопа.
Подтипы: реактивная петля (X.Set в обработчике X.OnUpdateData), событийная (обработчик поднимает то же событие), осцилляция пары (форс-гейт + реопен), спин-луп (while(cond) await без изменения cond).
НЕ катастрофа (цикл + гарантированный стоп): dedup реактива; re-entry guard (if(_flag)return); монотонный прогресс к терминалу; обычная рекурсия с base-case. Помечать «контролируемо».
Проверка ЛОГИКИ рекурсии (не только наличия base-case). Рекурсия часто — штатный ИНСТРУМЕНТ: обход графа/дерева с прогоном до терминала («до тупика»). Проверять не факт рекурсии, а её логику — на обратном ребре должно быть одно из:
- монотонный прогресс к терминалу — спуск к листьям / сжатие фронтира / убывающая мера (глубина, размер остатка);
- visited/dedup-гард, завершающий на back-edge (в т.ч. циклические данные).
Есть надёжный (1) или (2) → корректный инструмент, помечать «контролируемо, traversal».
Канонический пример корректной рекурсии — SerializeController.SerializeClass (рекурсивный спуск по графу модели): терминал — лист (IsSimpleType → return GetSimple, тот самый «прогон до тупика»); цикл в данных (back-edge) ловит visited-сет (VisitedObjects.Add(model) == false) и завершает fail-loud («Serialization failed from cycled model data»). Оба стопа надёжны → чисто, не катастрофа.
Катастрофа — рекурсия, чья логика НЕ даёт ни монотонного прогресса, ни visited-гарда: обход без пометки посещённого по потенциально циклическим данным, взаимная A→B→A без убывающей меры, спуск без гарантии достижения листа.
Правило: цикл без гарантии стопа → катастрофа; цикл с хрупким стопом → тяжёлый скрытый tangle (×0.6); цикл с надёжным стопом → чисто.
Проверка переиспользует граф нитей: найти циклы → на обратном ребре проверить гарантию стопа (семантика, основной контекст). Особое внимание: spine-event→анимация→контроллер→состояние→вью, Update-петли.
8. Ветка A — моно (≤2000 LOC)
- Выделить нити (раздел 3), собрать таблицу.
- По каждой нити — оси 1/2/3/5 (раздел 4) +
S(раздел 5). - Построить граф нитей → Ось 4 (раздел 6) + проверка рекурсии (раздел 7).
- Формула (раздел 11), формат (раздел 12).
9. Ветка A+ — двухфазный шардинг с реконструкцией графа
Наивно резать граф по LOC нельзя — потеряются cross-shard пересечения и циклы. Пер-нитевые оси шардим и усредняем; граф (спутанность + рекурсия) собираем на швах.
9.1 Предложение разбиения
Вывести структуру шардов с LOC и обоснованием границ (естественные швы), проверкой max/min≤3. Дождаться подтверждения (или запустить, оставив возможность сдвинуть швы, если пользователь уже дал «анализируй»).
9.2 Фаза 1 — по шардам, параллельно
Agent model=sonnet, run_in_background:true, по одному на шард. Каждый агент читает ТОЛЬКО свою зону и возвращает:
-
Внутренние нити с осями (1/2/3/5) и
S. -
Внутреннюю спутанность и циклы (с вердиктом контролируемо/катастрофа).
-
Манифест границы (критично для сшивки) — все полуребра за пределы зоны:
- экспонированные входы: public API / поднимаемые события / реактив наружу — с идентити;
- выходы наружу: подписки на чужие события, вызовы чужого API/контроллера/хаба,
Setв общий реактив,static/GetServiceв другие зоны — с идентити и каналом. Формат:{идентити, направление, канал, файл:метод}.
Что есть «идентити» (по нему матчатся полуребра на шве):
- событие —
ОбъявляющийТип.ИмяСобытия; - API/метод —
Тип.Метод(сигнатура); - реактив — конкретный тип
ReactiveValue<T>+ владелец/поле (напр.PointerModel.ScreenPosition); - static/глобал — полное
Namespace.Тип.член.
Матч ребра — совпадение идентити с обеих сторон шва. Если идентити не резолвится однозначно (перегрузки, дженерики, доступ через рефлексию/строковый ключ, событие через обёртку) → ребро помечается
unresolvedи трактуется как ветка B для ЭТОГО ребра: в вывод идёт дисклеймер «cross-shard связь по<идентити>не подтверждена», а НЕ молчаливый пропуск. Скрытая cross-shard рекурсия/спутанность не должна теряться тихо.
Промпт агента должен содержать полную модель (разделы 3–7), т.к. у агента нет этого контекста.
9.3 Фаза 2 — сборка (основной контекст, не делегируется)
- Сшить полуребра по идентити → cross-shard рёбра и cross-shard нити.
- На пересобранном графе: Ось 4 (включая межшардовые пересечения) + рекурсия (циклы через швы).
- Оси 1/2/3/5 и
S— среднее по шардам, с дедупом маркеров по типу (один тип = 1 единица, но перечислить все проявления).
9.4 Сведение
| Величина | Как сводим |
|---|---|
Оси 1/2/3/5, S |
среднее по шардам + обязательно разброс min–max (усреднение маскирует «где болит»: ядро может быть 3, вью 1) |
| Ось 4 спутанность | на пересобранном графе (не усреднять) |
| Рекурсия/катастрофа | на пересобранном графе (цикл может замкнуться через шов) |
10. Ветка B — частичный (>10000 LOC / деление неестественно)
Вывести предупреждение:
⚠️ Объём превышает порог реконструкции графа. Пер-шардовые оси применимы, но cross-shard спутанность и рекурсия могут быть пропущены. Оценка частичная.
Далее: по-шардовый анализ осей + швы выборочно (только явные пивоты), в выводе маркировать «оценка частичная».
11. Итоговая формула
База = (A1 + A2 + A3 + A5) / 12 × 10 # каждая ось 0–3
Сырой = База × 0.6^tangle_hidden × 0.9^tangle_visible
Итог = min(Сырой, CAP)
CAP = 1 если есть цикл БЕЗ гарантии стопа (гарантированный hang/overflow)
CAP = 2 если цикл с хрупким/частичным стопом
CAP = 10 (нет потолка) если катастроф нет
Дизамбигуация: проблема, попавшая и в спутанность, и в другую ось, считается один раз — в более тяжёлой (Ось 4 / потолок). Ступенчатость заряжает Ось 3 (база) и, при утечке half-state, Ось 4 (множитель) — но одну и ту же точку не считать дважды в множителе.
Чувствительность
| hidden | visible | Множитель |
|---|---|---|
| 0 | 0 | 1.000 |
| 0 | 1 | 0.900 |
| 0 | 2 | 0.810 |
| 1 | 0 | 0.600 |
| 1 | 1 | 0.540 |
| 1 | 2 | 0.486 |
| 2 | 0 | 0.360 |
Скрытая спутанность бьёт резко намеренно: невидимые сцепки не чинятся коммитом.
12. Формат вывода
[applied-quality] <target> · Ветка X · <LOC>
⛔ КАТАСТРОФА: <есть/нет> ← если есть, баннер первой строкой, CAP применён
## Карта нитей
| id | вход → выход | S | пересечения |
## Манифест швов (только A+) ← сшитые cross-shard рёбра
| идентити | из→в | канал | скрытое/явное |
## Циклы (проверка рекурсии)
| цикл | гарантия стопа | вердикт |
## Оси (рубрика; для A+ — со столбцами по шардам + min–max)
| Ось | балл | доказательство (id нити / файл:метод) |
## Спутанность (Ось 4)
| пересечение | нити | канал | скрытое/явное |
## Итог
- База / множитель (0.6^h·0.9^v) / CAP / Итог / шкала
- Диагностический сигнал: разрыв База↔Итог
Шкала итога (интервалы полуоткрыты — граница уходит в верхнюю корзину)
- [8–10] — прочный: нити чистые, распутанные.
- [6–8) — хороший, minor проблемы жизненного цикла.
- [4–6) — приемлемый, локальные баги на re-entry/границах.
- [2–4) — проблемный, сложно поддерживать (спутанность/ступенчатость).
- [0–2) — критический (или сработал потолок катастроф).
Диагностический сигнал (обязателен)
- Разрыв База↔Итог большой (Итог < 0.6×База): «Низкий Итог при более высокой Базе — над локальными багами есть скрытая спутанность/рекурсия, которую усреднённые оси не ловят. Смотреть швы прицельно.»
- Разрыв малый: «Оси и Итог близки — спутанности мало, минусы локальны и чинятся коммитами.»
13. Делегирование
- LOC + инвентарь входов/выходов → Haiku (
Explore/general-purpose). - Пер-шардовый анализ нитей + манифест границы (A+) → Sonnet-агенты параллельно (
run_in_background). - Сшивка графа, Ось 4, рекурсия, применение формулы/CAP → основной контекст, не делегируется (семантика).
14. Жёсткие правила
- Единица доказательства — сценарий отказа на конкретной нити, не абстрактный счётчик. Каждый минус привязан к
файл:метод/id нити, иначеn/a. - Размер носителя не оценивается (это code-quality). Оценивается over-fetch по нити + доменная замкнутость.
- Чистота — в динамике: паттерн, чистый в покое, но текущий на re-entry (replay/close→open) — минус. «Держит при повторном входе» — обязательный вопрос.
- Рекурсия без гарантии стопа = потолок, не множитель. Гарантированный стоп (dedup/guard/прогресс/base-case) снимает катастрофу.
- Fan-out события ≠ спутанность. Спутанность — общий мутабельный пивот или окно рассинхрона, не чистая событийная развязка.
- Проверять downcast в ОБЕ стороны. Не только «нить лезет в чужой concrete», но и «нить приводит СВОЮ декларированную абстракцию (
IX) к concrete» — ложная точка расширения в динамике: рвётся при подмене реализации. Разрыв засчитывать только при реальном пути подмены (иначе латентный смелл). - Гард ≠ проход по ложной точке расширения. Звонкий
throw/null-гард закрывает только ТИХИЙ разрыв (Ось 3). Сам ложный шов (абстракция загружена → низведена в concrete, декларированная расширяемость обнулена) остаётся и идёт в Ось 4 (скрытое ×0.6) НЕЗАВИСИМО от гарда. Никогда не выдавать «эталон/done right» за одно лишь наличие гарда наas Concrete. - A+: граф пересобирается на швах. Спутанность и рекурсия считаются глобально, не усредняются. Оси — среднее + разброс min–max.
- Результаты агентов — гипотезы до верификации. Самые тяжёлые находки (катастрофа, деление на ноль, гонка, always-return) при сомнении доверять чтением перед принятием как факт.
- Не смягчать балл «потому что фикс дорогой». Объём фикса — отдельно.