Слой 4 (трассировка) эпика ORCH-52, замыкающий цепочку 52b/52c/52d. Docs + prompts-only: src/**, STAGE_TRANSITIONS, QG_CHECKS, src/frontmatter.py, схема БД — не тронуты; новый QG не вводится; ретро-фит 51 маркера вне объёма. - Новый нормативный стандарт docs/_standards/TRACEABILITY.md: формат маркера, правило размещения, чтение истории с реальным проверяемым примером (src/serial_gate.py → ORCH-088 → ADR-001-serial-gate.md), fallback-доступ (git show origin/main:...), анти-археология (3+ → сводный сквозной ADR), каноничный текст правила чтения (единый источник). - Точечные аддитивные врезки в промпты (52d-канон не переписан): developer.md (правило чтения чужого маркера + fallback, «❌ X → ✅ Y»), architect.md (правило чтения + анти-археология), reviewer.md (усиление оси «Соответствие ADR» под-пунктом: слом маркированного инварианта → finding ≥P1). Все три ссылаются на единый текст в TRACEABILITY.md, не копируют (анти-дубль BR-6). - Сопутствующе: CLAUDE.md, docs/architecture/README.md (слой 4 эпика 52), CHANGELOG.md. - Анти-регресс: расширен tests/test_agent_prompts_canon.py (9 новых проверок); проверки 52d и test_agent_frontmatter_no_model.py зелёные; полный pytest tests/ -q зелёный (1253 passed), src/ не изменён. Refs: ORCH-078 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
148 lines
10 KiB
Markdown
148 lines
10 KiB
Markdown
# TRACEABILITY — стандарт маркеров-трассировки `ORCH-NNN` (golden source трассировки)
|
||
|
||
> **Назначение.** Единый нормативный контракт: как нетривиальная строка/блок/инвариант в коде
|
||
> привязывается к work item, который его ввёл, и к его архитектурному решению (ADR). Это **слой 4
|
||
> (трассировка)** эпика **ORCH-52** — рядом с `PIPELINE_DOCS.md` (слой 1, структура документов) и
|
||
> `HANDOFF_PROTOCOL.md` (слой 2, машинный frontmatter-контракт).
|
||
>
|
||
> **Статус истины.** Документ **кодифицирует сложившуюся практику**, а не вводит новый синтаксис.
|
||
> Источник истины о *поведении* остаётся код (`src/stages.py`, `src/qg/checks.py`,
|
||
> `src/stage_engine.py`); этот стандарт — описательно-нормативный, **не машинный гейт конвейера**.
|
||
> Соблюдение держится на дисциплине агентов + оси ревью (`reviewer.md`), а не на CI-lint.
|
||
|
||
Введён задачей **ORCH-078** (ORCH-52e). Сквозной ADR:
|
||
[`docs/architecture/adr/adr-0022-traceability-marker-standard.md`](../architecture/adr/adr-0022-traceability-marker-standard.md);
|
||
детально — `docs/work-items/ORCH-078/06-adr/ADR-001-traceability-marker-standard.md`. Продолжает
|
||
цепочку стандартов эпика 52: adr-0019 (52b), adr-0020 (52c), adr-0021 (52d).
|
||
|
||
---
|
||
|
||
## 1. Назначение и определение
|
||
|
||
**Маркер `ORCH-NNN`** (а для проекта enduro-trails — `ET-NNN`) в коде = обязательный стандарт
|
||
трассировки: он привязывает нетривиальную строку / блок / инвариант к work item, который его ввёл,
|
||
и к его ADR. Это даёт читающему агенту прямой путь «строка кода → решение, которое её породило»,
|
||
вместо `git blame`-археологии.
|
||
|
||
**Факт (сверено на 2026-06-09):** в `src/` де-факто живёт **51 уникальный** маркер `ORCH-NNN`
|
||
(`grep -rhoE 'ORCH-[0-9]+' src/ | sort -u | wc -l` → `51`) — сложившаяся практика. Этот стандарт её
|
||
формализует. **Массовый ретро-фит существующих 51 маркера вне объёма** — стандарт нормативен «на
|
||
будущее»: его правила применяются к **новому и правимому** коду.
|
||
|
||
---
|
||
|
||
## 2. Формат маркера
|
||
|
||
Маркер — это **inline-комментарий** (или фрагмент docstring модуля/функции), содержащий идентификатор
|
||
work item `ORCH-NNN`. Рекомендуется рядом указывать ссылку на конкретное решение в ADR, чтобы трасса
|
||
вела не просто к задаче, а к пункту решения:
|
||
|
||
```python
|
||
# Ordering term — ``t2.id < jobs.task_id`` (FIFO, ORCH-088, ADR-001 D1 / FR-2): a task
|
||
# does not enter `analysis` while an earlier unfinished task exists in the same repo.
|
||
```
|
||
|
||
Нового синтаксиса не вводится — кодифицируется уже сложившийся стиль (`ORCH-NNN[, ADR-001 D1]`).
|
||
|
||
---
|
||
|
||
## 3. Где ставится маркер
|
||
|
||
Маркер ставится рядом с **нетривиальным инвариантом**, понимание которого требует контекста решения:
|
||
|
||
- выбор fail-open / fail-closed поведения;
|
||
- точное условие сериализации / упорядочивания (FIFO, lease, барьер);
|
||
- идемпотентность / защита от повторной обработки;
|
||
- обходимая «дыра» конвейера, которую блок закрывает;
|
||
- любое условие, чьё «почему именно так» зафиксировано в ADR.
|
||
|
||
Маркер **НЕ ставится** на тривиальном/самоочевидном коде (геттеры, простые присваивания, очевидные
|
||
проверки) — это только зашумляет.
|
||
|
||
**Правило для нового кода:** вводишь значимый инвариант → ставь маркер своей задачи (`ORCH-NNN`)
|
||
рядом, по возможности со ссылкой на пункт ADR.
|
||
|
||
---
|
||
|
||
## 4. Как читать историю (с реальным проверяемым примером)
|
||
|
||
Пошагово, от строки кода к решению:
|
||
|
||
1. Видишь в коде маркер `ORCH-NNN` у строки/блока, который собираешься менять.
|
||
2. Открываешь его архитектурное решение: `docs/work-items/ORCH-NNN/06-adr/`.
|
||
3. Читаешь зафиксированный инвариант ПЕРЕД правкой; не ломаешь его (см. §7).
|
||
|
||
**Проверяемый пример из реального кода (`main`):**
|
||
|
||
> `src/serial_gate.py` несёт условие сериализации `t2.id < jobs.task_id` с маркером **ORCH-088**
|
||
> и отсылкой `ADR-001 D1 / FR-2` (FIFO-уточнение serial-gate). Чтобы понять, почему задача не входит
|
||
> в `analysis`, пока в репо есть более ранняя незавершённая задача, читаешь:
|
||
> `docs/work-items/ORCH-088/06-adr/ADR-001-serial-gate.md`.
|
||
|
||
Пример ссылается на **реально существующие** в `main` файл и ADR — иначе стандарт опровергал бы сам
|
||
себя (нерабочая трассировка).
|
||
|
||
---
|
||
|
||
## 5. Fallback-доступ к чужому ADR
|
||
|
||
Папки `docs/work-items/ORCH-NNN/` может **не быть в текущей ветке** (она срезана от `main` без неё —
|
||
типично для ветки другой задачи). Штатный способ прочитать чужой ADR — взять его из `origin/main`:
|
||
|
||
```bash
|
||
git fetch origin # при необходимости заранее
|
||
git ls-tree origin/main:docs/work-items/ORCH-NNN/06-adr/ # листинг доступных ADR
|
||
git show origin/main:docs/work-items/ORCH-NNN/06-adr/ADR-001-<slug>.md # прочитать конкретный
|
||
```
|
||
|
||
Это не блокер: отсутствие папки в ветке ≠ отсутствие решения — оно всегда есть в `main`.
|
||
|
||
---
|
||
|
||
## 6. Анти-археология: 3+ маркеров → сводный сквозной ADR
|
||
|
||
Если функция/блок несёт **3+** маркеров `ORCH-NNN` (эволюционировал через много задач), раскопки по
|
||
каждому work item нечитаемы. Вместо перечисления всех задач ставится **одна сводная ссылка на
|
||
сквозной ADR** (`docs/architecture/adr/adr-NNNN-*`), агрегирующий эволюцию.
|
||
|
||
Числовой порог `3` — граница, за которой inline-перечисление перестаёт быть читаемым (один-два
|
||
маркера ещё информативны, три и больше — уже археология).
|
||
|
||
**Пример из кода:** `src/merge_gate.py` несёт маркеры ORCH-043/065/071/073 (и ещё несколько) →
|
||
читать сводные сквозные `adr-0006` (merge-gate), `adr-0013` (merge-verify-gate),
|
||
`adr-0014` (sha-source-of-truth), `adr-0016` (ensure-open-PR) в `docs/architecture/adr/`, а не 8
|
||
отдельных work item.
|
||
|
||
Это конвенция для **нового/правимого** блока; массовая переразметка существующих файлов вне объёма.
|
||
|
||
---
|
||
|
||
## 7. Правило чтения (каноничная формулировка — единый источник)
|
||
|
||
Это **единственное** место, где живёт каноничный текст правила. Промпты агентов
|
||
(`developer.md`/`architect.md`/`reviewer.md`) **ссылаются** на него, а не копируют — чтобы не было
|
||
дрейфа формулировок между файлами.
|
||
|
||
> **Правишь код с маркером `ORCH-NNN` → прочитай его `docs/work-items/ORCH-NNN/06-adr/` ПЕРЕД
|
||
> изменением; не сломай зафиксированный инвариант. Не можешь сохранить инвариант — эскалируй /
|
||
> верни задачу в анализ, не правь вслепую.** Папки нет в ветке → читай из `origin/main` (§5). Блок
|
||
> несёт 3+ маркеров → опирайся на сводный сквозной ADR (§6).
|
||
|
||
Кто и как применяет правило:
|
||
|
||
- **developer / architect** — обязаны выполнить чтение ПЕРЕД правкой маркированного кода.
|
||
- **architect** — при введении/правке блока с 3+ маркерами оформляет/обновляет сводный сквозной ADR.
|
||
- **reviewer** — проверяет соблюдение: правка маркированного (`ORCH-NNN`) кода без сверки с его ADR
|
||
или со сломом инварианта → finding (рекомендуемая severity **P1**; слом критического инварианта
|
||
конвейера — на усмотрение reviewer вплоть до P0).
|
||
|
||
---
|
||
|
||
## Связи
|
||
|
||
- Сквозной ADR: [`adr-0022`](../architecture/adr/adr-0022-traceability-marker-standard.md).
|
||
- Стандарты-соседи: [`PIPELINE_DOCS.md`](PIPELINE_DOCS.md) (слой 1),
|
||
[`HANDOFF_PROTOCOL.md`](HANDOFF_PROTOCOL.md) (слой 2).
|
||
- Цепочка эпика 52: adr-0019 (52b) / adr-0020 (52c) / adr-0021 (52d) / adr-0022 (52e).
|
||
- Прецедент класса ошибки (слом инварианта без чтения ADR): `docs/history/LESSONS_2026-06-08_phantom-merge.md`.
|