claude-harness/docs/superpowers/plans/2026-10-24-dsh-sdd.md
Andrey Epifancev c8b92fae01 docs(dsh): пробный прогон SDD — режимы, дефект и fix-loop (#41)
Три задачи в temp-репозитории: implementer'ы deepseek-flash, все ревью
deepseek-v4-pro. Ревьюер Task 2 независимо нашёл T2.1 (медиана чётной длины
противоречит спеке) и T2.2 (нет теста), fix-раунд 1 → 186575c, скоуп-ре-ревью
APPROVED, финальное ревью ветки APPROVED. Режим 2 (фоновый контроллер, глубина
2) проверен отдельной пробой: вызов subagent из контроллера прошёл.

Артефакты прогона — openspec/changes/dsh-sdd/trial/ (план, спека, брифы,
отчёты, ledger), результаты — design.md. По урокам прогона skill sdd уточнён:
DONE_WITH_CONCERNS при замеченном расхождении, число тестов в плане — ориентир,
повтор при ошибке валидации provider/model.

Co-Authored-By: DeepSeek Harness <noreply@deepseek.com>
2026-10-24 17:49:38 +04:00

242 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# DSH-native SDD — Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Дать DSH-сессии инструкцию исполнения плана субагентами (асинхронный `subagent`, ledger, ревью, fix-loop) и opt-in overlay профиля с глубиной 2 и двумя маршрутами моделей; доказать семантику пробным прогоном из 3 задач.
**Architecture:** Три слоя. (1) `dsh/subagent-models.yml` — overlay, который владелец копирует в `cordis.patch.yml` профиля: включает `subagent-model-selection-settings` (маршруты `deepseek-flash` / `deepseek-v4-pro`) и `subagent.maxDepth: 2`; в бандл не входит, иначе падает headless. (2) `dsh/skills/sdd/SKILL.md` — DSH-семантика исполнения плана: два режима контроллера, протокол ожидания через завершение хода и уведомление, ревью задачи, fix-loop, ledger `## Findings`. (3) Пробный прогон в temp-репозитории: контроллер — главная сессия, implementer (flash) → reviewer (v4-pro) → fix через `send_message` → финальное ревью (v4-pro); отдельной пробой проверяется режим 2 (фоновый контроллер, глубина 2).
**Tech Stack:** bash, python3 stdlib, Node test runner (`node --test`), markdown, DSH 0.2.1-rc.3 (Cordis bundle, `subagent`, `send_message`, `list_agents`), Gitea CLI `tea`.
**Spec:** `openspec/changes/dsh-sdd/` — `proposal.md`, `design.md` (источник решений), `specs/dsh-sdd/spec.md` (требования и сценарии).
**Ветка:** `feat/41-dsh-sdd-spike`, issue #41, worktree `.claude/worktrees/sdd-spike`.
## Global Constraints
- DSH 0.2.1-rc.3; версия плагинного API не заморожена, после апгрейда тесты прогоняются заново.
- Бандл импортирует только Node builtins и локальные файлы (`dsh/tests/package.test.mjs` это проверяет): никаких `@deepseek-ai/*` импортов.
- `subagent-model-selection-settings` нельзя ставить в `dsh/bundle/cordis.patch.yml`: строки нет в headless-профиле, включённый флаг роняет загрузку. Только overlay профиля.
- Skill `sdd` ставится только в `~/.dsh/skills` через `bash dsh/install.sh --skills`. Claude Code его не получает: `roles/`, `hooks/`, `global/`, `install.sh` (корневой), `agents/` не меняются.
- Тесты идут без DSH runtime: `bash dsh/tests/run.sh` и `bash tests/run.sh` (630/630 на момент дизайна) — зелёными должны быть оба набора.
- Документация и тексты — по-русски, формат планов/ledger — как в этом репозитории.
- Коммиты — с trailer `Co-Authored-By: DeepSeek Harness <noreply@deepseek.com>`, force-push запрещён.
- Маркировка: находки ревью `T<n>.<k>` / `C-n` / `I-n` / `M-n`, рулинги `R-n (design #n)`, наблюдения `O-n`, замечания человека `H-n`; у каждой находки статус `fixed <commit>` / `deferred` / `rejected <причина>`.
## Review Focus
- Overlay копируют в headless-профиль → загрузка падает на «requires … in the Host scope»; overlay и PORT.md обязаны это сказать явно, а не только в design.md.
- Skill прочитан в сессии без model selection → диспатч с `provider`/`model` молча игнорируется или падает; skill обязан деградировать на модель сессии и записать это наблюдением, а не выдавать за выполненное требование.
- Ожидание описано как `job_output`/поллинг или как возврат значения `subagent` → инструкция врёт о платформе; ожидание — только конец хода + уведомление + `list_agents`.
- Фоновый контроллер при `maxDepth: 1` → `subagent depth 2 exceeds maxDepth 1`; skill обязан проверить глубину до диспатча и откатиться в режим 1 с рулингом.
- Ledger без `## Findings`/статусов или находка без маркера → отчёт контроллера считается ошибочным; тест skill обязан требовать разделы, а пробный прогон — показать заполненный ledger.
- `install.sh --skills` с новым skill ломает счётчик «copied 1 local skills» в `dsh/tests/install.test.mjs` → счётчик и проверка наличия `sdd` обновляются в той же задаче.
---
### Task 1: Overlay профиля и статическая проверка глубины
**Files:**
- Create: `dsh/subagent-models.yml`
- Create: `dsh/tests/subagent-models.test.mjs`
- Modify: `dsh/install.sh` (`check()`, после проверки hook bridge)
- Modify: `dsh/PORT.md` (§5 Configuration — подраздел про overlay и глубину; §7 — риск «Model tiers»; §8 — п. 4)
**Interfaces:**
- Produces: файл `dsh/subagent-models.yml` — YAML-массив из двух записей: `- id: subagent-model-selection-settings` с `config.enabled: true` и `config.allowedModels` из двух пар (`deepseek-official/deepseek-flash`, `deepseek-official/deepseek-v4-pro`), затем `- id: subagent` с `config.maxDepth: 2`.
- Produces: строки вывода `check()`: `ok: subagent overlay (<путь>)` или `WARN: subagent overlay missing …`; `ok: subagent maxDepth=2 (<файл>)` или `WARN: subagent maxDepth is not 2 in any profile patch; SDD mode 2 is unavailable`.
- Consumes: ничего из других задач.
- [x] **Step 1: Написать падающий тест** `dsh/tests/subagent-models.test.mjs`
```js
import assert from 'node:assert/strict'
import { spawnSync } from 'node:child_process'
import { existsSync, readFileSync } from 'node:fs'
import { dirname, join } from 'node:path'
import test from 'node:test'
import { fileURLToPath } from 'node:url'
import { cleanup, tempDir, write } from './helpers.mjs'
const here = dirname(fileURLToPath(import.meta.url))
const overlay = join(here, '..', 'subagent-models.yml')
const script = join(here, '..', 'install.sh')
test('overlay enables model selection for both routes and depth 2', () => {
assert.ok(existsSync(overlay), 'dsh/subagent-models.yml is missing')
const text = readFileSync(overlay, 'utf8')
assert.match(text, /id: subagent-model-selection-settings/)
assert.match(text, /model: deepseek-flash/)
assert.match(text, /model: deepseek-v4-pro/)
assert.match(text, /id: subagent\n\s+config:\n\s+maxDepth: 2/)
assert.match(text, /headless/)
})
test('install.sh --check reports the overlay and the profile depth', () => {
const home = tempDir()
try {
const dshHome = join(home, '.dsh')
const env = { ...process.env, HOME: home, DSH_HOME: dshHome }
const missing = spawnSync('bash', [script, '--check'], { env, encoding: 'utf8' })
assert.match(missing.stderr, /subagent maxDepth is not 2/)
write(join(dshHome, 'profiles', 'desktop', 'cordis.patch.yml'), '- id: subagent\n config:\n maxDepth: 2\n')
const present = spawnSync('bash', [script, '--check'], { env, encoding: 'utf8' })
assert.match(present.stdout, /ok: subagent overlay/)
assert.match(present.stdout, /ok: subagent maxDepth=2/)
} finally {
cleanup(home)
}
})
```
- [x] **Step 2: Прогнать тест и убедиться, что он падает**
Run: `node --test dsh/tests/subagent-models.test.mjs`
Expected: FAIL — `dsh/subagent-models.yml is missing`.
- [x] **Step 3: Создать `dsh/subagent-models.yml`**
YAML-массив с комментарием-шапкой: overlay для DSH-native SDD (#41); копировать в `$DSH_HOME/profiles/desktop/cordis.patch.yml`, не в бандл, потому что строки `subagent-model-selection-settings` нет в headless; после копирования — рестарт DSH; проверка — `bash dsh/install.sh --check`. Две записи из блока Interfaces, значения — дословно.
- [x] **Step 4: Добавить проверки в `dsh/install.sh`**
В `check()` после блока hook bridge: проверить наличие `$ROOT/dsh/subagent-models.yml`; отдельно — `grep -qs 'maxDepth: 2' "$DSH_HOME"/profiles/*/cordis.patch.yml` (glob не раскрылся — предупреждение, не ошибка; `failed` не поднимать: overlay опционален).
- [x] **Step 5: Обновить `dsh/PORT.md`**
§5: подраздел «Model routes and delegation depth» — как включить (скопировать `dsh/subagent-models.yml` в профиль, рестарт), что даёт (provider/model у `subagent` и `subagent_fork`, глубина 2), чего не делает (не в бандле; без overlay всё идёт на модели сессии).
§7: в пункте «Model tiers» — два маршрута и ссылка на overlay.
§8: п. 4 (SDD spike) получает статус «в работе, change `dsh-sdd`».
- [x] **Step 6: Прогнать тесты**
Run: `node --test dsh/tests/subagent-models.test.mjs`
Expected: PASS (2 tests).
- [x] **Step 7: Прогнать оба набора**
Run: `bash dsh/tests/run.sh && bash tests/run.sh`
Expected: все зелёные (если в worktree падает guard на 5 тестах — проверить `ls -ld dsh/bundle/hooks`, должен быть симлинк `../../hooks`, O-1).
- [x] **Step 8: Коммит**
```bash
git add dsh/subagent-models.yml dsh/tests/subagent-models.test.mjs dsh/install.sh dsh/PORT.md
git commit -m "feat(dsh): overlay профиля — model selection и maxDepth 2 (#41)"
```
---
### Task 2: Skill `sdd` — DSH-семантика исполнения плана
**Files:**
- Create: `dsh/skills/sdd/SKILL.md`
- Create: `dsh/tests/sdd-skill.test.mjs`
- Modify: `dsh/tests/install.test.mjs` (ожидание «copied 2 local skills», проверка `skills/sdd/SKILL.md`)
- Modify: `dsh/README.md` (What works / Not yet / Layout / Known limits)
**Interfaces:**
- Produces: skill с frontmatter `name: sdd` и `description: Use when executing an implementation plan in DeepSeek Harness …`; текст содержит: оба режима, `maxDepth`, инструменты `subagent`/`send_message`/`list_agents`/`interrupt_agent`, статусы `DONE`/`DONE_WITH_CONCERNS`/`NEEDS_CONTEXT`/`BLOCKED`, маршруты `deepseek-official/deepseek-flash` и `deepseek-official/deepseek-v4-pro`, ledger с `## Findings`, таблицу отличий от Claude-SDD.
- Consumes: `dsh/subagent-models.yml` из Task 1 (ссылка в разделе про глубину и модели).
- [x] **Step 1: Написать падающий тест** `dsh/tests/sdd-skill.test.mjs`
Проверки (каждая — отдельный `test`):
1. frontmatter: `/^---\nname: sdd\n/`, `description: .+`;
2. режимы: `/Режим 1/`, `/Режим 2/`, `/maxDepth: 2/` и `/глубин/`;
3. инструменты: `subagent`, `send_message`, `list_agents`, `interrupt_agent`;
4. статусы: `DONE_WITH_CONCERNS`, `NEEDS_CONTEXT`, `BLOCKED`;
5. маршруты: `deepseek-official/deepseek-flash`, `deepseek-official/deepseek-v4-pro`;
6. ledger: `## Findings`, `fixed <commit>`, `T<n>.<k>`;
7. ожидание: `/закончи ход/` и `/уведомлен/`; НЕ содержит `job_output`;
8. отличие: `синхронный` и `асинхронный`, `subagent-driven-development`;
9. деградация: `/модель сессии/`, `/не паритет/` — заголовок таблицы отличий с запретом выдавать за паритет;
10. размер: `Buffer.byteLength(text) < 12288`.
Run: `node --test dsh/tests/sdd-skill.test.mjs` → FAIL (файла нет).
- [x] **Step 2: Написать `dsh/skills/sdd/SKILL.md`**
Разделы: When to use / when not (DSH-сессии; в Claude Code — исходный `subagent-driven-development`); два режима и правило выбора (один план — главная сессия, глубина 1; несколько параллельных планов — фоновый контроллер на план, глубина 2) + проверка глубины до первого диспатча и рулинг об откате; протокол диспатча (бриф файлом, отчёт файлом, контракт статусов, в контекст — только статус, коммиты, одна строка тестов); ожидание (конец хода, уведомление, `list_agents` перед каждым диспатчем, `interrupt_agent` для зависших, запрет `job_output`); ревью задачи (спека + качество) и fix-loop 5 раундов (1–3 — тот же implementer через `send_message`, 4–5 — свежий на тир выше, потом адъюдикация); финальное ревью ветки `C-n`/`I-n`/`M-n`; ledger (первая строка — путь плана, таблица конфликтов, рулинги `R-n (design #n)`, `## Findings` со статусами); маршруты моделей и деградация; таблица отличий от `subagent-driven-development` (синхронный `Task` vs асинхронный `subagent`, `send_message`, глубина по умолчанию, выбор модели, ожидание); запреты (не заявлять паритет, `workflow` — расширение, в первой версии не включать).
- [x] **Step 3: Прогнать тест**
Run: `node --test dsh/tests/sdd-skill.test.mjs` → PASS.
- [x] **Step 4: Обновить `dsh/tests/install.test.mjs`**
`copied 1 local skills` → `copied 2 local skills`; после проверки `role` проверить `join(dshHome, 'skills', 'sdd', 'SKILL.md')` — существует и содержит `name: sdd`.
- [x] **Step 5: Обновить `dsh/README.md`**
What works: SDD-инструкция и overlay. Not yet: убрать SDD, оставить `briefing`, `harness-check`, `role-hint`, `harness-doctor`, auto-memory, caveman. Layout: `skills/sdd/SKILL.md`, `subagent-models.yml`. Known limits: заменить строку про `sonnet`/`haiku`/`opus` ссылкой на overlay.
- [x] **Step 6: Прогнать всё**
Run: `bash dsh/tests/run.sh && bash tests/run.sh` → зелёные.
- [x] **Step 7: Коммит**
```bash
git add dsh/skills/sdd/SKILL.md dsh/tests/sdd-skill.test.mjs dsh/tests/install.test.mjs dsh/README.md
git commit -m "feat(dsh): skill sdd — асинхронный протокол исполнения плана (#41)"
```
---
### Task 3: Пробный прогон 3 задач и запись результатов
**Files:**
- Create: `/tmp/dsh-sdd-trial*` — temp-репозиторий (не входит в PR)
- Modify: `openspec/changes/dsh-sdd/design.md` — раздел «Результаты пробного прогона»
- Modify: `dsh/PORT.md` §8 — п. 4 закрыт ссылкой на прогон
- Modify: этот план — отметить шаги
- Comment: issue #41, затем PR (`tea pulls create`)
**Interfaces:**
- Consumes: skill `sdd` из Task 2, overlay из Task 1 (в профиле уже включён владельцем).
- Produces: транскрипт прогона (диспатчи, статусы, отчёты, ledger) в `design.md`; вывод о режимах 1 и 2.
- [x] **Step 1: Создать temp-репозиторий и план**
`TRIAL="$(mktemp -d)/trial"`; `git init -b main`, коммит `README.md`; `git checkout -b feat/trial`; файл `docs/superpowers/plans/2026-10-24-trial.md` — один план (require-plan разрешает правки), проект: Python-модуль `src/stats.py`. Три задачи: (1) `mean(values)` — float, `ValueError` на пустом списке, готовый код и тест в плане; (2) `median(values)` — по требованиям для чётной длины среднее двух средних; **в плане намеренно оставлен дефект**: `return xs[len(xs) // 2]`, а тест в плане покрывает только нечётную длину (дефект должен найти ревьюер, не тесты); (3) `describe(values)` — dict `{count, mean, median}` через две функции. Тесты — `python3 -m unittest discover -s tests`. Спека прогона — `SPEC.md` в temp-репо: требования к `mean`/`median`/`describe`, включая «чётная длина — среднее двух средних».
- [x] **Step 2: Ledger прогона**
`.superpowers/sdd/trial-plan/progress.md`: первая строка — путь плана; таблица сканирования плана (конфликт: план Task 2 противоречит `SPEC.md` — рулинг `R-1`: следовать `SPEC.md`, дефект фиксировать находкой `T2.1` при ревью, а не править план до диспатча); пустой `## Findings`; три строки `Task N: pending`.
- [x] **Step 3: Диспатч implementer'а Task 1 (режим 1)**
`subagent` c `description` «trial task 1», `cwd` = temp-репо, `provider: deepseek-official`, `model: deepseek-flash`; промпт — brief файлом `briefs/task-1.md` (контекст, требования, точный код, тест, коммит), отчёт — `reports/task-1.md` с первой строкой-статусом; требование: `python3 -m unittest discover -s tests` зелёный, коммит. После вызова — закончить ход; продолжить по уведомлению.
- [x] **Step 4: Собрать отчёт Task 1 и отправить на ревью**
Прочитать `reports/task-1.md`, сверить коммит (`git -C "$TRIAL" log --oneline`) и прогон тестов; `list_agents` — сверка состояния; в ledger `Task 1: complete`. Диффпакет — `review/pkg-task-1.txt` (`git diff main...HEAD`); `subagent` с `model: deepseek-v4-pro`: ревью по `SPEC.md` и по качеству, находки `T1.<k>`, вердикт в `reports/review-1.md`.
- [x] **Step 5: Task 2 — диспатч, ревью, fix-loop**
Так же диспатчить Task 2 (flash, brief с кодом из плана и дефектом). Ревью (v4-pro) должно вернуть `T2.1` — чётная длина медианы. Fix-раунд 1: `send_message` тому же implementer'у с находкой; по уведомлению — тест на чётную длину, фикс, коммит; ре-ревью скопом — новый `subagent` (v4-pro) с пакетом `review/pkg-fix-1.txt`; в ledger `T2.1: fixed <commit>`. Если ревьюер дефект не нашёл — зафиксировать `O-1` (протокол пройден, но приёмка #41 «ревьюер находит дефект» не доказана) и повторить ревью с явным указанием проверять требование «чётная длина».
- [x] **Step 6: Task 3 и финальное ревью ветки**
Task 3 — flash, по плану; ревью — v4-pro; финальное ревью всей ветки — `subagent` v4-pro по полному диффу `main...HEAD`, находки `C-n`/`I-n`/`M-n`; один fix-диспатч при находках, одно скоуп-ревью.
- [x] **Step 7: Проба режима 2 (глубина 2)**
Отдельный temp-репозиторий или новая ветка в том же: `subagent` (flash) с промптом «ты контроллер, задиспатчь implementer'а на задачу X, дождись уведомления, верни отчёт»; контроллер обязан сам вызвать `subagent` и завершиться. Записать: работает / падает `exceeds maxDepth` / уведомление не пришло. При падении — находка `O-n` и вывод, что режим 2 требует поднятой глубины (overlay уже в профиле).
- [x] **Step 8: Записать результаты**
`openspec/changes/dsh-sdd/design.md` — раздел «Результаты пробного прогона 24.10.2026»: таблица приёмки #41 (пункт → чем доказан → статус), реальные диспатчи с моделями, найденный дефект `T2.1` с коммитом фикса, ledger дословно, вывод по режимам, наблюдения `O-n` со статусами. `dsh/PORT.md` §8 п. 4 — закрыт.
- [x] **Step 9: Проверки, коммит, PR**
Run: `bash dsh/tests/run.sh && bash tests/run.sh`; `openspec validate dsh-sdd --strict` (если поддерживается).
Коммит `docs(dsh): пробный прогон SDD — режимы, дефект и fix-loop (#41)`, push, `tea pulls create --base main --head feat/41-dsh-sdd-spike --title "DSH: SDD — skill, overlay, пробный прогон (#41)"`. Комментарий в #41 — состояние фазы и ссылка на PR.
## Acceptance
Из #41: три задачи не теряются (ledger `Task 1..3: complete` + три коммита в temp-репо), отчёты собираются (файлы отчётов + строки ledger), ревьюер находит и проверяет хотя бы один дефект (`T2.1` `fixed <commit>`), fix-loop завершается (ре-ревью чистое), ledger содержит `## Findings` со статусами, прогон тестов зелёный, отличие от Claude-SDD указано таблицей в skill.