--- work_item: ORCH-119 stage: analysis author_agent: analyst status: ready-for-review created_at: 2026-06-17 model_used: claude-opus-4-8 --- # 01 — BRD / Bug-report: ORCH-119 — `00-business-request.md` всегда `TBD`, теряется source-backed контекст запроса Work Item: **ORCH-119** · Repo: **orchestrator** · Стадия: analysis · Трек: **Bug** (укороченный маршрут, пропуск стадии `architecture`) > 🐞 **Багфикс-трек (ORCH-019).** Облегчённый пакет (bug-report + обязательный регресс-тест), но > все 4 файла analysis (гейт `check_analysis_complete` не меняется). Экономия — в пропуске стадии > `architecture`, не в числе файлов. > > **Эскалация в full-cycle рассмотрена и отклонена.** Дефект — контейнерный data-flow + рендеринг, > чинится **точным зеркалированием уже существующего прецедента `tasks.title`** (персист при создании > задачи → чтение в `_materialize_deferred_branch`). Нет нового компонента, нового QG, политического > решения или визуального артефакта → ADR/макет не требуется. Если разработчик в ходе фикса упрётся в > архитектурное решение (напр. иной механизм персиста, влияющий на схему/контракты) — снять трек: > `POST /bug-fast-track/escalate?work_item=ORCH-119` и пометить здесь `escalate: full-cycle`. --- ## 1. Бизнес-контекст и проблема ### Симптом (наблюдаемое) Для **каждой** созданной задачи файл `docs/work-items//00-business-request.md` генерируется с телом раздела «Description» равным буквальному `TBD`. Реальный текст запроса (описание Plane-issue, обогащённое из Plane API) **не попадает** в персистентный артефакт. Пример — сам этот work item: ``` # Business Request: BUG: 00-business-request.md is always TBD, losing source-backed request context Work Item ID: ORCH-119 ## Description TBD ``` ### Последствие (бизнес-боль) `00-business-request.md` — **точка входа конвейера** и источник для analyst (вход стадии `analysis`, см. `PIPELINE_DOCS.md` §2). Когда тело всегда `TBD`: - source-backed контекст запроса теряется из durable-артефакта репозитория (остаётся только эфемерно в `task_content` analyst-job'а и в Plane); - последующее чтение work item «глазами» (reviewer, человек, ретроспектива, петля уроков) видит пустой бизнес-запрос — невозможно сверить, ту ли задачу решал конвейер; - на **self-hosting** (`orchestrator`) задача почти всегда идёт **отложенным срезом ветки** (serial gate, ORCH-088), где контекст теряется безвозвратно (см. §3, причина B). ### Причина симптома (установленный факт, по коду) `src/webhooks/plane.py::_create_initial_docs` (строка ~925) **хардкодит** тело: ```python content = f"# Business Request: {name}\n\nWork Item ID: {work_item_id}\n\n## Description\n\nTBD\n" ``` Функция принимает только `(repo, branch, work_item_id, name)` — **`description` ей не передаётся**, хотя у вызывающего `start_pipeline` оно есть в области видимости и уже используется для analyst-job (`task_desc`, строка ~725: `Description:\n{description}`). То есть данные **есть**, но в артефакт не доходят. ### Локализация (куда смотреть разработчику) — два пути создания **Путь A — прямой** (`serial_gate` не применим к репо): `start_pipeline` (`src/webhooks/plane.py`) имеет `description` (строки ~518; обогащается из Plane API, ~539–551) → зовёт `_create_initial_docs(repo, branch, work_item_id, name)` (строка ~710) **без** `description`. Достаточно дотянуть аргумент. **Путь B — отложенный (критичный для self-hosting)** (`serial_gate_applies(repo)` → для `orchestrator`): `start_pipeline` **не** создаёт ветку/доки (ORCH-088, анти-stale-base); срез релоцирован в `src/agents/launcher.py::_materialize_deferred_branch` (строки ~514–538), который вызывает то же `_create_initial_docs`, **располагая только `title`** из строки `tasks` (`description` нигде не персистится). Установленный факт схемы: таблица `tasks` **не имеет** колонки `description`; `title` персистится через `_ensure_column` (`src/db.py:125`) и читается в `_spawn`/`_materialize_deferred_branch` именно так. ⇒ Чтобы путь B рендерил описание, `description` надо **сохранить durable при создании задачи** (зеркало `tasks.title`). ### Предусловие истинности данных (установленный факт) QG-0 (`_qg0_errors`, `src/webhooks/plane.py:490`) отклоняет создание при `description` короче 20 символов (строка ~500). ⇒ любая задача, дошедшая до `_create_initial_docs`, **гарантированно имеет непустое осмысленное описание** — терять его тем более недопустимо. Защитный fallback на случай пустого описания всё равно предусмотреть (NFR-2). ## 2. Объём (scope) ### В объёме - Рендер фактического `description` (предпочтительно `description_stripped`, plain-text) в раздел «Description» файла `00-business-request.md` — на **обоих** путях (A прямой, B отложенный). - Durable-персист `description` при создании задачи (зеркало `tasks.title`), чтобы путь B имел доступ к нему на момент claim. - Защитный fallback при отсутствии/пустом описании (без падения). - Обязательный регресс-тест (красный до фикса, зелёный после). ### Вне объёма - Изменение `STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / machine-verdict-ключей / семантики гейтов. - Изменение поведения serial-gate / отложенного среза ветки ORCH-088 (только **дополнить** данными, не менять момент/условие среза). - Ретро-генерация `00-business-request.md` для **уже существующих** задач (только новые создания). - Переформатирование/обогащение структуры самого `00-business-request.md` сверх вставки описания (заголовки/название источника остаются как есть). - Любая запись в Plane (артефакт пишется только в Gitea-ветку, как сейчас). ## 3. Заинтересованные стороны - **Заказчик/оператор** — получает читаемый durable бизнес-запрос вместо `TBD`. - **Агент analyst и reviewer** — могут сверять решённое с запросом по репозиторию. - **Петля уроков / ретроспектива (ORCH-098)** — корректный контекст в артефакте. - Приёмку результата выполняет конвейер (reviewer + Quality Gates), не аналитик. ## 4. Бизнес-требования (BR) - **BR-1** — Раздел «Description» в `00-business-request.md` содержит **фактический текст запроса** (из Plane-issue, как он используется для analyst-job'а), а не литерал `TBD`, для вновь создаваемых задач. - **BR-2** — Поведение одинаково на **обоих** путях создания: прямом (A) и отложенном срезе ветки (B, self-hosting/serial-gate). Путь B — приоритетный сценарий (доминирует на `orchestrator`). - **BR-3** — При отсутствующем/пустом описании артефакт создаётся с **явным безопасным fallback**- маркером (напр. «описание отсутствует в источнике»), без падения создания задачи. - **BR-4** — Сохранён состав/имена артефактов: создаётся ровно `00-business-request.md` по тому же пути; downstream-конвейер (analyst и далее) не затронут. ## 5. Нефункциональные требования (NFR) - **NFR-1 (обратная совместимость / never-break)** — изменение аддитивно: создание задачи **никогда** не должно падать из-за нового рендера/персиста. Любая ошибка обогащения → деградация на безопасное значение (fallback-маркер), а не отказ создания. Идемпотентность `_create_initial_docs` (422 = уже существует → no-op) сохранена. - **NFR-2 (целостность данных)** — описание рендерится **как есть** (plain-text `description_stripped`), без обрезки/искажения; многострочный текст сохраняется. `00-business-request.md` — информационный док (гейтом не парсится), поэтому markdown-спецсимволы в описании безопасны для гейтов. - **NFR-3 (инварианты ORCH-088)** — момент и условие отложенного среза ветки не меняются; описание лишь дополнительно переносится через durable-хранилище (зеркало `tasks.title`), анти-stale-base логика цела. - **NFR-4 (self-hosting-безопасность)** — фикс не деплоит/не рестартит прод, не трогает `main`, не добавляет сетевых вызовов в горячий `claim_next_job`. ## 6. Допущения и ограничения - `description`/`description_stripped` доступны в `start_pipeline` и достаточны как источник (уже используются для analyst-job). Plane-обогащение (ORCH «name_missing/desc_missing» блок) остаётся единственным источником описания — новых сетевых обращений не вводим. - QG-0 гарантирует ≥20 символов описания для прошедших задач (см. §1) — нормальный путь всегда имеет реальный текст. - Персист описания следует **установленному прецеденту `tasks.title`** (аддитивная колонка через `_ensure_column`); это не новое архитектурное решение. ## 7. Критерии успеха Новые задачи получают `00-business-request.md` с реальным описанием на обоих путях; обязательный регресс-тест красный до фикса и зелёный после; полный `pytest tests/ -q` зелёный. Детальные PASS/FAIL — `03-acceptance-criteria.md`. ## 8. Риски - Путь B забыт (чинят только прямой путь A) → на self-hosting баг остаётся. Митигируется обязательным integration-тестом пути B (TC-03). - Регресс схемы/создания задачи при добавлении персиста → митигируется аддитивным `_ensure_column` и тестом обратной совместимости (TC-05). Детальные тех-риски архитектором не выпускаются (bug-track).