---
work_item: ORCH-078
stage: architecture
author_agent: architect
status: proposed
created_at: 2026-06-09
model_used: claude-opus-4-8
---

# ADR-001: Стандарт маркеров-трассировки `ORCH-NNN` + правило чтения ADR перед правкой

Work Item: **ORCH-078** — ORCH-52e: трассировка `ORCH-NNN` (слой 4 эпика ORCH-52)
Стадия: **architecture**
Сквозная регистрация: **`docs/architecture/adr/adr-0022-traceability-marker-standard.md`**
(решение кросс-каттинговое — вводит нормативный стандарт разработки и ось ревью для ВСЕХ
агентов/проектов; продолжает цепочку adr-0019/0020/0021 эпика 52).

## Статус
Proposed

## Контекст

Эпик **ORCH-52** строит сквозной «golden source» документации конвейера слоями: **52b** (ORCH-075,
adr-0019) — стандарт структуры документов `PIPELINE_DOCS.md` + скелеты; **52c** (ORCH-076, adr-0020) —
машинный frontmatter-контракт `src/frontmatter.py` + `HANDOFF_PROTOCOL.md`; **52d** (ORCH-077,
adr-0021) — 6 промптов в каноне Anthropic + эмиссия 52c-схемы. **52e — слой 4 (трассировка)**.

**Факты, сверенные с кодом `main` (на 2026-06-09):**
- В `src/` де-факто живёт **51 уникальный** маркер `ORCH-NNN`
  (`grep -rhoE 'ORCH-[0-9]+' src/ | sort -u | wc -l` → 51), привязывающий нетривиальные строки/
  инварианты к work item, который их ввёл. Это **сложившаяся практика без формального стандарта**:
  `docs/_standards/` содержит только `PIPELINE_DOCS.md` и `HANDOFF_PROTOCOL.md`.
- Проверяемый одиночный пример: `src/serial_gate.py:241,269` несёт условие сериализации
  `t2.id < jobs.task_id` с маркером **ORCH-088** и явной отсылкой `ADR-001 D1 / FR-2` →
  `docs/work-items/ORCH-088/06-adr/ADR-001-serial-gate.md` существует.
- Проверяемый пример высокой плотности: `src/merge_gate.py` несёт **26** вхождений маркеров
  (ORCH-043/065/067/069/071/073/074/082) — раскопки по 8 work item; сквозные
  `adr-0006/0013/0014/0016` существуют и агрегируют эволюцию.
- Плотность маркеров по файлам (сверено): `config.py`=63, `stage_engine.py`=55,
  `agents/launcher.py`=50, `plane_sync.py`=48, `merge_gate.py`=26.

**Почему «как есть» не годится (боль):**
1. **Нет правила чтения.** Агент (developer/architect), правя маркированную строку, не обязан
   прочитать ADR, который её ввёл, → риск молча сломать зафиксированный инвариант. Это ровно класс
   «фантомного merge» (`docs/history/LESSONS_2026-06-08_phantom-merge.md`), породившего ORCH-071/073.
2. **Reviewer не контролирует соблюдение.** Reviewer-ось «Соответствие ADR» (`reviewer.md:37`)
   проверяет ADR *текущей* задачи, но не сверку правки *чужого* маркированного кода с его ADR.
3. **Анти-археология.** Файлы с плотностью 50+ маркеров превращают понимание блока в раскопки.
4. **Доступ к чужому work item.** Папки `docs/work-items/ORCH-NNN/06-adr/` может не быть в текущей
   ветке (срезана от `main` без неё) — нужен задокументированный fallback.

**Что УЖЕ покрыто 52d (анти-дубль, сверено `grep -nE 'ORCH-NNN|06-adr'`):** `developer.md:65`
говорит «реализуй по `06-adr/`» — но только про ADR *текущей* задачи; `architect.md:41`/`reviewer.md:37`
— аналогично. **Правила «правишь чужой маркированный код → прочти его ADR перед правкой» среди них
НЕТ.** Поэтому 52e не переписывает промпты — добавляет именно отсутствующее правило.

## Решение

### Сводка

Кодифицировать сложившуюся практику маркеров как **нормативный документ-стандарт**
`docs/_standards/TRACEABILITY.md` (слой 4 эпика 52, рядом с `PIPELINE_DOCS.md`/`HANDOFF_PROTOCOL.md`),
и **точечно** дополнить 3 промпта правилом чтения / контролем соблюдения **со ссылкой на единый
источник** (не копируя текст). Это **docs + prompts-only** изменение с нулевым касанием кода:
стандарт — описательно-нормативный документ + анти-регресс-тест промптов, **не машинный гейт
конвейера**. Никакого ретро-фита 51 существующего маркера — стандарт действует «на будущее».

### D1 — `TRACEABILITY.md` как нормативный документ, НЕ машинный гейт (FR-1, AC-1)

