Все рецепты

Аудит brownfield-проекта перед харнесом (Phase 0)

Фаза 0 серии Harness Engineering — вход на существующий (brownfield) проект. До любых AGENTS.md и линтеров вы делаете аудит: baseline.md инвентаризирует, что уже есть (структура, границы, конвенции, состояние тестов и CI как описательная база), а environment.md фиксирует стек и таблицу tool-selection (роль → конкретный инструмент), на которую опираются все следующие фазы. С копируемыми промптами бутстрапа аудита — стек-агностично, для JS/TS, Python, Go, Java/Kotlin и любого другого стека.

СреднийDevOps с AI20 минbaseline.md, environment.md, ADR, Claude Code
1

Зачем аудит до харнеса: вход на brownfield-проект

Серию по harness-инженерии часто читают так, будто проект — чистый лист. На практике вам достаётся существующий репозиторий (brownfield): чужой код, неявные конвенции, может быть уже хаотичное использование агента «в чатах». Если на такой проект сразу накатить AGENTS.md и линтеры, вы построите харнес на догадках — зафиксируете архитектуру, которой в коде нет, и включите барьеры, которые завалят сборку на первом же коммите. Поэтому Фаза 0 — это не строительство, а инвентаризация. Сначала вы честно узнаёте, что в репо уже есть, и только потом строите поверх реального состояния. Результат фазы — два документа: baseline.md (текущее состояние: что есть, разрыв до цели, приоритет фикса) и environment.md (стек и таблица tool-selection, на которую опираются все последующие фазы). Это вход, который идёт ПЕРЕД контекст-инжинирингом (Фаза 1): нельзя описать карту проекта, не прочитав сам проект.

🟥 Харнес на догадках

  • Карта архитектуры, которой нет в коде
  • Барьеры валят сборку на первом коммите
  • Инструменты выбраны «как принято», не под стек

🟩 Сначала аудит

  • baseline.md: что реально есть в репо
  • environment.md: стек → tool-selection
  • Приоритезированная точка старта, не «всё сразу»
Brownfield-вход — это про честность, а не про оптимизм. Где данных не хватает, в baseline.md пишется «не уверен / TBD», а не выдуманный факт: на выдуманную базу следующие фазы будут молча опираться и тиражировать ошибку.
2

baseline.md: что инвентаризируем

baseline.md описывает текущее состояние проекта по нескольким осям. Для каждой оси — три колонки: что есть сейчас, разрыв до целевого состояния, приоритет фикса. Оси: (1) context engineering — есть ли AGENTS.md / CLAUDE.md / README с архитектурой, ADR, и что важного лежит ВНЕ репо (чаты, облачные доки, тикеты); (2) детерминированные проверки — какие форматтеры, линтеры, тайп-чекеры, проверки границ модулей, поиск мёртвого кода уже подключены, и насколько строгие конфиги; (3) сигналы качества в CI; (4) garbage collection — есть ли регулярные проверки на дрейф; (5) workflow агента — как команда уже использует кодинг-агента (один тред на проект или на задачу, есть ли переиспользуемые промпты); (6) читаемость репо для нового человека/агента. Про тесты: покрытие фиксируется как описательное число базы («сейчас ~40%»), а не как цель — задача аудита измерить сигнал, а не назначить ему план. И требование к самому документу: конкретика, не «линтеры частично есть», а перечисление инструментов и версий из конфигов.

Шесть осей baseline.md

Context engineering: AGENTS.md/README/ADR + что лежит ВНЕ репо
Детерминированные проверки: форматтер/линтер/типы/границы/мёртвый код + строгость
Сигналы качества в CI (покрытие — как описательная база, не цель)
Garbage collection: есть ли регулярные проверки на дрейф
Workflow агента: один тред на задачу? переиспользуемые промпты?
Читаемость репо: понятен ли проект из ОДНОГО репо
Я внедряю harness engineering на этом проекте и сейчас на Phase 0
(аудит существующего проекта перед построением харнеса).

Создай docs/audit/baseline.md, в котором честно описано текущее
состояние проекта по 6 осям. Для каждой укажи 3 колонки:
что есть сейчас / разрыв до целевого состояния / приоритет фикса.

1. Context engineering. Есть ли AGENTS.md / CLAUDE.md / README с
   описанием архитектуры? Есть ли docs/ и ADR? Что важного лежит ВНЕ
   репо (чаты, облачные доки, тикеты), но влияет на решения?

2. Детерминированные проверки. Что уже подключено: форматтеры,
   линтеры, тайп-чекеры, проверки границ модулей, поиск мёртвого
   кода, security-сканеры. Для каждого — уровень строгости конфига.

