Служебный слой Harness и код проекта обновляются по-разному
К Harness относятся AGENTS, адаптеры сред исполнения, базовые навыки, протокол выполнения, .harness/docs, политики, механизм обновления, валидатор и шаблоны. Проекту принадлежат REQ, ADR, архитектура, задачи, ревью, аудиты, код и тесты продукта, конфигурация и дополнительные навыки проекта или сторонних источников.
Для мелкой правки не нужен искусственный STEP
Опечатка, пунктуация, безопасный комментарий или локальное форматирование могут идти через PROJECT QUICK FIX или ручную правку. изменения Git и коммит — достаточная история такой мелочи.
PROJECT RECONCILE восстанавливает согласованность
Расхождения архитектуры, документации и статусов фиксируются явно. PROJECT RECONCILE создаёт отчёт аудита и корректирующий STEP там, где изменение нельзя безопасно спрятать в текущую задачу.
Обновление Harness — отдельный детерминированный процесс
HARNESS UPDATE CHECK [TO <tag>] # проверка маршрута без изменений
HARNESS UPDATE APPLY [TO <tag>] # применение того же целевого маршрута
# Эквивалентная цепочка:
HARNESS UPDATE CHECK [TO <tag>] > APPLY
проверить изменения
GIT CHECK > COMMIT > PUSH > PRОбе команды обновления dispatcher направляет прямо в .harness/tools/harness-update.py без вызова модели. Агент не копирует файлы релиза вручную и не воспроизводит правила владения или слияния в рассуждениях. CHECK остаётся строго read-only: он проверяет текущий immutable BASE, маршрут, целевой релиз, владение путями и конфликты.
.harness/harness.lock.json → текущий BASE
.harness/harness-update-graph.json → latest + разрешённые переходы
.harness/harness-update.toml → правила владения и слияния каждого перехода
.harness/local/update-journal/ → журнал незавершённой транзакцииAPPLY перед первой записью заново выполняет машинную предварительную проверку. Каждый переход — отдельная транзакция: сохраняются затрагиваемые управляемые пути, lock и точные bytes/permissions локального execution-status.json; файлы записываются атомарно; затем запускается валидатор целевого состояния. Неизменяемый UPDATE-*.md публикуется только после PASS, после чего атомарно фиксируется commit point перехода.
При failure или прерывании переход откатывается до исходного состояния. Если процесс был убит и journal остался на диске, HARNESS UPDATE CHECK возвращает UPDATE_JOURNAL_PENDING, а следующий HARNESS UPDATE APPLY сначала выполняет recovery и затем повторяет обновление. Для ручного восстановления доступен python3 .harness/tools/harness-update.py recover --json, использующий автономный update_recovery.py.
Без TO <tag> конечная версия берётся из поля latest; явный TO фиксирует target, но updater всё равно обязан доказать достижимый маршрут.
reloadRequired: true или меняет уже загруженный модуль updater-а, Harness фиксирует достигнутый релиз и останавливает маршрут с требованием перезапуска. После reload та же целевая команда продолжает путь новым кодом.BASE / OURS / THEIRS и правила владения файлами
harness_owned
Локальное отличие от BASE блокирует скрытую перезапись.
shared
Для настраиваемых файлов выполняется трёхстороннее слияние. Сюда входят отслеживаемые файлы ролей и конфигурации Codex и Claude Code.
marker_merge
README и AGENTS объединяются с сохранением сгенерированных блоков проекта.
unknown
По умолчанию файл считается принадлежащим проекту, и механизм обновления его не меняет.
Схема проектных документов мигрируется отдельно и без скрытой потери данных
HARNESS UPDATE APPLY обновляет служебный слой, но не переписывает активные проектные REQ/ADR/OQ/STEP. Если целевой релиз требует миграции, валидатор оставляет явное состояние ожидания; затем PROJECT RECONCILE сначала выполняет read-only preflight всех заранее обнаружимых blocker-ов и только после этого изменяет проектные документы и пересобирает проекции.
Миграция legacy-документов сохраняет неизвестные разделы и исходные metadata, многострочные зависимости, русский формат ADR и свободный текст старого монолитного SPEC. Написанные вручную файлы на месте генерируемых проекций перед заменой сохраняются рядом как *.legacy.md. Завершённые старые STEP без доверенного исторического review могут получить явный LEGACY_COMPLETION baseline в migration report — это совместимость с историей, а не поддельный PASS-отчёт задним числом.
Неизменяемые исторические отчёты не переписываются; уже зафиксированные review proofs проверяются по хэшам, а повторная миграция без изменений остаётся идемпотентной.
Поддерживаемая точка входа обновления начинается с v0.6.0
Текущий deterministic updater принимает проекты, синхронизированные с Harness v0.6.0 или новее. Более ранние переходы остаются в графе как исторические данные и regression boundaries, но не считаются поддерживаемой рабочей точкой входа текущего engine. Переход из v0.5.3 исторически выполнялся legacy updater-ом до bridge v0.6.0, после которого требуется reload и дальнейший путь идёт уже через deterministic engine.
Если .harness/harness.lock.json отсутствует, доказуемой BASE-версии нет. Harness не угадывает её по похожести файлов. Для явного подключения используется только известный immutable baseline: python3 .harness/tools/harness-update.py adopt --from vX.Y.Z --json. Adoption сама выполняется как транзакция с журналом и принимается только после PASS валидатор постусловий; при failure или прерывании новый lock не остаётся.
source.commit и получить SOURCE_TAG_MOVED до обновления. Recovery разрешён только для двух документированных пар release/OID; произвольный tag mismatch остаётся security blocker..harness/harness-update-graph.json, а не захардкоженным сценарием документации.Изменяющие операции Git тоже проходят детерминированные границы безопасности
Перед GIT CHECK, GIT COMMIT, GIT PUSH, GIT PR, GIT PR FINISH и GIT SYNC используется .harness/tools/git-preflight.py. Он возвращает PASS/BLOCKED и точный план операции; фактические mechanical mutations выполняет .harness/tools/git-action.py, а provider-specific Pull Request operations — .harness/tools/pr_provider.py.
Для GIT COMMIT до validator фиксируются branch, HEAD и дерево индекса. Перед git commit снимок проверяется повторно, а после него сверяются фактические ветка/родитель/дерево. Пользовательские hooks не отключаются. Если hook изменил проверенное состояние, результат становится COMMIT_POSTCONDITION_FAILED; Harness компенсирует только доказанно принадлежащую операции изменение ref через reflog и compare-and-swap. Неоднозначная ситуация остаётся fail-closed, а git reset --hard для recovery не используется.
COMMIT/PUSH/PR также используют bounded side-effect checkpoint в execution state. После crash Harness сначала наблюдает внешний факт: уже доказанная mutation не повторяется, неизменившийся baseline допускает retry, а третье состояние возвращает SIDE_EFFECT_RECOVERY_AMBIGUOUS. Для push проверяется live remote HEAD; для PR выполняется exact provider query по head/base/head SHA.
Для GIT PR FINISH предварительная проверка подтверждает, что PR уже имеет состояние MERGED, рабочее дерево чистое, локальный HEAD соответствует сохранённому provider head SHA, а ветку возврата можно безопасно обновить fast-forward. Локальный .harness/local/git/pr-state.json удаляется только после полностью успешного завершения.
gh, Gitea — tea. Для self-hosted Gitea host берётся из configured push.remote; несколько подходящих Tea profiles дают PROVIDER_LOGIN_AMBIGUOUS. GIT CHECK, GIT COMMIT, GIT PUSH и GIT SYNC используют обычный Git.Граф и целевые релизы читаются как данные, а не как произвольные инструкции
Изменяемую исходную ветку разрешено читать только для канонического .harness/harness-update-graph.json. Сам граф содержит только данные маршрутизации: latest, направленные переходы, тип перехода и при необходимости границу перезапуска. Содержимое служебного слоя каждого перехода читается только из неизменяемых тегов релизов.
Скрипты миграции, установки и bootstrap из целевого релиза автоматически не запускаются. Единственный target code внутри update-транзакции — обязательный валидатор постусловий; его failure приводит к rollback, а не к фиксации частично обновлённого Harness.