Стандарт фиксирует **существующий контракт**, а не вводит новый синтаксис. Обязательные смысловые
блоки (7 шт., по FR-1): (1) назначение и определение маркера `ORCH-NNN`/`ET-NNN`; (2) формат —
inline-комментарий, рекомендуется ссылка на решение (`ORCH-088, ADR-001 D1`); (3) где ставится —
рядом с **нетривиальным инвариантом** (fail-open/-closed, точное условие сериализации,
идемпотентность, обходимая дыра конвейера), не на тривиальном коде; (4) как читать историю **с
реальным проверяемым примером** (`src/serial_gate.py` → ORCH-088 → `ADR-001-serial-gate.md`);
(5) fallback-доступ (D3); (6) анти-археология (D4); (7) каноничный текст правила чтения (D2).

**Архитектурное решение:** стандарт остаётся **слоем 1 (описательным)** в терминологии 52b —
источник истины о *поведении* остаётся код (`src/stages.py`, `src/qg/checks.py`); enforcement
маркеров в CI/гейт **не вводится** (см. «Альтернативы»). Реальный пример обязан ссылаться на
существующие в `main` файл+ADR (проверяемость трассировки — иначе стандарт сам себя опровергает).

### D2 — Единый источник истины правила чтения; промпты ссылаются, не дублируют (BR-6, AC-6)

Каноничная формулировка правила живёт **только** в `TRACEABILITY.md` §7:

> «Правишь код с маркером `ORCH-NNN` → прочитай его `docs/work-items/ORCH-NNN/06-adr/` ПЕРЕД
> изменением; не сломай зафиксированный инвариант; не можешь сохранить — эскалируй / верни в анализ.»

Промпты несут **короткую врезку со ссылкой** на этот текст, а не его копию. Это структурно гасит
риск дрейфа формулировок между 4 файлами и удовлетворяет анти-дубль BR-6: 52d-канон (5 XML-секций +
52c-эмиссия) **не переписывается**, врезки **аддитивны**.

### D3 — Точные точки врезок в промпты (FR-2..FR-6)

Сверено по фактической структуре промптов; врезки минимальны и не трогают machine-verdict ключи:

| Промпт | Точка врезки | Содержание | Формат |
|--------|--------------|------------|--------|
| `developer.md` | `<constraints>` (рядом с пунктом `06-adr/` строка 65) + строка списка «что прочесть» в `<context>` | правило чтения чужого маркера + **fallback-доступ** (D5) | пункт «❌ X → ✅ Y» (AC-2) |
| `architect.md` | `<constraints>` | правило чтения + **анти-археология** (D4): блок с 3+ маркерами → сводный сквозной ADR | пункт + ссылка на стандарт |
| `reviewer.md` | усиление оси «Соответствие ADR» (`<task>` п.2, строка 37) под-пунктом | проверка: правка маркированного кода **сверена** с его `06-adr`; слом/несверка → finding | под-пункт оси, не новая ось |

Во всех трёх — **ссылка** на `docs/_standards/TRACEABILITY.md` (D2). Существующие 52d-упоминания
ADR *текущей* задачи не удаляются и не дублируются — рядом добавляется правило для *чужих* маркеров.

### D4 — Анти-археология: порог 3+ маркеров → сводный сквозной ADR (FR-6, AC-5)

Нормативная конвенция: если функция/блок несёт **≥3** маркеров `ORCH-NNN`, вместо перечисления всех
work item ставится **одна сводная ссылка на сквозной ADR** (`docs/architecture/adr/adr-NNNN-*`),
агрегирующий эволюцию. Числовой порог `3` выбран как граница, за которой inline-перечисление
перестаёт быть читаемым (один-два маркера ещё информативны, три и больше — уже раскопки). Пример из
кода: `src/merge_gate.py` (ORCH-043/065/071/073…) → сводные `adr-0006/0013/0014/0016`. Это конвенция
для **нового/правимого** блока — массовая переразметка существующих файлов вне объёма (NFR-3).

### D5 — Fallback-доступ к чужому ADR (FR-5, AC-4)

Когда папки `docs/work-items/ORCH-NNN/` нет в текущей ветке (срезана от `main` без неё) —
задокументированный штатный способ чтения из `origin/main`:

```
git show origin/main:docs/work-items/ORCH-NNN/06-adr/ADR-001-<slug>.md
git ls-tree origin/main:docs/work-items/ORCH-NNN/06-adr/        # листинг
git fetch origin                                                 # при необходимости заранее
```

Присутствует и в `TRACEABILITY.md` §5, и в `developer.md` (рядом с правилом чтения) — агент без
папки в ветке знает штатный путь к чужому ADR.

### D6 — Сквозная регистрация adr-0022 (BR-7)