3. Сигналы качества. Что измеряется в CI? Покрытие тестами зафиксируй
   как ОПИСАТЕЛЬНОЕ число базы, не как цель. Тесты — сигнал здоровья.

4. Garbage collection. Есть ли регулярные автопроверки на дрейф
   документации, устаревшие зависимости, нарушения архитектуры?

5. Workflow агента. Как команда уже использует кодинг-агента: один
   тред на проект или на задачу? Есть ли переиспользуемые промпты?

6. Читаемость репо. Понял бы новый человек или агент в первом
   запуске, что делает проект, прочитав ТОЛЬКО репо? Что неочевидно?

Будь конкретен: перечисляй инструменты и версии из конфигов, а не
"линтеры частично есть". Где данных нет — пиши "не уверен / TBD",
не выдумывай.
baseline.md — это снимок, а не план реформ. Не предлагайте в нём, «как починить»: его задача — зафиксировать «как есть». Решение, что и в каком порядке чинить, появится на последнем шаге как приоритезированная точка старта.
3

environment.md: таблица tool-selection (роль → инструмент)

environment.md фиксирует стек проекта и — главное — таблицу tool-selection, на которую опираются все следующие фазы (и из которой потом собирается «конфигуратор» харнеса). Сначала описываете контекст: языки и версии, build/test-тулчейн, CI/CD (или «TBD», если нет), планировщик фоновых задач, хостинг репо, развёртывание, доступ к LLM. Затем — сердце фазы: каждой РОЛИ из будущих барьеров ставится в соответствие КОНКРЕТНЫЙ инструмент именно под этот стек. Ключ в том, что роль универсальна, а инструмент — нет. Таблица ниже показывает, как одна роль раскрывается по стекам: границы импортов держит dependency-cruiser в JS/TS, import-linter в Python, ArchUnit в Java/Kotlin, depguard в Go; мёртвый код ищут knip / ts-prune в JS/TS и vulture в Python; типы проверяет tsc или mypy; циклы — madge. Никакой стек не объявляется универсальным законом: вы выбираете строку под свой проект. На этапе аудита столбец «выбранный инструмент» заполняется ПРЕДЛОЖЕНИЕМ, не решением — человек ревьюит до старта механизации. И выбор фиксируется одним ADR (0001-tool-selection) со статусом Proposed.
Роль (универсальна)JS/TSPythonGo · Java/Kotlin
Границы импортов / архитектурыdependency-cruiser, eslint-plugin-boundariesimport-linterdepguard · ArchUnit
Поиск мёртвого кодаknip, ts-prunevulturedeadcode · (IDE-инспекции)
Проверка типовtscmypy, pyrightgo vet · компилятор
Циклы зависимостейmadgeimport-linter (contracts)компилятор (Go) · ArchUnit (JVM)
Pre-commit оркестраторhusky + lint-stagedpre-commit (framework)lefthook (стек-агностичен)
Phase 0, продолжение. Создай docs/audit/environment.md. Этот
документ фиксирует контекст проекта, на который опираются все
следующие фазы.

Опиши контекст:
1. Стек: языки, фреймворки, рантаймы, версии.
2. Build/test-тулчейн: пакетный менеджер, test-runner, builder.
3. CI/CD: где запускается автоматизация (GitHub Actions / GitLab CI /
   Jenkins / ... / ничего — тогда "TBD").
4. Планировщик фоновых задач: где будут жить регулярные "уборщики".
5. Хостинг репо: GitHub / GitLab / self-hosted.
6. Развёртывание: куда катится прод.
7. Доступ к LLM: какие модели/агенты уже использует команда.

В конце добавь раздел "Tool selection for harness components" —
таблицу, где каждой РОЛИ ставится в соответствие КОНКРЕТНЫЙ инструмент
ИМЕННО ДЛЯ ЭТОГО СТЕКА:

| Роль | Выбранный инструмент | Альтернативы рассмотрены | Причина |
|------|----------------------|--------------------------|---------|
| Форматтер кода | ... | ... | ... |
| Линтер общего назначения | ... | ... | ... |
| Линтер границ модулей | ... | ... | ... |
| Поиск мёртвого кода | ... | ... | ... |
| Проверка типов | ... | ... | ... |
| Security/dependency scanner | ... | ... | ... |
| Pre-commit оркестратор | ... | ... | ... |

ВАЖНО: столбец "выбранный инструмент" заполни ПРЕДЛОЖЕНИЕМ, не
решением. Не объявляй инструмент одного стека универсальным законом —
выбирай под наш стек. Я ревьюну до начала механизации.

