Andrey Epifancev ca3814f62a docs(openspec): результаты приёмки DSH-цикла (#42)
Co-Authored-By: DeepSeek Harness <noreply@deepseek.com>
2026-10-24 19:43:30 +04:00

138 lines
10 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.

# Design: OpenSpec в DSH
Issue: #42. Спека: `openspec/changes/dsh-openspec/specs/dsh-openspec/spec.md`.
Спайк: 24.10.2026, temp-проект `/tmp/openspec-spike-dPkz`, openspec 1.13.1.
## 1. Что показал спайк
| Проверка | Результат |
|---|---|
| `openspec init --tools agents` в пустом git-проекте | 6 скиллов в `.agents/skills/`, `openspec/config.yaml`, `openspec/{specs,changes/archive}`; AGENTS.md не создаётся |
| Команды | `Commands skipped for: agents (no adapter)` — слэш-команд адаптер не ставит |
| `--tools claude`, затем `--tools agents` | `.claude/skills` и `.claude/commands/opsx` остаются нетронутыми, `.agents/skills` добавляется рядом |
| Отличие agents-скиллов от claude-скиллов | одна строка подсказки (`/opsx:apply` → `/openspec-apply-change`) и `allowed-tools: Bash(openspec:*)` в frontmatter |
| `openspec new change` → `instructions` → `validate --strict` → `archive -y` | весь цикл без интерактивных вопросов; спека `probe` создалась, change ушёл в `openspec/changes/archive/2026-10-24-spike-test/` |
| `openspec change new` | команды нет; группа `new` скрыта из верхнего `--help`, но `openspec new change <name>` работает |
| DSH видит `.agents/skills` | да: сабагент, запущенный с cwd в worktree после `openspec init --tools agents`, получил в каталоге скиллов все шесть `openspec-*` |
Последняя строка — главная: проектный корень скиллов DSH действительно читает
`.agents/skills`, поэтому отдельный слой совместимости не нужен.
## 2. Решения
### R-1 (решение владельца). Скиллы живут в проекте, не глобально
`openspec init --tools agents` пишет `.agents/skills` в проект; в `~/.dsh/skills`
копии нет. Обоснование:
- версия скиллов совпадает с версией CLI проекта, `openspec update` их обновляет;
- глобальная копия стареет молча и не знает про `--store` и профили конкретного
проекта;
- если проект сделал init сам, глобальная копия даёт два скилла с одним именем;
поведение DSH при дублях не проверено, и проверять его незачем.
Цена: новый проект нужно один раз подключить (`--openspec` или `openspec init`).
Это осознанно: OpenSpec — свойство проекта, а не машины.
### R-2 (решение владельца). Слэш-команды нет
Вход — model-invocable скиллы: их `description` содержит «openspec propose»,
«openspec archive» и т.п., поэтому фраза владельца запускает воркфлоу без
команды. `/role` остаётся единственной командой бандла. Цена: в DSH нет
аналога `/opsx:*`, набирать команды вручную нельзя — только просить модель.
Это укладывается в то, как DSH уже работает с ролями.
### R-3. `--openspec` не создаёт OpenSpec-корень
Флаг добавляет agents-адаптер к проекту, который уже использует OpenSpec: если
`openspec/` нет, скрипт отказывается и печатает готовую команду. Иначе
`--openspec` в чужом каталоге молча завёл бы `openspec/`, `config.yaml` и
changes-каталог — побочный эффект, который не читается из названия флага.
### R-4. `--check` предупреждает, а не падает
Отсутствие `openspec` в PATH — `WARN`: guard, bootstrap, роли и SDD от него не
зависят. Код возврата `--check` меняют только `FAIL`-пункты (python3, git,
node, хуки, бандл).
### R-5. Проверка «DSH видит скиллы» — живая, не в тестах
Юнит-тест может проверить наличие и frontmatter файлов, но не то, что DSH
подхватил каталог. Поэтому в тестах — файлы и поведение `install.sh`, а
видимость проверяется один раз живой сессией (сабагент с cwd в проекте) и
фиксируется здесь.
## 3. Отличия от Claude Code
| Что | Claude Code | DSH |
|---|---|---|
| Куда ставит `openspec init` | `.claude/skills` + `.claude/commands/opsx/*` | `.agents/skills`, без команд |
| Вход | `/opsx:propose`, `/opsx:apply`, … | скиллы по имени/фразе; команды нет |
| Обновление | `openspec update` | `openspec update`, тот же генератор |
| Глобальная копия | нет | нет (R-1) |
Обе копии в одном репозитории — не дублирование ради дублирования: это два
клиента одного генератора. Расхождение ловится повторным `openspec init` /
`openspec update`, а не ручной синхронизацией.
## 4. Решения, принятые без обсуждения
- **2026-10-24. Скиллы `.agents/skills` коммитятся в репозиторий обвязки.**
Обвязка сама ведёт спеки через OpenSpec, а dogfooding — единственный способ
держать слой проверенным. Обоснование: если скиллы не закоммичены, первый же
DSH-прогон в этом репозитории их не увидит. Цена ошибки: лишние 6 каталогов
в диффе при обновлении openspec; лечится `openspec update` и отдельным
коммитом.
- **2026-10-24. `.openspec-target` (`agents`) коммитится вместе со скиллами.**
Это маркер адаптера, который пишет генератор; без него `openspec update` не
знает, какой адаптер обновлять. Цена ошибки: одна строка в диффе.
- **2026-10-24. Тест `--openspec` подставляет фейковый бинарь `openspec` в PATH.**
Тесты DSH-порта идут без внешних CLI (см. `dsh/tests/run.sh`); живой openspec
в тесте сделал бы набор зависимым от машины. Цена ошибки: тест не проверяет
настоящий генератор — это делает живая приёмка.
- **2026-10-24. Проверка скиллов в `--check` смотрит репозиторий обвязки
(`$ROOT`), а не cwd.** `install.sh` — скрипт установки обвязки, его `--check`
отвечает за состояние обвязки; проект проверяется флагом `--openspec`.
Цена ошибки: из чужого проекта `--check` покажет `WARN` о скиллах обвязки —
сообщение говорит, что делать.
## 5. Риски
- **Версия скиллов против CLI.** Скиллы генерирует CLI; если проект обновит
`openspec` и не выполнит `openspec update`, скиллы отстанут от CLI. `--check`
сравнивать версии не будет: он не знает, какой CLI у проекта. Признак —
`metadata.generatedBy` во frontmatter.
- **`.claude/commands/opsx` в DSH не работают** и остаются в репозитории для
Claude Code. Это не мёртвый груз, а второй клиент; в PORT.md написано явно.
- **DSH при дублях скиллов.** Не проверено и не проверяется, потому что
глобальной копии нет (R-1). Если кто-то поставит `openspec init --tools agents`
при уже скопированных вручную скиллах, поведение определит DSH.
- **`openspec init` пишет в проект.** Флаг `--openspec` запускается только по
явной команде и только при существующем `openspec/`; `adopt-project.sh` и
`new-project.sh` его не вызывают.
## 6. Приёмка
- `openspec validate dsh-openspec --strict` — change валиден.
- `bash dsh/tests/run.sh` — зелёный, включая новый `openspec.test.mjs`.
- Живая проверка DSH: сессия/сабагент с cwd в проекте после `openspec init
--tools agents` видит шесть `openspec-*` в каталоге скиллов; полный цикл
`new change → validate --strict → archive -y` проходит без Claude Code
(спайк 24.10.2026, транскрипт — в отчёте задачи).
- `/role` и bootstrap не изменились: тесты `role-skill.test.mjs`,
`bootstrap.test.mjs` и `sdd-skill.test.mjs` зелёные.
### Приёмка: прогон 24.10.2026
- CLI: openspec 1.13.1, temp-проект `/tmp/dsh-openspec-accept`, ветка `feat/probe`.
- `openspec init --tools agents`: шесть скиллов в `.agents/skills`; повторный
прогон идемпотентен, файлы не задвоились.
- `openspec new change probe` → `status` → `instructions proposal` → написаны
`proposal.md` и дельта `specs/probe/spec.md`.
- `openspec validate probe --strict` → `Change 'probe' is valid`.
- `openspec archive probe -y` → `Specs updated successfully.` / `Change 'probe'
archived as '2026-10-24-probe'.`, основная спека
`openspec/specs/probe/spec.md` создана.
- Видимость скиллов в DSH-сессии проверяет контроллер отдельным сабагентом;
результат дописывается сюда после прогона.