architect(ET): auto-commit from architect run_id=792
All checks were successful
CI / test (push) Successful in 1m15s
All checks were successful
CI / test (push) Successful in 1m15s
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
---
|
||||
work_item: ORCH-108
|
||||
stage: architecture
|
||||
author_agent: architect
|
||||
status: proposed
|
||||
created_at: 2026-06-17
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# ADR-001: Размещение пользовательского FAQ по STOP и контур анти-дрейфа
|
||||
|
||||
Work Item: **ORCH-108** — FAQ: как использовать статус STOP для отмены задачи
|
||||
Стадия: **architecture**
|
||||
Сквозная регистрация: **N/A — локальное решение задачи** (docs-only; новых QG/стадий/
|
||||
компонентов/таблиц нет, маркеры `ORCH-NNN` в `src/**` не вводятся → сквозной
|
||||
`docs/architecture/adr/adr-NNNN-*` не требуется; критерий — `docs/_standards/PIPELINE_DOCS.md` §4).
|
||||
|
||||
## Статус
|
||||
Proposed
|
||||
|
||||
## Контекст
|
||||
|
||||
Механизм отмены задачи через Plane-статус **STOP** реализован в ORCH-090
|
||||
(`docs/architecture/adr/adr-0026-stop-cancel-task.md`, `src/cancel.py`,
|
||||
`src/stage_engine.py::cancel_task`, `src/webhooks/plane.py`). Пользовательской
|
||||
инструкции «как этим пользоваться» нет — упоминания STOP разрознены и адресованы разным
|
||||
читателям (витрина `docs/overview/business.md` «Сценарий 6», инженерный обзор
|
||||
`docs/overview/tech-pipeline.md` «Отмена: STOP → `cancelled`», глубокий ADR ORCH-090). Это
|
||||
порождает неверную ментальную модель («STOP откатит мой код из прода» — **неверно**) и нагрузку
|
||||
на оператора (self-hosting: один инстанс на все проекты).
|
||||
|
||||
Аналитик (BRD/TRZ/AC, `ready-for-review`) полностью описал требуемый артефакт и приложил готовый
|
||||
черновик содержания (TRZ Приложение A). Это **docs-only** задача: `src/**`, `STAGE_TRANSITIONS`,
|
||||
`QG_CHECKS`, `check_*`, схема БД — не меняются; поведение STOP фиксировано ORCH-090 и FAQ его лишь
|
||||
**документирует**. Архитектурных решений по существу два: (1) куда положить FAQ в дереве доков и
|
||||
(2) как структурно защитить его от дрейфа «доки ↔ код». Остальное — исполнение на стадии
|
||||
development.
|
||||
|
||||
Факты, сверенные на ветке задачи (read-only):
|
||||
- Цели перекрёстных ссылок **существуют**: `docs/overview/business.md` §«Сценарий 6: остановить
|
||||
задачу» (стр. 96), `docs/overview/tech-pipeline.md` §«Отмена: STOP → `cancelled`» (стр. 122),
|
||||
`docs/work-items/ORCH-090/06-adr/ADR-001-stop-cancel-task.md`. Ссылки FR-4 не «висячие».
|
||||
- Семантика разделов доков (ORCH-011, `adr-0039`): `overview/` — витрина «что за система»,
|
||||
`architecture/` — инженерный справочник, `deployment/` — «как развернуть у себя»,
|
||||
`operations/` — «как эксплуатировать наш прод» (runbook'и: `ONBOARDING.md`,
|
||||
`PHANTOM_MERGE_RUNBOOK.md`, `STAGING.md`, …).
|
||||
- `docs/overview/` — **курируемый плоский каталог из 10 файлов**, чьё содержимое прибито
|
||||
структурным тестом `tests/test_system_docs.py` (витрина — не свалка произвольных доков).
|
||||
- Прецедент анти-дрейф теста документа — `tests/test_lite_setup_doc.py` (детерминированный,
|
||||
offline; позитивные якоря-секции + «кирпичи» + кросс-ссылки + негативный скан запрещённых
|
||||
литералов по `FORBIDDEN`).
|
||||
|
||||
## Решение
|
||||
|
||||
### Сводка
|
||||
Размещаем FAQ как **`docs/operations/FAQ_STOP.md`** — пользовательский документ «вопрос → ответ»,
|
||||
прилинкованный из витрины/обзора и закрытый детерминированным структурным тестом
|
||||
`tests/test_faq_stop_doc.py`. Утверждаем разумный дефолт аналитика (A1) как архитектурное решение,
|
||||
с явной фиксацией ключевого нюанса теста — **негативный скан проверяет запрещённые
|
||||
утверждения, а не голые подстроки** (иначе он ложно срабатывал бы на предложениях, которые эти же
|
||||
термины корректно **отрицают**).
|
||||
|
||||
### D1 — Размещение: `docs/operations/FAQ_STOP.md` (BR-1, A1)
|
||||
FAQ ложится в `docs/operations/` рядом с операторскими runbook'ами.
|
||||
|
||||
Обоснование выбора между тремя кандидатами (аудитория FAQ «пользователь доски + оператор»
|
||||
неоднородна, поэтому секция не очевидна):
|
||||
- **`docs/overview/` — отвергнуто.** Это курируемая витрина фиксированного состава (10 файлов),
|
||||
защищённая `tests/test_system_docs.py`; добавление отдельного FAQ нарушит инвариант каталога
|
||||
витрины и саму семантику «обзор, а не справочник процедур».
|
||||
- **Новый раздел `docs/faq/` — отвергнуто.** Заведение top-level раздела ради одного документа —
|
||||
scope-creep; нет канона/индекса/норматива сопровождения для нового раздела.
|
||||
- **`docs/operations/FAQ_STOP.md` — выбрано.** Это де-факто дом человеко-ориентированных процедур
|
||||
и «что делать, если…» (тробл-шутинг STOP в FR-2 п.7 ссылается на `stop_status_enabled`/
|
||||
`stop_status_repos`, а «где увидеть результат» в п.8 — на read-only блок `stop` в `GET /queue`;
|
||||
обе темы — операторская территория). Пользователь доски и оператор на self-hosting сильно
|
||||
пересекаются; именно к operations-доке оператор отсылает пользователя.
|
||||
|
||||
Документированная остаточная издержка: лёгкое несоответствие «аудитория-пользователь ↔
|
||||
секция-operations». Принимается осознанно (см. «Последствия»); пере-размещение в будущий
|
||||
`docs/faq/` остаётся дешёвым (один файл + правка двух ссылок + одного теста).
|
||||
|
||||
### D2 — Граница объёма: docs-only, без рантайм-поверхности (NFR-1, AC-10)
|
||||
Подтверждаю и фиксирую как архитектурный инвариант:
|
||||
- `src/**`, `STAGE_TRANSITIONS`, `QG_CHECKS`, `check_*`, machine-verdict ключи, схема БД — **не
|
||||
трогаются**; kill-switch не требуется (нет исполняемого кода).
|
||||
- **`07-infra-requirements.md` — N/A** (топология/контейнеры/сеть не меняются).
|
||||
- **`08-data-requirements.md` — N/A** (таблиц/колонок/индексов не добавляется).
|
||||
- `docs/architecture/README.md` / `internals.md` — **не обновляются**: задача не затрагивает
|
||||
стадии/QG/компоненты (новый operations-FAQ описывает уже задокументированную фичу ORCH-090, не
|
||||
вводя архитектурных сущностей). Внесение FAQ в архитектурный справочник было бы дублированием
|
||||
источника истины (нарушение NFR-5).
|
||||
- Coverage-гейт (ORCH-027): docs-only не добавляет строк `src/` → базовая линия покрытия не
|
||||
меняется; `tests/test_faq_stop_doc.py` — структурный тест документа, `src/` не покрывает и на
|
||||
метрику не влияет.
|
||||
|
||||
### D3 — Контур анти-дрейфа: `tests/test_faq_stop_doc.py`, негативный скан на уровне утверждений (NFR-4, FR-6, AC-11)
|
||||
Структурный тест по образцу `tests/test_lite_setup_doc.py` — детерминированный, **без сети/LLM/
|
||||
subprocess**, только парсинг файла. Обязательный состав проверок:
|
||||
1. **Существование** `docs/operations/FAQ_STOP.md`.
|
||||
2. **Позитивные якоря** — все 8 обязательных секций-вопросов TRZ §FR-2 присутствуют (заголовки —
|
||||
стабильные якоря; тест матчит по нормализованному заголовку, не по точной пунктуации).
|
||||
3. **«Кирпичи»-факты** — присутствуют ключевые токены (`STOP`, `cancelled`, «To Analyse»,
|
||||
«отлож…»/`deferred`, упоминание `GET /queue`/блока `stop`).
|
||||
4. **Кросс-ссылки** (FR-4) — ссылка на `tech-pipeline.md` и на ADR ORCH-090 присутствует.
|
||||
5. **Негативный скан (КЛЮЧЕВОЙ нюанс).** Запрещённые **утверждения** FR-5 («STOP откатывает
|
||||
прод», «STOP трогает `main`/force-push», «продолжить с середины», «STOP мгновенно убивает
|
||||
деплой») детектируются как **утверждения целиком**, а **НЕ** как голые подстроки. Причина:
|
||||
корректный FAQ закономерно содержит слова `main`, «откатыва…», «force-push», «деплой» внутри
|
||||
**отрицающих** предложений («STOP **не откатывает** … `main`»). Наивный substring-скан по этим
|
||||
словам ложно завалит именно те фразы, которые требование AC-9 предписывает иметь. Реализация:
|
||||
матчить нормативно-запрещённые фразы (например, утверждение отката прод-кода **без**
|
||||
отрицания рядом), либо проверять, что запрещённый токен встречается только в соседстве с
|
||||
отрицанием. Конкретную форму выбирает разработчик; инвариант — **тест не должен фолзить на
|
||||
фактически верном FAQ** и **обязан краснеть на реально ложном утверждении**.
|
||||
|
||||
Контракт теста — никогда не делать сеть/LLM/subprocess (как и эталон), чтобы оставаться частью
|
||||
обычного зелёного `tests/` без инфра-зависимостей.
|
||||
|
||||
### D4 — Целостность ссылок и link-first (FR-4, NFR-5, AC-8)
|
||||
Перекрёстные ссылки добавляются **в обе стороны** (витрина/обзор → FAQ; FAQ → обзор + ADR
|
||||
ORCH-090). Источник истины поведения остаётся за ADR ORCH-090 и инженерным обзором — FAQ их
|
||||
**не форкает** (машинные детали: маркеры/lease/тумбстон — только ссылками). Цели ссылок
|
||||
проверены существующими (см. Контекст). Якорь-слаг на секцию обзора
|
||||
(`tech-pipeline.md` «Отмена: STOP → `cancelled`») разработчик обязан сверить с фактической
|
||||
генерацией якоря при переносе (риск TR-4).
|
||||
|
||||
### D5 — Норматив сопровождения (traceability)
|
||||
Фиксируется правило: **правишь поведение STOP** (`src/cancel.py` / `cancel_task` / маршрут `stop`
|
||||
в `src/webhooks/plane.py`) → **обнови `docs/operations/FAQ_STOP.md` в том же PR** (правило агентов
|
||||
№2/№6; reviewer-ось «документация»). Машинный маркер `ORCH-108` в `src/**` НЕ вводится (docs-only),
|
||||
поэтому анти-археологии маркеров (`docs/_standards/TRACEABILITY.md`) этот PR не порождает; связь
|
||||
«код STOP ↔ FAQ» держится нормативом сопровождения + структурным тестом D3.
|
||||
|
||||
## Альтернативы
|
||||
- **FAQ в `docs/overview/`** — отвергнуто: курируемая витрина фиксированного состава под
|
||||
`tests/test_system_docs.py`; FAQ ≠ обзорный слайд (см. D1).
|
||||
- **Новый раздел `docs/faq/`** — отвергнуто: scope-creep ради одного файла (см. D1).
|
||||
- **Без анти-дрейф теста, полагаясь на reviewer** — отвергнуто: NFR-4 требует структурной
|
||||
защиты от дрейфа «доки ↔ код»; ручная проверка не воспроизводима.
|
||||
- **Негативный скан по голым подстрокам** — отвергнуто: ложные срабатывания на корректно
|
||||
отрицающих предложениях (см. D3) — это сделало бы тест либо красным на верном FAQ, либо
|
||||
вынудило бы выкинуть из FAQ обязательные явные отрицания.
|
||||
- **Сквозной (global) ADR** — отвергнуто: решение не кросс-каттинговое (нет нового QG/стадии/
|
||||
компонента/таблицы; не меняет канон доков как такой).
|
||||
|
||||
## Последствия
|
||||
- **+** Единый самодостаточный источник для пользователя доски → меньше неверных ожиданий и
|
||||
обращений к оператору (self-hosting-выгода).
|
||||
- **+** Структурный тест (D3) делает дрейф «доки ↔ код» воспроизводимо ловимым; норматив D5
|
||||
закрывает процессный пробел.
|
||||
- **+** Нулевой рантайм-риск: docs-only, прод-деплой этой задачи безопасен.
|
||||
- **−** Лёгкое несоответствие «пользовательская аудитория ↔ секция operations» (D1). Митигейшн:
|
||||
явный вводный абзац «для кого» в FAQ + дешёвое будущее пере-размещение.
|
||||
- **−** Риск чрезмерно строгого негативного скана (D3). Митигейшн: матч на уровне утверждений +
|
||||
явный инвариант «не фолзить на верном FAQ» (TR-3).
|
||||
- **Откат:** удалить `docs/operations/FAQ_STOP.md` и `tests/test_faq_stop_doc.py`, снять
|
||||
добавленные ссылки из `business.md`/`tech-pipeline.md` и запись из `CHANGELOG.md`. Рантайм не
|
||||
затрагивается.
|
||||
|
||||
## Ссылки
|
||||
- BRD: `docs/work-items/ORCH-108/01-brd.md`
|
||||
- TRZ: `docs/work-items/ORCH-108/02-trz.md` (+ Приложение A — черновик содержания FAQ)
|
||||
- Acceptance: `docs/work-items/ORCH-108/03-acceptance-criteria.md`
|
||||
- Tech-risks: `docs/work-items/ORCH-108/10-tech-risks.md`
|
||||
- Источник истины поведения STOP: `docs/work-items/ORCH-090/06-adr/ADR-001-stop-cancel-task.md`,
|
||||
`docs/architecture/adr/adr-0026-stop-cancel-task.md`
|
||||
- Сверено по коду: `src/cancel.py`, `src/stage_engine.py::cancel_task`,
|
||||
`src/webhooks/plane.py` (`handle_issue_updated`/`handle_stop`/`handle_status_start`),
|
||||
`src/config.py` (`stop_status_enabled`/`stop_status_repos`), `src/main.py` (блок `stop` в
|
||||
`GET /queue`)
|
||||
- Эталон анти-дрейф теста: `tests/test_lite_setup_doc.py`
|
||||
- Семантика разделов доков: `docs/architecture/adr/adr-0039-system-overview-docs-canon.md`
|
||||
39
docs/work-items/ORCH-108/10-tech-risks.md
Normal file
39
docs/work-items/ORCH-108/10-tech-risks.md
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
work_item: ORCH-108
|
||||
stage: architecture
|
||||
author_agent: architect
|
||||
status: proposed
|
||||
created_at: 2026-06-17
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# 10 — Технические риски: ORCH-108 — FAQ по статусу STOP
|
||||
|
||||
Work Item: **ORCH-108** · Repo: **orchestrator** (self-hosting) · Стадия: architecture
|
||||
|
||||
> Информационный документ (гейтом не парсится). Перечисляет риски реализации **docs-only**
|
||||
> задачи и их митигейшн. Класс рисков — минимальный: рантайм/конвейер не затрагиваются.
|
||||
|
||||
## Реестр рисков
|
||||
|
||||
| ID | Риск | Вер. | Влия. | Митигейшн |
|
||||
|----|------|------|-------|-----------|
|
||||
| TR-1 | **Дрейф «доки ↔ код».** Будущая правка поведения STOP (`src/cancel.py`/`cancel_task`/маршрут `stop`) сделает FAQ неверным. | Сред. | Сред. | Структурный анти-дрейф тест `tests/test_faq_stop_doc.py` (ADR D3) + норматив сопровождения «правишь STOP → обнови FAQ в том же PR» (ADR D5) + reviewer-ось «документация». |
|
||||
| TR-2 | **FAQ-«сирота» / дубль источника истины.** FAQ не связан с витриной или дословно копирует ADR/обзор вместо ссылки. | Низ. | Низ. | Link-first (ADR D4): двусторонние ссылки (AC-8), машинные детали — только ссылками; тест проверяет наличие кросс-ссылок. |
|
||||
| TR-3 | **Ложно-строгий негативный скан.** Тест ищет запрещённые слова (`main`, «откатыва…», `force-push`) как голые подстроки → краснеет на корректно **отрицающих** предложениях FAQ (которые AC-9 предписывает иметь). | Сред. | Сред. | Негативный скан — на уровне **утверждений**, а не подстрок (ADR D3); инвариант «тест не фолзит на верном FAQ, но краснеет на реально ложном». Зеркало эталона `tests/test_lite_setup_doc.py`. |
|
||||
| TR-4 | **Битый якорь кросс-ссылки.** Ссылка `tech-pipeline.md#отмена-stop--cancelled` не совпадёт с фактически генерируемым slug заголовка «Отмена: STOP → `cancelled`». | Низ. | Низ. | Разработчик сверяет slug при переносе (ADR D4); цели секций подтверждены существующими (business.md §«Сценарий 6», tech-pipeline.md §«Отмена», ADR ORCH-090). |
|
||||
| TR-5 | **Фактическая неточность FAQ.** Утверждение расходится с кодом (напр. «STOP откатит прод», «убивает деплой мгновенно»). | Низ. | Выс. | NFR-2/FR-5/AC-9: каждое утверждение verifiable против read-only модулей (ADR §Ссылки); reviewer сверяет с кодом; негативный скан (TR-3) ловит запрещённый класс. Содержание выверено аналитиком (TRZ Приложение A). |
|
||||
| TR-6 | **Ошибочное размещение раздела.** Аудитория FAQ — «пользователь доски», секция — `operations/` («наш прод»). | Низ. | Низ. | Осознанный компромисс (ADR D1): альтернативы (`overview/` под тестом витрины, новый `docs/faq/`) хуже; вводный абзац «для кого»; будущее пере-размещение дёшево (1 файл + 2 ссылки + 1 тест). |
|
||||
|
||||
## Сводный вывод
|
||||
|
||||
Доминирующий класс — **дрейф документации** (TR-1) и **хрупкость анти-дрейф теста** (TR-3); оба
|
||||
структурно снижены решением D3 (claim-level негативный скан + детерминированный offline-тест) и
|
||||
нормативом сопровождения D5. Рантайм-рисков **нет**: задача docs-only, не трогает `src/**`/
|
||||
`STAGE_TRANSITIONS`/`QG_CHECKS`/схему БД, не деплоит/не рестартит прод/не трогает `main` →
|
||||
self-hosting-безопасна, прод-деплой безвреден.
|
||||
|
||||
**Эскалация не требуется.** Не `arch:major-change` (нет новой стадии/компонента/смены БД), возврат
|
||||
в анализ не нужен (BRD/TRZ/AC полны и согласованы с кодом; блокирующих неоднозначностей нет —
|
||||
`01-questions.md` аналитиком осознанно не создан). Остаточный риск для прод-конвейера —
|
||||
**пренебрежимо мал**.
|
||||
Reference in New Issue
Block a user