From ee0d876f6b8def2be99937d097f2bff169684d7f Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Sat, 24 Oct 2026 16:59:53 +0400 Subject: [PATCH] =?UTF-8?q?docs(dsh):=20=D0=B4=D0=B8=D0=B7=D0=B0=D0=B9?= =?UTF-8?q?=D0=BD=20SDD=20=D0=B4=D0=BB=D1=8F=20DSH=20=E2=80=94=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B6=D0=B8=D0=BC=D1=8B=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D0=B0=20=D0=B8=20=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D1=88=D1=80=D1=83=D1=82=D1=8B=20=D0=BC=D0=BE=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D0=B5=D0=B9=20(#41)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Design note и spec delta для фазы #41: два режима контроллера (главная сессия / фоновый сабагент), асинхронный протокол диспатча и отчётов, fix-loop, ledger с ## Findings, карта из двух маршрутов моделей. Основание — измеренные ограничения DSH 0.2.1-rc.3: subagent.maxDepth по умолчанию 1, у subagent нет provider/model без modelSelectionSettings, выбор модели работает сразу только в workflow.agent(). Co-Authored-By: DeepSeek Harness --- openspec/changes/dsh-sdd/.openspec.yaml | 2 + openspec/changes/dsh-sdd/design.md | 159 ++++++++++++++++++ openspec/changes/dsh-sdd/proposal.md | 71 ++++++++ .../changes/dsh-sdd/specs/dsh-sdd/spec.md | 105 ++++++++++++ 4 files changed, 337 insertions(+) create mode 100644 openspec/changes/dsh-sdd/.openspec.yaml create mode 100644 openspec/changes/dsh-sdd/design.md create mode 100644 openspec/changes/dsh-sdd/proposal.md create mode 100644 openspec/changes/dsh-sdd/specs/dsh-sdd/spec.md diff --git a/openspec/changes/dsh-sdd/.openspec.yaml b/openspec/changes/dsh-sdd/.openspec.yaml new file mode 100644 index 0000000..1f5d280 --- /dev/null +++ b/openspec/changes/dsh-sdd/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-10-24 diff --git a/openspec/changes/dsh-sdd/design.md b/openspec/changes/dsh-sdd/design.md new file mode 100644 index 0000000..df3b47a --- /dev/null +++ b/openspec/changes/dsh-sdd/design.md @@ -0,0 +1,159 @@ +# Design: DSH-native SDD + +## Context + +Claude-SDD (`~/.dsh/skills/subagent-driven-development/SKILL.md`) опирается на +синхронный `Task`: контроллер вызвал implementer'а и в том же ходе получил +отчёт. DSH так не умеет — и это не деталь, а другая форма исполнения. + +Что измерено в DSH 0.2.1-rc.3 (`@deepseek-ai/dsh-tool-subagent`, +`dsh-subagent`, `dsh-tool-workflow`, `dsh-workflow-ptc`): + +| Свойство | Значение в DSH | Следствие для SDD | +|---|---|---| +| `subagent` возвращает | `started subagent ` сразу, результат — уведомлением позже | нет синхронного ожидания; ход контроллера заканчивается | +| Продолжение ребёнка | `send_message` (провайдер `spawn` continuable) | раунды фикса идут в того же implementer'а | +| `subagent_fork` | наследует завершённые ходы родителя | для implementer'а не годится: нужен свежий контекст | +| `subagent.maxDepth` | по умолчанию **1** (настройка сервиса, volatile) | контроллер-сабагент не позовёт implementer'а, пока не поднято до 2 | +| Выбор модели у `subagent` | только при `modelSelectionSettings: true` на строке `tool-subagent`; иначе ребёнок наследует модель сессии | «укажи модель в dispatch» невыполнимо без правки профиля | +| `workflow` | синхронный, один вызов инструмента; `agent(prompt, {schema, provider, model, label, phase})` | годится для детерминированного fan-out с выбором модели без настроек | +| Кэпы `workflow` | `maxTotalAgents`, `maxConcurrentAgents`, `maxItemsPerCall` | backstop для веера; для 3 задач не упираемся | +| Наблюдение за детьми | `list_agents`, `interrupt_agent`, уведомления | «дождаться» = закончить ход и проснуться от уведомления | +| Модели в окружении | `deepseek-official/deepseek-flash`, `deepseek-official/deepseek-v4-pro` | три тира роли схлопываются в два | + +Строка `subagent-model-selection-settings` есть в web/desktop-профиле и +отсутствует в headless. Поэтому флаг `modelSelectionSettings` нельзя ставить в +бандл: headless упадёт на загрузке с «requires … in the Host scope». Он живёт +в opt-in overlay профиля. + +## Goals / Non-Goals + +**Goals** +- Инструкция, по которой DSH-сессия исполняет план без вранья о возможностях + платформы: два режима контроллера, протокол отчётов, ревью задачи, fix-loop, + ledger с `## Findings`, финальное ревью. +- Проверяемый прогон: план из 3 задач в temp-репозитории, дефект найден + ревьюером и закрыт в fix-loop. +- Тесты, идущие без DSH runtime. +- Явная таблица отличий от Claude-SDD. + +**Non-Goals** +- Паритет с `Task`: его не будет, и это фиксируется, а не имитируется. +- Переписывание `~/.dsh/skills/subagent-driven-development/` — skill + superpowers остаётся как есть; DSH-семантика живёт в отдельном skill. +- Правка `roles/dev.md` в общем слое: роль для DSH — слой `~/.dsh/roles`. +- Автоматическое включение выбора модели и глубины: это решение владельца. + +## Решения владельца (brainstorming 24.10.2026) + +- **Режим контроллера зависит от контекста, а не один на всех.** + Одна сложная задача — контроллер главная сессия. Несколько задач параллельно, + каждая по SDD, — контроллер фоновый сабагент на задачу. + +## Design + +### Режим 1 — главная сессия контроллер + +Главная сессия читает план, ведёт ledger, диспатчит `subagent` (depth 1, +укладывается в дефолтный `maxDepth: 1`), получает уведомление, диспатчит +ревьюера, при находках — `send_message` implementer'у. Плюс: рулинги по +конфликтам плана принимает тот, у кого есть спека и контекст. Минус: контекст +главной сессии растёт, поэтому отчёты — файлами, а в контекст возвращается +только статус, коммиты и одна строка тестов. + +### Режим 2 — фоновый контроллер + +Один `subagent` на план, `maxDepth: 2`. Контроллер не блокируется: диспатч +implementer'а возвращает id, ход заканчивается, уведомление о завершении +начинает следующий ход. Пропущенное уведомление ловится `list_agents` перед +следующим диспатчем. Главная сессия в это время свободна для другой задачи. + +### Протокол (общий для обоих режимов) + +1. Setup: ledger `.superpowers/sdd//progress.md`, первая строка — + путь плана; скан плана на конфликты (таблица в ledger, рулинги до Task 1). +2. Dispatch implementer'а: brief файлом, отчёт файлом, контракт — `DONE`, + `DONE_WITH_CONCERNS`, `NEEDS_CONTEXT`, `BLOCKED`. +3. Ревью задачи: пакет диффа файлом, вердикт по спеке и по качеству, находки + `T.`. +4. Fix-loop до 5 раундов: раунды 1–3 — тот же implementer через + `send_message`, 4–5 — свежий и на тир выше; затем адъюдикация. +5. Финальное ревью ветки: `C-n`/`I-n`/`M-n`, один fix-диспатч, одно + скоуп-ревью. +6. Ledger: `## Findings` с маркером и статусом; рулинги `R-n (design #n)`. + +### Модели + +Два маршрута вместо трёх тиров: + +| Роль в SDD | Маршрут | Почему | +|---|---|---| +| implementer по готовому коду из плана | `deepseek-official/deepseek-flash` | транскрипция + тесты | +| implementer по прозе, интеграция | `deepseek-official/deepseek-v4-pro` | решение в нескольких файлах | +| ревью задачи, ре-ревью | `deepseek-official/deepseek-v4-pro` | вердикт важнее цены | +| финальное ревью ветки | `deepseek-official/deepseek-v4-pro` | самый широкий дифф | + +Без overlay всё идёт на модели сессии (`deepseek-flash`); тиры становятся +недоступны, и инструкция это явно говорит, а не молча игнорирует. + +### Где живёт + +`dsh/skills/sdd/SKILL.md` — в репозитории обвязки, ставится +`dsh/install.sh --skills` в `~/.dsh/skills`. Claude Code его не получает: +DoD порта требует, чтобы CC-харнес не менялся. + +## Альтернативы + +- **Только workflow.** Детерминированный fan-out силён для независимых задач, + но решения по конфликтам плана, адъюдикация находок и «стоп, план врёт» + требуют суждения в моменте. Скрипт может ветвиться по структурному ответу + ревьюера, но не может решить, что находка неверна. +- **Только фоновый контроллер.** Дороже на одну задачу и требует поднятой + глубины; для одиночной задачи лишний уровень. +- **Гибрид.** `workflow` — для веера независимых задач внутри плана, + контроллер — для последовательной петли. Держим как расширение, в первой + версии не включаем: веер ещё не встречался в планах этого репозитория. + +## Риски + +- Уведомление о завершении ребёнка не пришло (обрыв, компакция) — контроллер + обязан сверяться с `list_agents` и git, а не с памятью. +- `maxDepth: 2` не поднят, а режим 2 выбран — диспатч упадёт + `subagent depth 2 exceeds maxDepth 1`; инструкция требует проверить до + старта и откатиться в режим 1 с записью рулинга. +- Ledger лежит в git-ignored scratch: `git clean -fdx` его уничтожает; + восстановление — по `git log`. +- Модели две: «haiku» из Claude-текста не существует, перенос формулировок + тиров без таблицы превратится в фикцию. + +## Что должен доказать пробный прогон + +| Пункт приёмки #41 | Чем доказывается | +|---|---| +| 3 задачи не теряются | ledger: три `Task N: complete`, три коммита | +| отчёты собираются | файлы отчётов implementer'ов + строки в ledger | +| ревьюер находит дефект | `T1.1` с `fixed ` | +| fix-loop завершается | раунд в ledger, ре-ревью чистое | +| ledger содержит `## Findings` со статусами | сам файл | +| отличие от Claude-SDD указано | таблица выше + раздел в skill | + +## Decisions made without discussion + +- **24.10.2026 — overlay вместо флага в бандле.** Обоснование: headless-профиль + не содержит строку `subagent-model-selection-settings`, включённый флаг роняет + загрузку. Цена ошибки: владельцу нужно скопировать три записи в профиль + руками; забыл — работает на модели сессии. +- **24.10.2026 — карта тиров.** `flash` — транскрипция и механика, `v4-pro` — + интеграция и все ревью. Цена ошибки: дороже прогон или слабее ревью; правится + одной таблицей в skill. +- **24.10.2026 — skill ставится только в `~/.dsh`.** Обоснование: DoD порта + запрещает менять CC-харнес. Цена ошибки: в Claude-сессиях инструкции про + DSH-режимы нет — там работает исходный `subagent-driven-development`. +- **24.10.2026 — гибрид отложен.** `workflow` описан как расширение, не + реализуется в этом change. Цена ошибки: веер задач придётся ввести позже + отдельной правкой skill. + +## Открытые вопросы + +- Нужно ли после приёмки добавить в `~/.dsh/roles/dev.md` строку «в DSH + исполнение плана — skill `sdd`» (сейчас роль ссылается на superpowers-SDD). diff --git a/openspec/changes/dsh-sdd/proposal.md b/openspec/changes/dsh-sdd/proposal.md new file mode 100644 index 0000000..4dc55f6 --- /dev/null +++ b/openspec/changes/dsh-sdd/proposal.md @@ -0,0 +1,71 @@ +# Proposal: DSH-native SDD + +Issue: #41 (роадмап порта — #48). Источники: +- `dsh/PORT.md`, разделы 3 (deferred: SDD), 7 (риски), 8 (next phases, п. 4); +- brainstorming 24.10.2026 (ответы владельца о режимах контроллера); +- разбор исходников DSH 0.2.1-rc.3: `dsh-tool-subagent`, `dsh-tool-workflow`, + `dsh-subagent`, `dsh-workflow-ptc`. + +## Why + +SDD — единственное место, где DSH расходится с Claude Code не текстом, а +семантикой. В Claude Code контроллер исполняет план, вызывая `Task` и получая +результат в том же ходе; в DSH `subagent` возвращает id и завершается +уведомлением позже, а `workflow` исполняет детерминированный скрипт и ждёт +всех детей. Пока эта разница не переписана, `subagent-driven-development` +в DSH-сессии либо врёт о возможностях платформы, либо ломается на первом +ожидании. + +Дополнительно разбор исходников показал две вещи, которые меняют план: + +1. Глубина делегирования по умолчанию — 1. Фоновый контроллер-сабагент не + может позвать implementer'а, пока `subagent.maxDepth` не поднят до 2. +2. У инструмента `subagent` нет `provider`/`model` в схеме, пока строке + `tool-subagent` не поставлен `modelSelectionSettings: true`; ребёнок + наследует модель сессии. Выбор модели работает сразу только внутри + `workflow.agent()`. Маршрутов в этом окружении два: + `deepseek-official/deepseek-flash` и `deepseek-official/deepseek-v4-pro`. + +Без этих двух фактов любая инструкция SDD «укажи модель в dispatch» невыполнима +и превращается в фикцию. + +## What Changes + +- **Новый DSH-skill `dsh/skills/sdd/SKILL.md`** — инструкция исполнения плана + в DSH: два режима контроллера (главная сессия и фоновый сабагент), протокол + dispatch/wait/report, ревью задачи, fix-loop, ledger `## Findings`, рулинги, + финальное ревью ветки, отличие от Claude-SDD одной таблицей. + Ставится `dsh/install.sh --skills` в `~/.dsh/skills`; Claude Code его не + получает — харнес Claude не меняется. +- **`dsh/subagent-models.yml`** — opt-in overlay профиля: `modelSelectionSettings` + для `tool-subagent` и `tool-subagent-fork` плюс `subagent.maxDepth: 2`. + В бандл не входит: строка `subagent-model-selection-settings` есть в + web/desktop-профиле и отсутствует в headless, и включённый флаг уронил бы + headless на загрузке. +- **`dsh/PORT.md`** — раздел о включении выбора модели и глубины, ссылка на + overlay, снятие пункта 4 из «Next phases» после приёмки. +- **`dsh/tests/sdd-skill.test.mjs`** — проверки, которые идут без DSH runtime: + frontmatter skill, оба режима, имена инструментов, требование маршрута + модели, отсутствие ссылок на несуществующие средства (`job_output` как + ожидание сабагента, `maxDepth` без оговорки). +- **Пробный прогон** в temp-репозитории: план из 3 задач, implementer → + reviewer → fix → финальное ревью; транскрипт и ledger — в отчёте issue. + Прогон доказывает семантику, а не заменяет тесты: без DSH runtime его не + повторить, поэтому он делается один раз и результаты фиксируются в + `design.md` и в комментарии к #41. + +## Impact + +- Claude-harness не меняется: `roles/`, `hooks/`, `global/`, `install.sh`, + `agents/` остаются как есть. +- Бандл не меняет состав строк профиля; новое поведение — только по явному + решению владельца через overlay. +- Роль dev после приёмки должна ссылаться на новый skill для DSH-сессий + (одна строка; правится в `~/.dsh/roles`, не в общем `roles/dev.md`). + +## Acceptance + +Из #41, без изменений: три задачи не теряются, отчёты собираются, ревьюер +находит и проверяет хотя бы один дефект, fix-loop завершается, ledger содержит +`## Findings` со статусами, прогон тестов зелёный, отличие от Claude-SDD +указано явно. diff --git a/openspec/changes/dsh-sdd/specs/dsh-sdd/spec.md b/openspec/changes/dsh-sdd/specs/dsh-sdd/spec.md new file mode 100644 index 0000000..e7461e4 --- /dev/null +++ b/openspec/changes/dsh-sdd/specs/dsh-sdd/spec.md @@ -0,0 +1,105 @@ +# Spec Delta: dsh-sdd + +## Purpose + +Исполнение плана субагентами в DeepSeek Harness (SDD). Контроллер диспатчит +implementer'а на задачу плана, получает отчёт, отправляет задачу на ревью +и ведёт fix-loop до чистоты, затем заказывает финальное ревью ветки. DSH не +имеет синхронного `Task`, поэтому протокол строится на асинхронном `subagent` +(идентификатор, уведомление, `send_message`) и на ledger как единственной +памяти между ходами. + +## ADDED Requirements + +### Requirement: Режим контроллера выбирается по контексту +Skill SHALL предлагать два режима и MUST выбирать между ними по числу +параллельных планов, а не по умолчанию. + +- Один план в сессии — контроллер главная сессия; implementer'ы и ревьюеры + диспатчатся на глубину 1, что укладывается в `subagent.maxDepth` по + умолчанию. +- Несколько задач, каждая по SDD, — контроллер фоновый сабагент на план, + глубина 2. + +Skill MUST проверить доступную глубину до первого диспатча и MUST записать +рулинг с откатом в режим главной сессии, если глубина меньше нужной. + +#### Scenario: Одна сложная задача +- **WHEN** в сессии один план и он архитектурный +- **THEN** контроллером остаётся главная сессия, а субагенты вызываются с + глубины 1 + +#### Scenario: Глубина не поднята +- **WHEN** выбрано несколько параллельных планов, а `subagent.maxDepth` равен 1 +- **THEN** skill не диспатчит контроллера, фиксирует рулинг об откате в режим + главной сессии и продолжает исполнение в нём + +### Requirement: Асинхронный протокол диспатча и отчёта +Диспатч implementer'а SHALL передавать требования файлом брифа, а результат +MUST возвращаться файлом отчёта; в контекст контроллера возвращается только +статус, коммиты, одна строка сводки тестов и concerns. Контракт статусов: +`DONE`, `DONE_WITH_CONCERNS`, `NEEDS_CONTEXT`, `BLOCKED`. + +#### Scenario: Отчёт файлом +- **WHEN** implementer завершил задачу +- **THEN** полный отчёт лежит в файле отчёта, а в ledger и контекст попали + только статус, коммиты и строка тестов + +### Requirement: Ожидание без блокировки +Skill MUST NOT ждать ребёнка синхронно: в DSH такого средства нет. Пока +у контроллера есть локальная работа, он MUST продолжать её; когда работы нет, +он MUST закончить ход и продолжить по уведомлению о завершении. Перед каждым +следующим диспатчем контроллер MUST сверить живых детей через `list_agents`, +чтобы поймать завершившегося без отчёта. + +#### Scenario: Ребёнок завершился без отчёта +- **WHEN** уведомление о завершении не пришло, а `list_agents` показывает + неактивного ребёнка +- **THEN** контроллер считает задачу завершённой по git-состоянию и ledger, + а не перезапускает её + +### Requirement: Ревью задачи и fix-loop +Каждая задача MUST проходить ревью по спеке и по качеству; implementer self-review +его не заменяет. Fix-loop MUST длиться не более 5 раундов: раунды 1–3 — тот же +implementer через `send_message`, раунды 4–5 — свежий implementer на тир выше. +После пятого раунда контроллер MUST адъюдицировать каждую открытую находку. + +#### Scenario: Дефект найден и закрыт +- **WHEN** ревьюер задачи вернул находку по существу +- **THEN** раунд фикса уходит тому же implementer'у, ре-ревью ограничено + исправлением, находка получает статус `fixed ` + +### Requirement: Ledger и маркировка находок +Своя рабочая директория плана SHALL содержать `progress.md` с первой строкой — +путём плана. Ledger MUST содержать таблицу сканирования плана, рулинги +`R-n (design #n)` и раздел `## Findings`, где у каждой находки есть маркер +источника (`T.`, `C-n`/`I-n`/`M-n`) и статус `fixed `, +`deferred` или `rejected <причина>`. + +#### Scenario: Находка без статуса +- **WHEN** финальное ревью ветки вернуло находку, а исполнение остановлено +- **THEN** отчёт контроллера обязан показать её со статусом; находка без + статуса считается ошибкой контроллера + +### Requirement: Тира моделей и деградация +Skill MUST называть маршруты моделей явно при каждом диспатче, если выбор +модели доступен, и MUST NOT выдавать это за гарантию: у `subagent` параметры +`provider`/`model` появляются только после включения выбора модели в профиле. +Без включённого выбора модели skill MUST исполнять всё на модели сессии и +указывать это в отчёте. + +#### Scenario: Выбор модели выключен +- **WHEN** профиль не включает выбор модели для `subagent` +- **THEN** все implementer'ы и ревьюеры идут на модели сессии, а отчёт + фиксирует отсутствие тиров как наблюдение, а не как выполненное требование + +### Requirement: Отличие от Claude-SDD зафиксировано +Skill SHALL содержать таблицу отличий от `subagent-driven-development` Claude +Code: синхронный `Task` против асинхронного `subagent`, наличие `send_message`, +глубина по умолчанию, выбор модели, отсутствие уведомления как штатного +ожидания. Skill MUST NOT утверждать паритет с Claude-SDD. + +#### Scenario: Чтение skill перед первым диспатчем +- **WHEN** модель загрузила skill и читает таблицу отличий +- **THEN** из неё видно, что ожидание строится на завершении хода и + уведомлении, а не на возврате значения инструмента