Архитектурный аудит по трём осям: намерение, структура, поведение git-истории. Находка допускается, только когда измерена её цена. Вызывать при «разбери архитектуру», «где техдолг», «что рефакторить», «оцени кодовую базу», «изучи чужой репо», «стоит ли переписывать», перед крупным рефакторингом и при планировании миграции. Сюда же — жалобы на цену изменения, в которых слова «архитектура» нет: боимся трогать модуль, страшно менять, почему тут больно менять, одна правка задевает соседние файлы,...
Scanned 9/3/2026
Install to Claude Code
npx -y skills add Socialpranker/zodchiy --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of zodchiy?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/socialpranker-zodchiy)More formats (shields.io, HTML) on the badges page.
---
name: zodchiy
description: "Архитектурный аудит по трём осям: намерение, структура, поведение git-истории. Находка допускается, только когда измерена её цена. Вызывать при «разбери архитектуру», «где техдолг», «что рефакторить», «оцени кодовую базу», «изучи чужой репо», «стоит ли переписывать», перед крупным рефакторингом и при планировании миграции. Сюда же — жалобы на цену изменения, в которых слова «архитектура» нет: боимся трогать модуль, страшно менять, почему тут больно менять, одна правка задевает соседние файлы, каждый релиз ломается смежное. НЕ для: ревью диффа перед коммитом (code-review), поиска уязвимостей (fynd-dyrka) — даже когда речь о платежах и деньгах, отладки конкретного отказа (systematic-debugging), внешнего ресёрча (deepdive), UI (design-modern)."
---
# Зодчий — архитектурный аудит с измеримой материальностью
**Тезис: материальность измеряется, а не утверждается.** Остальные инструменты
объявляют «цикл — находка, только если он чего-то стоит», но стоимость взять
неоткуда: граф импортов её не содержит. Здесь она берётся из git-истории и
служит условием допуска находки в отчёт.
Полный дизайн — `SPEC.md`. Ниже — как исполнять.
## Железное правило
```
Число — из скрипта. Суждение — из модели. Не наоборот.
Ни одна метрика не оценивается «на глаз»: ни fan-in, ни сложность, ни цикл.
Ни одна находка не выносится до того, как построена полная карта.
```
Нарушение — брак прогона, а не мелочь: вердикт, вынесенный до карты, тянет за
собой весь дальнейший разбор.
**Число сопровождается ссылкой.** Поле `source` находки — путь в `measure.json`
(`behavior.hotspots[file=src/x.py].fix_share`), а не проза «по данным замера».
Прозу нельзя отличить от числа, названного по памяти; путь проверяется
механически — `zodchiy.py selfcheck`. Полный перечень путей —
`references/measure_schema.md`.
**Рядом с абсолютным числом — перцентиль.** Пороги подобраны на двух
репозиториях и на третьем поплывут. `fix_share 0.43` не переносится между
проектами, `верхние 7% этого репозитория` переносится. Поля `*_pct` есть у
всех ранжируемых метрик.
**Бюджет чтения.** Файл читается целиком только после того, как попал в топ по
метрике (`hotspots`, `hubs`, `complex_files`, `slowest_files`, `unstable_files`).
На пятисотфайловом репозитории обратный порядок топит контекст, и разбор
скатывается к суждению по именам каталогов — ровно то, что шаг 2 запрещает.
**Модель по шагам.** Шаг 1 — модель не нужна вовсе, это скрипт. Шаг 2 —
механическое чтение, хватает средней. Шаг 4 — сильная: на слабой опровержение
превращается в вежливое согласие.
## Три оси
| Ось | Откуда | Чего НЕ видит |
|---|---|---|
| **Намерение** | ADR, CLAUDE.md, README, import-linter/ArchUnit/eslint-boundaries | врёт, когда документы отстали от кода |
| **Структура** | `scripts/structure.py` | связи через DI, реестры, рефлексию, строковые ключи |
| **Поведение** | `scripts/behavior.py` | код, который ещё не менялся |
**Допуск находки — по сходимости:**
| Осей сошлось | Статус | Судьба |
|---|---|---|
| 1 | `hypothesis` | в отчёт не идёт, ждёт следующего прогона |
| 2 | `finding` | в отчёт, с указанием недостающей оси |
| 3 | `verdict` | первым, годится в основание ADR |
Ось намерения **никогда** не перебивает исполняемое поведение. Наличие ADR не
доказывает, что так и сделано.
## Режимы
| Режим | Когда | Справочник |
|---|---|---|
| `audit` | свой проект: что болит и что чинить | ниже + `references/materiality.md` |
| `recon` | чужой/незнакомый репо: как устроен и почему так | `references/recon.md` |
| `gate` | CI: не стало ли хуже | `references/materiality.md` |
| `plan` | из находок в решения и миграцию | `references/remedy.md` |
Режим не объявлен — выведи из просьбы и назови одной строкой.
## Команда
Один вход, а не четыре скрипта. Дальше по тексту команды пишутся коротко
(`zodchiy.py gate`), полный путь — `python3 ~/.claude/skills/zodchiy/zodchiy.py`.
| Команда | Что делает |
|---|---|
| `measure <repo> --out .zodchiy/measure.json` | обе оси + калибровка; в stdout сводка, JSON в файле |
| `snapshot <measure> --out .zodchiy/baseline.json` | снимок метрик под сравнение |
| `diff <measure> --baseline <base>` | что изменилось между прогонами |
| `gate <measure> --baseline <base>` | то же + `exit 1` при регрессии — для CI |
| `add --findings <csv> --json '{...}'` | дописать находку |
| `refute --json '{...}'` | вердикт линзы опровержения (шаг 4) |
| `selfcheck --findings <csv> --measure <json>` | проверка находок перед сдачей |
| `verify --findings <csv> --measure <json>` | сверить прогноз `gain` с новым замером |
| `export --findings <csv> --measure <json> [--format sarif]` | находки машиночитаемо: JSON по схеме или SARIF |
`behavior <repo>` и `structure <repo>` гоняют одну ось — для отладки, не для
отчёта: без калибровки числа не годятся в находку.
## Деградация
Скилл переносим между харнессами, а фичи харнессов — нет. Каждая деградация
**объявляется в отчёте**. Молчаливая запрещена: она превращает «проверка была»
в неправду, и заметить это по отчёту нельзя.
| Чего нет | Что делаем | Чем платим и где это видно |
|---|---|---|
| субагентов | линзы шага 4 прогоняются последовательно, вердикт пишется с `mode: sequential` | потолок находки — `finding`; `selfcheck` вернёт `refutation.ceiling_cap` и строку `disclosure` для «слепых зон» |
| прогрессивной загрузки `references/` | справочник читается файлом по пути из таблицы ниже перед шагом, которому он нужен | ничем, если прочитан; по памяти — доктрина расходится с файлом молча |
| `tree-sitter` | разбор регулярками | `parser.backends.regex > 0`; такие файлы выпадают из метрик сложности, потолок по ним — `finding` |
| git-истории | две оси вместо трёх | `behavior.available: false`, потолок `finding` (см. `references/materiality.md` §6) |
Что каждый харнесс читает, куда класть адаптеры и чего у него нет —
`references/harnesses.md`. Факты там проверены 01.09.2026 по первоисточникам
и протухают: перед сборкой адаптеров сверяются заново, а не по памяти.
## Порядок работ — `audit`
Каждый шаг — пункт в todo. Пропуск шага объявляется вслух с причиной.
### 1. Считать
```bash
python3 ~/.claude/skills/zodchiy/zodchiy.py measure <repo> --out .zodchiy/measure.json
```
В stdout — сводка, полный JSON в файле. Читай файл прицельно (`adjacency`,
`temporal_coupling`, `hotspots`), а не целиком.
Смотри `calibration.passed` и `confidence.ceiling` **до** всего остального.
Калибровка не прошла — заблокированные метрики не дают находок, и это
проговаривается в отчёте. Потолок `finding` означает, что `verdict` в этом
прогоне недостижим в принципе.
Скрипт молчит про то, чего не может: короткая история, regex вместо дерева,
несвязный граф — всё выходит явными полями, а не тишиной.
**Чекпоинт.** `calibration.passed == false` или потолок ниже ожидаемого —
остановись и спроси, продолжать ли на оставшихся осях. Одна строка в конце
отчёта на сорок находок этого не заменяет: к тому моменту решение уже принято.
### 2. Понять — карта без вердиктов
Прочитай намерение: `CLAUDE.md`, `README`, `docs/architecture/*`, контракты
слоёв в `pyproject.toml` / `.eslintrc` / `archunit`. Прочитай ключевой код.
Построй карту: слои, модули, потоки, контракты, где чем владеют. Шаблон с
обязательными секциями — `references/map_template.md`.
**Здесь запрещено:** называть проблемы, ставить severity, предлагать лечение.
Тянет назвать — запиши в черновик находок и вернись к карте.
**Не верь именам.** Каталог зовётся `domain` — проверь, что в нём домен.
Функция зовётся `validate_*` — прочитай тело. Имя не доказывает ничего.
**Говори про ненайденное.** Границы слоёв ничем не защищены, кроме соглашения —
это утверждение, а не молчание. Помечай: `OBSERVED` / `INFERRED` / `UNKNOWN`.
### 3. Судить
Только теперь — находки. Числа берутся из `measure.json`; перечитывать код ради
смысла можно, ради измерения — нет.
Каталог рисков R1–R6 и пороги — `references/risks.md`.
Гейт материальности и Pain × Spread — `references/materiality.md`.
Правила расхождения осей — `references/axes.md`.
**Различай R2 и R3 через граф.** Пара меняется вместе И связана импортом
(`adjacency_through_barrels`) — честная зависимость, R2. Меняется вместе БЕЗ
ребра — одно решение разложено в двух местах, R3, другое лечение. Проверять
надо по графу *через barrel*: `from pkg import X` даёт ребро в `__init__.py`,
и наивная проверка объявит связь скрытой, когда она прямая.
**Цикл считай только рантаймовый.** `cycles` — настоящие. `cycles_type_only` —
`if TYPE_CHECKING:` и `import type`, они ровно для разрыва цикла и заведены.
Смешать — выдать выдуманный дефект первой строкой.
**Сложность сравнивай по функции**, не по файлу: `cyclomatic_per_function_max`,
не `cyclomatic_total`. Порог McCabe задан на функцию.
**Цена считается и во времени.** `pain × spread` — цена в пространстве.
`velocity.touch_cost` говорит, сколько мест надо тронуть на одно изменение;
`velocity.episodes.multi_commit_share` — какая доля изменений потребовала
доделок. Это и есть «больно менять», выраженное числом.
**`rework_rate` — не то же, что `fix_share`.** `fix_share` говорит «файл часто
чинят» (сложное место). `stability.rework_rate` — «правки этого файла не
держатся» (обратной связи нет: ловит не тест, а пользователь). Диагнозы разные,
лечение разное. Ранжировать по `rework_rate_lb`, не по сырой доле: «5 из 5»
иначе обгоняет «55 из 67» и первой строкой отчёта идёт шум.
### 4. Опровергнуть
Каждая находка со статусом `verdict` и каждая с приоритетом ≥6 идёт на
опровержение — **разными линзами**, а не копиями одного промпта: N одинаковых
агентов дают одно мнение по цене N. Четыре линзы, что каждая читает и чем
убивает находку — `references/refutation.md`.
Как физически шли линзы — независимо или одним проходом — объявляется полем
`mode`, а не подразумевается: см. «Деградация» выше и `references/refutation.md`.
Вердикт линзы кладётся файлом, а не пересказывается:
```bash
zodchiy.py refute --json '{"finding_id":"F1","lens":"L4","verdict":"dropped",
"reason":"...","mode":"parallel"}'
```
Не устояла — вниз по статусу или прочь.
### 5. Отчёт
Открывается строкой `Чеклист: X/Y`. Незакрытые пункты перечисляются с причиной
и следствием — тихий пропуск запрещён.
Порядок: снимок (remote, ветка, HEAD, чистота дерева, дата) → калибровка и
потолок → карта → находки по приоритету → **слепые зоны**.
Секция «слепые зоны» обязательна и собирается механически, не пересказом:
`calibration.blocked_metrics` + файлы, разобранные регулярками
(`parser.backends.regex`) + окно истории (`snapshot.since`) + связи, которых
граф импортов не видит (DI, реестры, рефлексия, строковые ключи) + режим шага 4
(`selfcheck` → `refutation.disclosure`, если линзы шли последовательно).
**Тихое усечение запрещено.** Обрезал список топ-N — скажи, сколько отброшено.
Молчание читается как «покрыто всё», и это единственная ошибка отчёта, которую
читатель не может заметить.
Перед сдачей: `zodchiy.py selfcheck --findings ... --measure ...` — поля на
месте, `source` разрешается, находки высокого приоритета прошли опровержение.
**Отчёт — не единственный выход.** `zodchiy.py export` отдаёт те же находки
машиночитаемо: JSON по `schema/findings.schema.json` либо SARIF для CI и code
scanning. Markdown пишет модель, и его форма зависит от харнесса — сравнивать
прогоны и гейтить сборку можно только по машинному выходу. Экспорт гоняет тот
же `selfcheck` и отказывается собирать документ из брака.
### 6. Артефакты
`references/artifacts.md`: `docs/architecture/current-state.md`, ADR,
диаграммы, план миграции, `.zodchiy/findings.csv`, `baseline.json`,
`.zodchiy/verify/refutation.json`.
## Справочники
| Файл | Когда открывать |
|---|---|
| `references/measure_schema.md` | ищешь путь к числу или пишешь `source` находки |
| `references/risks.md` | шаг 3: каталог R1–R6 и разделы «что НЕ флагать» |
| `references/materiality.md` | шаг 3: гейт материальности, Pain × Spread |
| `references/axes.md` | оси разошлись — что перевешивает |
| `references/map_template.md` | шаг 2: секции карты и пометки OBSERVED/INFERRED/UNKNOWN |
| `references/refutation.md` | шаг 4: четыре линзы и запись вердикта |
| `references/remedy.md` | режим `plan`: из находок в решения |
| `references/recon.md` | режим `recon`: чужой репозиторий |
| `references/artifacts.md` | шаг 6: формы артефактов |
## Форма находки
```
id · title · risk · symptom · axes · source · cost_pain · cost_spread ·
remedy · remedy_cost · gain · gain_metric · gain_target · gain_direction ·
alternatives · refutation · confidence · priority · status
```
Четыре поля, без которых находка — брак:
- **`cost_pain`** — чем обходится сейчас, числом и ссылками на коммиты. Нет
числа — находки нет.
- **`remedy_cost`** — во что обойдётся лечение, той же валютой. Без него линза
«лечение дороже болезни» работает на глаз: сравнивать не с чем. Дороже
болезни на горизонте — находка не выносится, идёт в «знаем, не чиним» с датой
пересмотра.
- **`gain` + `gain_metric` + `gain_target`** — проверяемый прогноз в машинной
форме. «Станет чище» — брак. `gain_metric: containment_ratio`,
`gain_target: 0.70` — годится: `zodchiy.py verify` сверит это со следующим
прогоном и проставит `gain_actual` и `gain_verdict`. Прогноз, который не
ложится на метрику снимка, помечается `gain_metric: manual` — честно и
видно, а не молча.
- **`refutation`** — какой факт снял бы находку. «Ничего не снимет, это
очевидно» означает, что находку не проверяли.
Скилл требует измеримости от чужого кода. `zodchiy.py verify` — то же требование
к собственным советам: обещал `containment 51% → 70%`, через прогон видно, что
вышло. Без этой петли рекомендация ничем не отличается от мнения.
## Что режется гейтом
Придирки · вкусовщина в именовании · теоретическая чистота · «так принято» ·
спекулятивный масштаб («а если 10 млн пользователей») · новизна ради новизны.
Модернизация оправдана текущим дефектом или измеримым упрощением. Точечный
ремонт границы предпочтительнее переписывания, когда переписывание добавит
больше переходной сложности, чем уберёт.
## Что НЕ флагать
Разделы «что НЕ флагать» в `references/risks.md` — несущие, а не вежливые.
Проверено на живом коде: без них скилл объявил бы дефектами DI-корень с самым
высоким churn (74 правки, но 11% багфиксов — точка расширения по замыслу),
barrel с fan-in 109 и четыре «цикла», ни один из которых не существует в
рантайме.
Высокий churn при низкой доле багфиксов — точка расширения, не долг.
Смотри `hotspots[].fix_share`, а не только `edits`.
Эти четыре ложняка закреплены регрессией: `evals/` держит по паре
«нарушение / похожий, но невиновный» на каждый из них. Правишь `scripts/*.py` —
гоняй `python3 evals/run_evals.py` (юнит + сквозной прогон на мини-репозиториях,
без модели, секунды). Подробности — `evals/README.md`.
## Границы
Безопасность → `fynd-dyrka` · ревью диффа → `code-review` · внешний ресёрч →
`deepdive` · UI → `design-modern`.
Репо без git-истории или короче порога: поведенческая ось недоступна, скилл
говорит это прямо, работает на двух осях, потолок — `finding`.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!