Затем заведи ADR docs/decisions/0001-tool-selection.md со статусом
Proposed, фиксирующий эти выборы.
Роль выбирается по классу ошибок, который надо ловить, а не по моде на инструмент. Если в репо нет циклов импортов — не тащите madge ради галочки; пустой барьер только замедляет сборку. Лучше одна реальная роль с настроенным инструментом, чем семь предложенных «на будущее».
4

Карта слоёв и границ для будущих барьеров

Пока вы читаете репо, отдельно отмечайте слои и границы между ними — именно их на Фазе 3 будут защищать барьеры. На brownfield-проекте чёткой layer model часто нет: зависимости текут как сложилось. Задача аудита — не навязать идеальную архитектуру, а зафиксировать наблюдаемую и явно пометить её «Discovered, not enforced yet» (обнаружено, пока не форсится). Это честная разница: вы пишете «так уже сделано», а не «так задумано идеально». Для каждого слоя отметьте направления зависимостей: что МОЖНО, что НЕЛЬЗЯ. Эта стрелочная карта — будущий конфиг линтера границ (dependency-cruiser в JS/TS, import-linter в Python, ArchUnit в Java/Kotlin, depguard в Go — строка из вашей таблицы tool-selection). Самое частое нарушение, которое агент допускает «по пути», — слой домена/бизнес-логики, который лезет напрямую в инфраструктуру (БД, внешние API). Зафиксируйте это направление словами сейчас, в фазе аудита, — чтобы на Фазе 3 механизировать его проверкой. Где границы пока не ясны, ставьте «?» и TODO: неполная карта лучше выдуманной.
UI / точки входа
можно
Прикладной слой / use cases
можно
Домен / бизнес-логика
нельзя (частое нарушение)
Инфраструктура: API, БД, очереди
Не путайте «нет layer model» с «модель не нужна». На brownfield почти всегда есть неявные слои — их просто никто не записал. Аудит делает их видимыми; форсить их будет Фаза 3 через инструмент из вашей таблицы tool-selection.
5

Честный scope: аудит ≠ переписывание + что дальше

Главная ловушка Фазы 0 — увидеть проблемы и тут же кинуться чинить. Аудит — это не рефакторинг и не построение всего харнеса сразу. На выходе у вас ровно два документа (baseline.md, environment.md) плюс ADR-предложение по инструментам — и приоритезированная точка старта, а не план на квартал. Definition of Done фазы: baseline.md с конкретными пробелами, environment.md с таблицей tool-selection, ADR 0001-tool-selection со статусом Proposed на ревью у человека. Честные границы харнеса в целом: он обеспечивает архитектурную целостность и поддерживаемость, но НЕ валидирует функциональную корректность (делает ли код то, что нужно пользователю — остаётся на человеке и продуктовых тестах) и НЕ заменяет ревью. И не чините всё сразу: один реальный барьер ценнее идеального плана. Из baseline выберите 1–3 самых дешёвых и болезненных пробела как старт — остальное войдёт в следующие фазы. Дальше — Фаза 1: контекст-инжиниринг (AGENTS.md, architecture.md, ADR), которая берёт оба ваших аудит-документа как вход.

Definition of Done — Фаза 0

baseline.md: 6 осей, конкретные инструменты/версии, честные «TBD»
environment.md: стек + таблица tool-selection (роль → инструмент)
ADR 0001-tool-selection со статусом Proposed на ревью
Приоритезированная точка старта: 1–3 пробела, не план на квартал
Рефакторить код «по пути» во время аудита
Строить весь харнес сразу до первого барьера
Считать, что харнес проверяет функциональную корректность
Если аудит вскрыл больше работы, чем ожидалось, — это не повод расширять Фазу 0, а сигнал к декомпозиции. Зафиксируйте находки в baseline и разнесите их по фазам 1–5; пытаться закрыть всё в аудите — тот самый scope creep, от которого харнес и защищает.

Результат

Вы прошли вход в серию на существующем (brownfield) проекте: вместо того чтобы строить харнес на догадках, вы сделали аудит. На руках — baseline.md (текущее состояние по шести осям, с покрытием как описательной базой, а не целью), environment.md с таблицей tool-selection (роль → конкретный инструмент под ваш стек), ADR 0001 со статусом Proposed и приоритезированная точка старта из 1–3 пробелов. Аудит — это не переписывание: вы зафиксировали, что есть, и наметили, с чего начать. Дальше — Фаза 1: контекст-инжиниринг (AGENTS.md, ADR, architecture.md), которая берёт оба аудит-документа как вход.