Решение кросс-каттинговое: вводит нормативный стандарт разработки и ось ревью, действующие на ВСЕХ
агентов и ВСЕ проекты из общего инстанса (self-hosting). По прецеденту цепочки эпика 52
(52b→adr-0019, 52c→adr-0020, 52d→adr-0021) заводится **adr-0022** (следующий 4-значный номер).
Per-work-item ADR (этот файл) — детальное решение; глобальный — точка входа для будущих агентов.

### D7 — Нулевое касание кода и QG (NFR-1, FR раздела «Изменения схемы/QG»)

`src/**`, `STAGE_TRANSITIONS`, `QG_CHECKS`, `check_*`, `_parse_*`, `src/frontmatter.py`, схема БД —
**не трогаются**. `frontmatter_validation_strict` остаётся `False` — enforcement не вводится. Новый
QG не регистрируется. Анти-регресс — расширение `tests/test_agent_prompts_canon.py` (tests-only):
утверждение присутствия reading-rule/`TRACEABILITY`-маркеров в developer/architect/reviewer, по
образцу `_ANTI_REGRESS`. Существующие проверки 52d (5 секций, 6 полей, точный регистр verdict-ключей,
self-hosting-маркеры deployer) и `test_agent_frontmatter_no_model.py` остаются зелёными.

## Альтернативы

- **Машинный гейт маркеров** (CI-lint: «правка маркированной строки без касания соответствующего
  ADR → fail», или enforcement через frontmatter) — **отвергнуто**: требует правки `src/`/CI вне
  scope (NFR-1); для self-hosting рискованно (ложный fail валит конвейер всех проектов); премэйчур
  при отсутствии даже описательного стандарта. Сначала норматив + анти-регресс промптов; машинный
  enforcement — потенциальная будущая задача (как hard-fail схемы в adr-0021).
- **Массовый ретро-фит 51 маркера** (привести все к формату «маркер + ссылка на ADR») —
  **отвергнуто**: огромный диф, риск регресса смысла, вне объёма; стандарт нормативен «на будущее»
  (NFR-3).
- **Копировать текст правила в каждый промпт** (без `TRACEABILITY.md` как источника) —
  **отвергнуто**: дрейф формулировок между 4 файлами, нарушение анти-дубль BR-6; теряется единая
  точка обновления.
- **Не заводить сквозной ADR (только per-work-item)** — **отвергнуто**: рвёт цепочку эпика 52
  (52b/c/d все имеют глобальный ADR); будущий агент не найдёт точку входа в стандарт трассировки.

## Последствия

- **+** Замыкается слой 4 эпика 52: сложившаяся практика маркеров получает формальный контракт +
  правило чтения, защищающее от слома инвариантов (класс «фантомного merge»).
- **+** Reviewer получает явную ось контроля → правка чужого маркированного кода без сверки с ADR
  ловится в ревью (finding ≥P1).
- **+** Единый источник правила (D2) → нет дрейфа между промптами; обновление — в одном файле.
- **+** Self-hosting без рестарта: промпт `cat`-ается из worktree при запуске → правило вступает в
  силу на следующем worktree от `main` без рестарта прод-контейнера 8500 (NFR-4).
- **+** Полная обратимость: чисто текстовое изменение, нет миграций/состояния/kill-switch.
- **−** Рост объёма 3 промптов (митигейшн: короткие врезки-ссылки вместо инлайна — D2).
- **−** Риск регресса инструкции при точечной правке (митигейшн: расширенный
  `test_agent_prompts_canon.py` — D7; см. `10-tech-risks.md` TR-2).
- **−** Стандарт нормативен, но не enforced машинно → соблюдение держится на дисциплине агентов +
  ревью (осознанный компромисс; машинный gate — отдельная будущая задача).
- **Откат:** `git revert` PR полностью возвращает прежнее состояние — стандарт удаляется, врезки
  исчезают, поведение кода и гейтов идентично (нечего гейтить, NFR-5).

## Ссылки
- BRD: `docs/work-items/ORCH-078/01-brd.md`
- TRZ: `docs/work-items/ORCH-078/02-trz.md`
- Acceptance: `docs/work-items/ORCH-078/03-acceptance-criteria.md`
- Технические риски: `docs/work-items/ORCH-078/10-tech-risks.md`
- Сквозной ADR: `docs/architecture/adr/adr-0022-traceability-marker-standard.md`
- Цепочка эпика 52: `adr-0019` (52b), `adr-0020` (52c), `adr-0021` (52d)
- Сверено по коду: `src/serial_gate.py:241,269` (ORCH-088, `t2.id < jobs.task_id`),
  `src/merge_gate.py` (26 маркеров), `tests/test_agent_prompts_canon.py` (`_ANTI_REGRESS`),
  `.openclaw/agents/{developer,architect,reviewer}.md`
- Прецедент класса ошибки: `docs/history/LESSONS_2026-06-08_phantom-merge.md`
