DSH: harness-check + role-hint через pre-step, follow-ups #62 (#43) #79

Merged
aep merged 18 commits from feat/43-dsh-prestep into main 2026-10-25 12:54:36 +03:00
3 changed files with 135 additions and 0 deletions
Showing only changes of commit 0d5d621fdc - Show all commits

View File

@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-10-25

View File

@ -0,0 +1,73 @@
# Design: dsh-prestep — harness-check и role-hint через agent/pre-step
Issue: #43 (+#62). Статус: черновик до builder-check; утверждение —
`/approve dsh-prestep design`.
## Контекст
CC-хуки harness-check/role-hint — SessionStart; в DSH аналог — инъекции
`agent/pre-step` (уже используем для superpowers-bootstrap). Гейты #59
живые: этот change идёт первым по гейтованному циклу (acceptance #59).
## Механика
Обе инъекции — раз за сессию, с маркером `<-- DSH-HARNESS-PRESTEP:...>`
и тем же механизмом видимости, что у bootstrap (`isBootstrapVisible`
переименован в общий `isInjectionVisible(agent, messages, marker)`).
Порядок в pre-step: другие инъекции → harness-check → role-hint (обе
неблокирующие; reject/abort — пропуск; сабагенты — пропуск, как
bootstrap).
### harness-check
- Сигнал подключения: `CLAUDE.md` или `AGENTS.md` в корне cwd содержит
`OpenSpec и superpowers` ИЛИ существует `openspec/` ИЛИ
`.claude/code-paths` ИЛИ `CLAUDE.harness-section.md`. Нет — инъекция:
«[claude-harness] Проект не подключён к обвязке: предложи владельцу
`adopt-project.sh` или спроси, нужна ли обвязка». Не блокирует.
- cwd — `sessionCwd` (та же резолюция, что у гейтов: workingDirectory →
process.cwd()).
### role-hint
- Триггер: первое пользовательское сообщение сессии (в `decision.messages`
ищем message с `source.kind === 'user'` и текстом; до первого такого —
инъекции нет).
- Ключевые слова (порядок приоритета, как в AGENTS.md):
- admin: `jira`, `грант`, `гант`, `спринт`;
- qa: `стенд`, `прогон`, `скриншот`, `макет`;
- analyst: `тз`, `oq`, `спека`, `методика`;
- dev: `срез`, `issue`, `pr`, `тест`, `миграция`.
Совпадение — инъекция `[claude-harness] Роль сессии: <r>. Вызови
skill role. Если не так — скажи.` Нет — инъекция вопроса с четырьмя
вариантами (текст — как в AGENTS.md).
- Матчинг: нижний регистр, подстроки по границам слов (русские слова —
подстрока в нижнем регистре; `pr` — только как отдельное слово).
## Decisions made without discussion
| # | Решение | Обоснование | Цена ошибки |
|---|---|---|---|
| D-1 | Роль определяется по первому сообщению (не по заголовку — его в DSH нет) | Ровно то правило AGENTS.md, которое модель сейчас исполняет «по памяти»; переносим в технику | Ложная подсказка роли при неоднозначном сообщении — поправима (`/role`), не блокирует |
| D-2 | harness-check — только подсказка, без HARNESS_AUTO_ADOPT | YAGNI; авто-подключение — отдельная фича при запросе | Сессия в неподключённом проекте продолжает работу — как и сейчас |
| D-3 | Общий хелпер инъекций (рефакторинг bootstrap) без изменения поведения bootstrap | Два новых pre-step не должны дублировать маркер/дедуп | Регрессия bootstrap — страхуется существующими тестами bootstrap |
| D-4 | #62-пункты едут задачами этого change (не отдельными фичами) | Мелкие, один PR-цикл дешевле трёх | Смешивание тем в одном PR — компенсируется отдельными задачами плана |
| D-5 | Конфиг-ключи harnessCheck/roleHint — по умолчанию true, гейтятся bootstrapOk (нужен ctx.on) | Симметрия с bootstrap; без pre-step обе инъекции невозможны | Нет |
## Тесты (идеи для плана)
- pure: detectAdoption(files), detectRole(firstUserText) → role|null,
buildRoleHintText(role), buildHarnessCheckText(), маркер-дедуп;
- wiring: apply с fake ctx — инъекции появляются при наличии
пользовательского сообщения, один раз, пропускаются для сабагентов;
- T2.1: негативный тест openspec — PATH-изоляция (временный каталог без
openspec-бинарника);
- O-2: install.sh WARN при DSH_HOME→существующий каталог + нестандартный
HOME (тест в install.test.mjs);
- T3.4: пин текста в sdd-скилле («шаг „тест падает“ обязателен»).
## На потом (в план)
- Разбивка: Task 1 prestep.js (harness-check+role-hint pure) → Task 2
wiring+bootstrap-рефакторинг → Task 3 #62 (T2.1/O-2/T3.4) → Task 4
спека-дельта `session-prestep` + доки.

View File

@ -0,0 +1,60 @@
# Proposal: dsh-prestep — harness-check и role-hint через agent/pre-step
Issue: #43 (+#62 follow-ups). Источники: роадмап #48 (закрыт), дизайн #69,
AGENTS.md (правило первого сообщения), архив #42 (§6 приёмка).
## Why
У Claude Code два SessionStart-хука: `harness-check.sh` (проект не подключён
→ предложить adopt) и `role-hint.sh` (подсказка роли по заголовку сессии).
В DSH их нет (#43): сессия в неподключённом проекте молча работает без
обвязки, а выбор роли держится только на дисциплине модели (первое правило
AGENTS.md). Плюс три мелких follow-ups из #42 (#62: T2.1 — PATH в негативном
тесте, T3.4 — TDD-порядок в брифах, O-2 — изоляция HOME/DSH_HOME в брифах).
## What Changes
1. **harness-check как pre-step**: один раз за сессию (маркер-дедуп, как у
bootstrap) проверяем, что проект подключён (в `CLAUDE.md`/`AGENTS.md`
корня cwd есть секция обвязки «OpenSpec и superpowers» или файлы
`openspec/`/`.claude/code-paths`); нет — неблокирующая инъекция:
«проект не подключён к обвязке; предложи `adopt-project.sh` или спроси
владельца». Конфиг `harnessCheck: true`.
2. **role-hint как pre-step**: на первом пользовательском сообщении —
ключевые слова из AGENTS.md (Jira/Гант/спринт → admin; стенд/прогон/
скриншот/макет → qa; ТЗ/OQ/спека/методика → analyst; срез/issue/PR/
тест/миграция → dev) → инъекция `[claude-harness] Роль сессии: <r>` с
указанием вызвать `skill role`; нет совпадения — инъекция вопроса с
четырьмя вариантами. Один раз за сессию. Конфиг `roleHint: true`.
Заголовка сессии в DSH нет — сигнал берём из первого сообщения
(ровно то правило, что уже написано в AGENTS.md).
3. **Follow-ups #62** (задачами этого же change):
- T2.1/M-2: негативный тест `--check` без openspec — изоляция PATH
вместо фиксированного `bin:/usr/bin:…`;
- T3.4: sdd-skill и шаблоны брифов — «шаг „тест падает“ обязателен до
кода» формулируется жёстче;
- O-2: брифы/рецепты изолируют и HOME, и DSH_HOME; `install.sh`
предупреждает, когда DSH_HOME указывает на существующий каталог при
нестандартном HOME.
4. Обе инъекции используют общую маркер/видимость-машинерию bootstrap
(выносим хелперы, поведение bootstrap не меняется).
## Impact
- Affected: `dsh/bundle/lib/prestep.js` (новое), `dsh/bundle/lib/bootstrap.js`
(рефакторинг хелперов), `dsh/bundle/index.js` (wiring, аддитивно),
`dsh/skills/sdd/SKILL.md`, `dsh/install.sh` (WARN O-2),
`dsh/tests/openspec.test.mjs` (T2.1), тесты prestep, спека-дельта
(capability `session-prestep`), README/PORT.
- Не трогаем: CC-сторону (хуки harness-check.sh/role-hint.sh остаются),
гейты, bootstrap-инъекцию.
- Breaking: нет (обе инъекции — неблокирующие; конфиг отключает).
## Non-goals
HARNESS_AUTO_ADOPT (авто-подключение) — потом, при запросе; портирование
`briefing` (#45) — отдельно; анализ заголовка сессии (в DSH его нет).
## Открытые вопросы
Нет — решения в design.md; владелец утверждает через `/approve dsh-prestep design`.