Фаза 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 — это снимок, а не план реформ. Не предлагайте в нём, «как починить»: его задача — зафиксировать «как есть». Решение, что и в каком порядке чинить, появится на последнем шаге как приоритезированная точка старта.
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/TS
Python
Go · Java/Kotlin
Границы импортов / архитектуры
dependency-cruiser, eslint-plugin-boundaries
import-linter
depguard · ArchUnit
Поиск мёртвого кода
knip, ts-prune
vulture
deadcode · (IDE-инспекции)
Проверка типов
tsc
mypy, pyright
go vet · компилятор
Циклы зависимостей
madge
import-linter (contracts)
компилятор (Go) · ArchUnit (JVM)
Pre-commit оркестратор
husky + lint-staged
pre-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), которая берёт оба ваших аудит-документа как вход.
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), которая берёт оба аудит-документа как вход.