From 0006aea56207ad2192c678ced562feabf1a21c45 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Mon, 24 Aug 2026 19:55:28 +0300 Subject: [PATCH] chore: harden SDD governance workflow --- AGENTS.md | 42 +-- README.md | 29 +++ openspec/.cli-version | 1 + .../.openspec.yaml | 8 + .../design.md | 166 ++++++++++++ .../proposal.md | 36 +++ .../specs/audit-remediation-workflow/spec.md | 31 +++ .../engineering-change-governance/spec.md | 67 +++++ .../specs/multi-repository-delivery/spec.md | 61 +++++ .../openspec-authority-and-lifecycle/spec.md | 88 +++++++ .../specs/project-documentation/spec.md | 32 +++ .../specs/project-foundation/spec.md | 36 +++ .../tasks.md | 45 ++++ openspec/config.yaml | 34 ++- .../schemas/wealth-ledger-sdd/schema.yaml | 244 ++++++++++++++++++ .../wealth-ledger-sdd/templates/design.md | 48 ++++ .../wealth-ledger-sdd/templates/proposal.md | 30 +++ .../wealth-ledger-sdd/templates/spec.md | 11 + .../wealth-ledger-sdd/templates/tasks.md | 9 + .../specs/audit-remediation-workflow/spec.md | 20 +- .../engineering-change-governance/spec.md | 69 +++++ .../specs/multi-repository-delivery/spec.md | 63 +++++ .../openspec-authority-and-lifecycle/spec.md | 80 +++++- openspec/specs/project-documentation/spec.md | 24 +- openspec/specs/project-foundation/spec.md | 40 +-- openspec/specs/user-authentication/spec.md | 2 + scripts/verify-openspec-authority.sh | 102 ++++++++ scripts/verify-openspec-authority.test.sh | 94 ++++++- scripts/verify-openspec-version.sh | 29 +++ scripts/verify-workspace-change.sh | 193 ++++++++++++++ 30 files changed, 1659 insertions(+), 75 deletions(-) create mode 100644 README.md create mode 100644 openspec/.cli-version create mode 100644 openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/.openspec.yaml create mode 100644 openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/design.md create mode 100644 openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/proposal.md create mode 100644 openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/audit-remediation-workflow/spec.md create mode 100644 openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/engineering-change-governance/spec.md create mode 100644 openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/multi-repository-delivery/spec.md create mode 100644 openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/openspec-authority-and-lifecycle/spec.md create mode 100644 openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/project-documentation/spec.md create mode 100644 openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/project-foundation/spec.md create mode 100644 openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/tasks.md create mode 100644 openspec/schemas/wealth-ledger-sdd/schema.yaml create mode 100644 openspec/schemas/wealth-ledger-sdd/templates/design.md create mode 100644 openspec/schemas/wealth-ledger-sdd/templates/proposal.md create mode 100644 openspec/schemas/wealth-ledger-sdd/templates/spec.md create mode 100644 openspec/schemas/wealth-ledger-sdd/templates/tasks.md create mode 100644 openspec/specs/engineering-change-governance/spec.md create mode 100644 openspec/specs/multi-repository-delivery/spec.md create mode 100755 scripts/verify-openspec-version.sh create mode 100755 scripts/verify-workspace-change.sh diff --git a/AGENTS.md b/AGENTS.md index c6bdeaa..2d45af7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,24 +1,36 @@ # Specs -## Назначение +## Назначение и authority -Репозиторий единственных versioned SDD-артефактов и canonical OpenSpec store: `wealth-ledger-specs` в `specs/openspec` (относительно workspace). Все функциональные изменения планируются в `openspec/changes//` до реализации в frontend или backend. +Этот репозиторий — единственный versioned SDD authority. Canonical OpenSpec store — `wealth-ledger-specs`, физический root от workspace — `specs/openspec` (локально `openspec`). OpenSpec commands, читающие или изменяющие change, всегда получают `--store wealth-ledger-specs`; nearest-root или default-store fallback запрещён. -## Проверка +Proposal, Delta Specs, Design, Tasks, changes и archives хранятся только в `openspec`. Не создавать versioned planning artifacts вне него, включая `superpowers/plans`; `../references/**` read-only. `docs` хранит as-built state и Completion Evidence, но не копию change artifacts. + +## Workflow и verification + +Поддерживаемая CLI version задана в `openspec/.cli-version`; новые changes используют project-local schema `wealth-ledger-sdd`. Артефакты создаются по одному после approval Change Owner. Общая policy: [`../docs/development/engineering-governance.md`](../docs/development/engineering-governance.md); lifecycle: [`../docs/development/openspec-authority-and-lifecycle.md`](../docs/development/openspec-authority-and-lifecycle.md); audit work: [`../docs/development/audit-remediation.md`](../docs/development/audit-remediation.md). + +Из workspace canonical pre-archive gate: ```bash -openspec validate --type change --store wealth-ledger-specs -openspec instructions apply --change --json --store wealth-ledger-specs -bash scripts/verify-openspec-authority.sh -bash scripts/verify-runtime-openapi.sh +bash specs/scripts/verify-workspace-change.sh ``` -## Границы +Для scoped diagnostics из `specs`: -- Change содержит proposal, design, delta-specs и tasks; требования и задачи живут здесь, не в delivery-plan файле или коде. -- Реализация отмечается в tasks только после выполненной работы. Перед архивированием change проходит `opsx-verify` и получает связанную документацию в `../docs`. -- Не хранить код приложений и долгоживущие ADR в этом репозитории. -- Для фактических границ системы и терминов использовать [`../docs/architecture/system-overview.md`](../docs/architecture/system-overview.md) и [`../docs/architecture/domain-glossary.md`](../docs/architecture/domain-glossary.md). -- Для задачи по Audit ID, продолжения remediation или выбора следующего улучшения сначала прочитать [`../docs/development/audit-remediation.md`](../docs/development/audit-remediation.md); продолжать или создавать change только в store `wealth-ledger-specs`. -- Все OpenSpec commands, читающие или изменяющие change, обязаны указывать `--store wealth-ledger-specs`; nearest-root и global-default selection не поддерживаются. -- Не создавать и не коммитить framework-specific planning/spec/task/design artifacts вне `openspec/` (то есть `specs/openspec` от workspace), включая `superpowers/plans`; `../references/**` остаётся read-only исключением. +```bash +bash scripts/verify-openspec-version.sh +openspec schema validate wealth-ledger-sdd --verbose +openspec validate --type change --strict --store wealth-ledger-specs +openspec validate --specs --strict --store wealth-ledger-specs +bash scripts/verify-openspec-authority.sh +``` + +Structural validation не заменяет semantic verification и independent read-only review. Tasks отмечаются только после выполненной работы; archive не допускает unchecked tasks или verification override. + +## Boundaries + +- Design содержит Delivery Map `frontend`, `backend`, `specs`, `docs` и условный Solution Assessment. +- Specs описывают observable behavior, не изменения кода; Design — architecture, не line-by-line implementation; Tasks — implementation checklist без будущего evidence. +- Не хранить application code и durable ADR в `specs`. +- Для фактической системы и терминов использовать [`../docs/architecture/system-overview.md`](../docs/architecture/system-overview.md) и [`../docs/architecture/domain-glossary.md`](../docs/architecture/domain-glossary.md). diff --git a/README.md b/README.md new file mode 100644 index 0000000..e98427e --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# WealthLedger Specs + +Этот репозиторий — единственный versioned SDD authority рабочей области. Canonical OpenSpec store `wealth-ledger-specs` расположен в `openspec/` (`specs/openspec` от workspace), новые changes используют project-local schema `wealth-ledger-sdd`. + +## Начало работы + +Перед созданием change прочитайте [engineering governance](../docs/development/engineering-governance.md) и [OpenSpec lifecycle](../docs/development/openspec-authority-and-lifecycle.md). Proposal, Delta Specs, Design и Tasks создаются последовательно по одному после approval Change Owner. Для любой команды, читающей или изменяющей change, явно передавайте `--store wealth-ledger-specs`. + +Design должен оценить `frontend`, `backend`, `specs`, `docs` в Delivery Map и при обязательном trigger включить Solution Assessment. Docs описывает as-built state и не становится параллельным store требований. + +## Проверка + +Из workspace под Node 22 выполните: + +```bash +bash specs/scripts/verify-workspace-change.sh +``` + +Для диагностики OpenSpec из этого репозитория: + +```bash +bash scripts/verify-openspec-version.sh +openspec schema validate wealth-ledger-sdd --verbose +openspec validate --type change --strict --store wealth-ledger-specs +openspec validate --specs --strict --store wealth-ledger-specs +bash scripts/verify-openspec-authority.sh +``` + +Structural validation не заменяет semantic verification и independent read-only review перед archive. Audit-derived работа маршрутизируется через [live remediation registry](../docs/development/audit-remediation.md). diff --git a/openspec/.cli-version b/openspec/.cli-version new file mode 100644 index 0000000..81c871d --- /dev/null +++ b/openspec/.cli-version @@ -0,0 +1 @@ +1.10.0 diff --git a/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/.openspec.yaml b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/.openspec.yaml new file mode 100644 index 0000000..545eaec --- /dev/null +++ b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/.openspec.yaml @@ -0,0 +1,8 @@ +schema: spec-driven +created: 2026-08-24 +goal: Make local AI-agent delivery predictable, proportionate, and verifiable across all WealthLedger repositories. +affected_areas: + - frontend + - backend + - specs + - docs diff --git a/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/design.md b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/design.md new file mode 100644 index 0000000..a02a31b --- /dev/null +++ b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/design.md @@ -0,0 +1,166 @@ +## Context + +Мотивация и границы изменения зафиксированы в [proposal.md](proposal.md), а нормативное поведение — в delta specs этого change. + +WealthLedger состоит из четырёх независимых Git-репозиториев (`frontend`, `backend`, `specs`, `docs`); workspace root не является Git-репозиторием. Разработка и проверки выполняются локально, CI отсутствует. Canonical SDD authority уже вынесен в зарегистрированный store `wealth-ledger-specs` с физическим root `specs/openspec`. + +Текущий OpenSpec workflow использует встроенную схему `spec-driven`. Она содержит нужные четыре артефакта, но разрешает Design сразу после Proposal и не задаёт проектную семантику артефактов, Delivery Map, Solution Assessment и последовательные owner checkpoints. OpenSpec CLI обновлён до 1.10.0; версия поддерживает project-local schema fork, `affected_areas`, schema validation и operation guidance. Команда `openspec update` при этом не принимает `--store` и ищет соседний `openspec/`, поэтому её нельзя безопасно запускать из workspace root без staging. Изолированное сравнение также показало, что upstream 1.10 entrypoints возвращают общий выбор store и допускают archive с warnings, тогда как WealthLedger требует fixed store и hard blockers. + +Frontend уже имеет широкий `npm run verify`, но не отклоняет Node 26 до checks и дважды выполняет один набор тестов (`test:run`, затем coverage). Backend имеет отдельные lint/typecheck/test/build commands, но не имеет одного canonical verifier; запуск тестов под Node 26 дал ложные failures, тогда как Node 22.21.0 прошёл 19 suites / 59 tests. Docs не имеет lockfile-backed validator. Текущий remediation registry описывает только аудит 20.08.2026 и ошибочно оставляет trigger-dependent WL-P3-04 в `planned`. + +## Goals / Non-Goals + +**Goals:** + +- использовать native OpenSpec 1.10 extension points как versioned SDD engine WealthLedger; +- сделать artifact graph строго последовательным, сохранив только Proposal, Delta Specs, Design и Tasks; +- хранить policy в одном устойчивом месте, а AGENTS и generated entrypoints оставить компактными routing/enforcement layers; +- дать каждому application repository один canonical local gate и один workspace-level dispatcher для affected areas; +- отклонять неподдерживаемые Node/OpenSpec versions до дорогостоящих или вводящих в заблуждение checks; +- встроить risk-based testing и build-vs-buy decision в обычный SDD flow без новых обязательных артефактов; +- сделать docs-as-code и audit remediation воспроизводимыми без превращения docs в parallel spec store. + +**Non-Goals:** + +- добавление CI/CD, monorepo build system или deployment automation; +- замена текущей auth implementation, выбор auth-платформы или миграция сессий; +- восстановление deferred Prisma e2e до срабатывания его существующего review trigger; +- массовое удаление существующих тестов либо замена frontend bundle/dependency tools; +- новый общий numeric coverage threshold для backend; +- изменение пользовательского поведения или runtime API WealthLedger. + +## Decisions + +### 1. Native custom schema `wealth-ledger-sdd` + +В `specs/openspec/schemas/wealth-ledger-sdd` создаётся минимальный fork встроенной `spec-driven` schema. Он сохраняет четыре привычных artifacts и меняет dependency graph на: + +```text +proposal → specs → design → tasks → apply +``` + +Связи задаются нативными `requires`: `specs` требует `proposal`, `design` требует `specs`, `tasks` требует `design`, а Apply требует `tasks`. `specs/openspec/config.yaml` выбирает `wealth-ledger-sdd` как default для будущих changes. Текущий bootstrap change сохраняет metadata `schema: spec-driven`; это исключает самореферентную миграцию его artifact graph во время выполнения. + +Templates и instructions schema уточняют роли артефактов: + +- Proposal — WHY, scope, intended outcome, non-goals и capabilities; без технологий, API, файлов и зависимостей. +- Delta Specs — WHAT, только observable behavior и invariants. +- Design — HOW крупными архитектурными частями, включая обязательный Delivery Map и условный Solution Assessment. +- Tasks — DO, implementation checklist по affected repositories с точными planned verification actions, но без observed results, commit IDs и archive bookkeeping. + +Дополнительные planning artifacts не вводятся. Completion Evidence остаётся post-implementation записью в durable development documentation. + +OpenSpec 1.10 не моделирует identity человека, утвердившего artifact. Поэтому schema обеспечивает структурный порядок, а owner approval обеспечивается project workflow: agent создаёт только один текущий artifact, показывает его владельцу и останавливается; следующая команда продолжения является допустимой только после явного решения Change Owner. Если новая сессия не может установить факт approval из доступного контекста, она обязана запросить его повторно. Добавление отдельного approval artifact или самописной БД статусов отклонено как несоразмерное усложнение. + +### 2. Version contract и безопасное обновление OpenSpec + +`specs` хранит exact supported OpenSpec CLI version в компактном versioned contract; начальное значение — `1.10.0`. Preflight сравнивает его с `openspec --version` до store operations. Глобальная установка CLI сохраняется: она нужна агентам, работающим из workspace root и независимых repositories; локальная npm-копия OpenSpec не добавляется, поскольку создала бы второй resolution path и не решила бы root integration. + +OpenSpec schema проверяется `openspec schema validate wealth-ledger-sdd` из `specs`, после чего `openspec schema which` должен указывать project-local source. `openspec config.yaml` содержит только schema selection, краткий routing context и additive artifact/operation rules; полные policies в него не копируются. + +Project-owned `.opencode` files в workspace root являются generated local projection, а не SSOT. Обновление до нового upstream выполняется через isolated staging, затем в projection переносятся upstream changes и повторно накладываются минимальные WealthLedger overrides: fixed `wealth-ledger-specs`, one-artifact-at-a-time workflow и hard archive blockers. Authority verifier обязан отклонить projection, если update вернул nearest-root/default-store fallback или permissive archive. Прямой `openspec init` в workspace root запрещён, поскольку создал бы второй planning root. + +### 3. Policy ownership и AGENTS layering + +Устойчивая process policy размещается в одном новом development-документе. Он определяет термины Change Owner, Delivery Map, Completion Evidence и Enforceable Engineering Invariant, risk-based test matrix, build-vs-buy triggers и SSOT boundaries. Архитектурная причина выбора native schema и минимального local orchestration фиксируется отдельным ADR. Existing OpenSpec lifecycle documentation ссылается на policy и описывает фактический workflow, не копируя schema instructions целиком. + +AGENTS строятся слоями: + +- root — workspace map, SSOT, cross-repository lifecycle и общие запреты; +- repository AGENTS — только локальные команды, style/boundary sources и repo-specific constraints; +- подробные архитектура, testing policy и rationale остаются в docs; +- нормативное изменение поведения остаётся в OpenSpec. + +Таким образом изменение policy требует обновить один authoritative документ и необходимые machine gates, а не синхронно переписывать пять больших инструкций. + +### 4. Guardrail matrix и canonical local gates + +Enforceable invariants связываются с существующими или минимально добавляемыми non-mutating gates: + +| Invariant | Authority | Enforcement | +| --- | --- | --- | +| Node runtime | application `engines`/`.nvmrc` | repo-owned preflight до остальных npm stages | +| OpenSpec CLI/schema | version contract и project-local schema | version preflight, schema validate, strict change/spec validation | +| Frontend style and boundaries | frontend conventions and public APIs | TypeScript, Biome, Knip, dependency-cruiser, OpenAPI, bundle/coverage ratchets | +| Backend style and correctness | backend conventions and API boundary | ESLint, app/test TypeScript, Jest, build, hygiene | +| Docs-as-code syntax | docs configuration | calibrated `markdownlint-cli2` plus `git diff --check` | +| Cross-repo API contract | backend runtime OpenAPI and frontend snapshot | existing runtime OpenAPI verifier when both contract sides are affected | +| SDD authority/lifecycle | OpenSpec specs, schema and AGENTS | authority verifier, schema graph, semantic verify and independent review | + +Frontend `verify` начинает с runtime preflight и выполняет Vitest один раз через coverage command; отдельный `test:run` удаляется из composite command, поскольку coverage уже запускает тот же suite. Existing coverage, dependency and bundle negative fixtures сохраняются: они доказывают hard guardrails, а не тестируют тривиальные scripts ради coverage. + +Backend получает один `verify`, объединяющий runtime preflight, hygiene, lint, оба typecheck, Jest и build. Deferred e2e явно не входит в зелёный gate до WL-P2-05 trigger. Coverage command остаётся доступной диагностикой, но numeric threshold не добавляется. + +Docs получает Node 22 lockfile-backed setup и `markdownlint-cli2`. Конфигурация отключает только MD013 line length, поскольку проект осознанно использует длинные audit tables и command evidence; с этим исключением текущий baseline из 31 Markdown files проходит без ошибок. Собственный Markdown linter и Chromium/network-based link checker отклонены как избыточные для текущего локального scope. Cross-repository links проверяются в scoped documentation review до появления совместимого offline workspace-aware готового решения. + +Runtime/version preflight scripts остаются тонкими и не получают unit tests. Их hard-failure behavior подтверждается observed pass на Node 22 и controlled failure на неподдерживаемой версии. Новые постоянные negative fixtures создаются только для guardrail logic с самостоятельным parsing/branching, а не для shell orchestration. + +### 5. Один workspace verifier без monorepo framework + +Non-mutating dispatcher размещается в `specs/scripts`, поскольку `specs` владеет Delivery Map и SDD lifecycle, а workspace root не versioned. Он принимает canonical change, читает `affected_areas`, проверяет наличие решения по всем четырём delivery areas и вызывает только канонические gates affected repositories. `specs` проверяется всегда; runtime OpenAPI comparison добавляется, когда затронуты обе стороны API contract. Ошибка любого child gate сохраняется как общий blocking result без fallback или auto-fix. + +Nx, Turborepo, Bazel, Make/just layer и новый root package отклонены: workspace не имеет единого dependency graph, build cache или CI, а четыре repos уже владеют рабочими commands. Минимальный dispatcher не реализует build logic, а только последовательно делегирует в существующие repo gates. Это намеренно узкий custom seam, для которого готовые monorepo platforms несоразмерны задаче. + +### 6. Delivery Map этого change + +| Area | Status | Архитектурный результат | +| --- | --- | --- | +| frontend | affected | ранний Node preflight, один canonical verify без повторного Vitest run, актуальные agent/onboarding instructions | +| backend | affected | ранний Node preflight, canonical verify без e2e и coverage threshold, актуальные agent/onboarding instructions | +| specs | affected | OpenSpec 1.10 contract, custom schema/config/templates, SDD/workspace verifiers, updated authority projection and synced requirements | +| docs | affected | immutable audit snapshot, единый registry, governance guide, ADR, indexes и calibrated docs-as-code gate | + +### Contract Gate Decision + +| Gate | Status | Reason | +| --- | --- | --- | +| runtime-openapi | required | Меняются contract-verification pipelines обеих сторон: frontend canonical gate проверяет committed snapshot, а backend canonical gate собирает runtime producer. API surface не меняется; task 7.2 подтверждает отсутствие случайного drift при изменении этих gates. | + +Пустые commits не создаются: каждая область имеет самостоятельный versioned результат. Root AGENTS и `.opencode` projection обновляются как local workspace integration и проверяются из `specs`, но не объявляются пятым Git repository. + +### 7. Audit remediation и отдельная auth assessment + +Новый `audit-24-08-2026.md` сохраняет повторный аудит как immutable snapshot. Live registry расширяется на все snapshots, исправляет stale статусы (включая WL-P3-04: `planned` → `deferred` с существующим accessibility trigger), отражает выполненные и оставшиеся gaps и делает `harden-agent-sdd-governance` единственным active remediation change. Известные stale contradictions прежнего аудита и документации исправляются в их authoritative current-state местах без редактирования старых snapshots. + +Ретроспективный выбор auth solution не включается в этот change. После завершения governance отдельный `assess-auth-platform-options` применит новый Solution Assessment к текущей реализации и зрелым вариантам, включая Better Auth, без заранее принятого решения о миграции. + +## Solution Assessment + +### OpenSpec workflow + +Рассмотрены: встроенная `spec-driven` без изменений, native project-local schema fork и отдельный workflow engine/custom generator. Встроенная схема не выражает обязательный `specs → design` edge и не несёт проектной семантики. Внешний engine создал бы второй lifecycle authority и собственный формат. Выбран native fork OpenSpec 1.10: он сохраняет CLI, store, validators и четыре знакомых artifacts, добавляя только проектные dependencies/templates. + +### Multi-repository orchestration + +Рассмотрены: Nx/Turborepo, Make/just и тонкий dispatcher существующих gates. Первые варианты оправданы при общем build graph, cache или CI и добавляют новый control plane для четырёх независимых repos. Выбран thin dispatcher без собственной build/test logic; при появлении CI или существенного параллельного build graph решение должно быть пересмотрено. + +### Docs validation + +Рассмотрены: собственный checker, `markdownlint-cli2`, Remark-based link validation и browser/network link checkers. Выбран lockfile-pinned `markdownlint-cli2`: он поддерживает Node 22, не требует сети во время gate и после единственного осознанного исключения MD013 проходит текущий baseline. Custom checker отклонён. Link validator пока не включается: внешние tools либо требуют browser/network, либо нуждаются в отдельной настройке cross-repository root; добавлять их без подтверждённого recurring failure означало бы создавать новый maintenance surface. + +### Testing policy + +Рассмотрены blanket TDD/coverage для каждого файла и risk-based selection. Blanket policy уже проявилась повторным прогоном frontend tests и стимулирует тесты декларативных scripts/DTO вместо реальных рисков. Выбран risk-based matrix из specs; существующие hard-guardrail fixtures сохраняются, а новые тесты появляются только по risk trigger или самостоятельной logic. + +## Risks / Trade-offs + +- **OpenSpec 1.10 schema graph не хранит identity человеческого approval** → agent workflows останавливаются после одного artifact; при потере контекста approval запрашивается повторно, отдельный approval artifact не вводится. +- **Root `.opencode` projection не versioned, потому что workspace root не Git** → schema/config/AGENTS остаются authoritative, staged update procedure документируется, а versioned authority verifier проверяет локальную projection после каждого update. +- **Exact CLI pin потребует осознанного upgrade change** → version bump объединяется с schema validation и staged integration diff, исключая silent behavior drift. +- **Workspace dispatcher связан с четырьмя repo names и metadata contract** → seam остаётся малым, fail-closed и меняется только через SDD при изменении workspace map. +- **Backend verify не включает e2e** → registry продолжает явно маркировать WL-P2-05 deferred; gate не выдаёт e2e за passing и пересматривается по существующему Prisma trigger. +- **Markdown lint может провоцировать косметические churn** → baseline принимается с MD013 disabled, auto-fix не входит в verification, новые rules добавляются только при доказанной пользе. +- **Внешние и cross-repository Markdown links пока не имеют общего автоматического checker** → affected links проверяются scoped review; новый dependency появляется только после отдельного solution assessment. +- **Больше hard gates увеличит локальное время проверки** → workspace verifier запускает только affected areas, duplicate frontend test run удаляется, а expensive integration gate включается только при соответствующем Delivery Map. + +## Migration Plan + +1. Зафиксировать OpenSpec 1.10.0 contract и добавить preflight, не меняя schema текущего change. +2. Создать native fork `wealth-ledger-sdd`, изменить dependency graph/templates, пройти schema validation и только затем сделать его default в config. +3. Обновить local agent entrypoints через staged 1.10 generation, сохранить fixed-store и hard-archive overlays и доказать authority verifier положительным и representative negative cases. +4. Ввести repo-owned runtime/canonical gates и workspace dispatcher; сначала подтвердить controlled Node mismatch, затем выполнить полные gates под Node 22. +5. Обновить governance docs, ADR, audit snapshot/registry, indexes, AGENTS и onboarding; исправить только подтверждённые stale statements. +6. Выполнить structural validation, все affected repo gates, runtime OpenAPI comparison, semantic verification и independent read-only review. +7. После успешного archive записать Completion Evidence и commits изменённых repositories в live registry; только затем перевести remediation entry в `done`. + +Rollback не требует data migration: default schema возвращается на `spec-driven`, repo verify commands и lockfiles восстанавливаются обычным Git revert, а project-local schema может остаться неактивной до исправления. Global OpenSpec 1.10 сохраняется, поскольку текущий change и store уже успешно читаются этой версией; downgrade выполняется только отдельным подтверждённым compatibility решением. diff --git a/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/proposal.md b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/proposal.md new file mode 100644 index 0000000..bb6f27a --- /dev/null +++ b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/proposal.md @@ -0,0 +1,36 @@ +## Why + +Повторный аудит подтвердил, что отдельные технические улучшения уже работают, но правила разработки для AI-агентов остаются фрагментарными: агент может переусложнить решение, написать несоразмерные тесты, проигнорировать готовое проверенное решение или по-разному трактовать SDD, документацию и завершённость изменения. До продолжения продуктовой разработки WealthLedger нужен единый локально проверяемый контур, который сохраняет стиль проекта, ясный Single Source of Truth и соразмерность инженерных решений без зависимости от CI. + +## What Changes + +- Установить единый жизненный цикл изменения: согласованное намерение, описание наблюдаемого поведения, архитектурное решение, implementation checklist, реализация и проверяемое подтверждение результата. +- Разделить ответственность за артефакты: Change Owner утверждает намерение; продуктовые изменения утверждает Product Owner, а технические и процессные — Engineering Owner. AI-агент может подготовить черновик, но не может считать его утверждённым самостоятельно. +- Закрепить назначение SDD-артефактов: Proposal описывает только намерение и причину; Delta Specs — изменение поведения системы; Design — архитектурный способ реализации крупными частями; Tasks — конкретный checklist реализации. +- Обязать сначала оценивать существующие проверенные решения для областей с высокой стоимостью самописной реализации и создавать собственное решение только при зафиксированной несовместимости подходящих альтернатив. +- Ввести риск-ориентированную политику тестирования: тесты обязательны для поведения с существенным риском, публичных контрактов и регрессий, но не создаются автоматически для простых обёрток, декларативных структур, служебных скриптов и поведения внешних библиотек. +- Сделать локальные инженерные ограничения обязательными и воспроизводимыми, чтобы несоответствие стилю проекта, архитектурным границам, контрактам и критическим инвариантам блокировало завершение работы AI-агента. +- Требовать для каждого versioned change явной оценки четырёх delivery areas — frontend, backend, specs и docs — с обоснованием `N/A` для незатронутых областей и единым доказательством завершения затронутых областей. +- Уточнить границы Single Source of Truth: OpenSpec задаёт нормативные требования и изменения; executable contracts и код отражают исполняемое состояние; docs описывает только фактическое текущее состояние; ADR сохраняет причины устойчивых решений; AGENTS служит краткой навигацией и набором исполнимых ограничений. +- Зафиксировать результаты повторного аудита как неизменяемый снимок и продолжать remediation через единый актуальный реестр с однозначными статусами, следующими действиями и evidence. +- Сделать локальный SDD-процесс воспроизводимым и не допускающим незаметного выбора другого OpenSpec authority или завершения изменения без требуемой семантической проверки. + +## Capabilities + +### New Capabilities + +- `engineering-change-governance`: правила выбора готового решения или собственной реализации, соразмерного тестирования, инженерной простоты и обязательных локальных guardrails для AI-агентов. +- `multi-repository-delivery`: оценка frontend, backend, specs и docs для каждого change, правила `N/A` и проверяемое подтверждение полной поставки по всем затронутым областям. + +### Modified Capabilities + +- `openspec-authority-and-lifecycle`: уточнить роли, назначение и порядок SDD-артефактов, обязательность согласования намерения, каскадную проверку зависимых артефактов и семантическую верификацию перед завершением. +- `project-documentation`: закрепить docs как описание текущего реализованного состояния без дублирования планируемых OpenSpec-требований и связать завершение изменения с durable completion evidence. +- `project-foundation`: усилить единообразные локальные инструкции AI-агентов, навигацию по источникам истины и обязательность проверок стиля и границ каждого репозитория. +- `audit-remediation-workflow`: добавить новый неизменяемый audit snapshot, объединить историю remediation в одном актуальном реестре и нормализовать статусы ранее найденных отклонений. + +## Impact + +Изменение затрагивает инженерный процесс всех четырёх delivery areas WealthLedger и делает правила обязательными одинаково для людей и AI-агентов. После его принятия изменение не считается готовым, пока не соблюдены SDD lifecycle, правила выбора решения и тестов, локальные guardrails, документация фактического состояния и completion evidence для каждой затронутой области. + +Это изменение не вводит CI, не заменяет автоматически существующую авторизацию, не удаляет массово текущие тесты и не меняет пользовательское поведение WealthLedger. Отдельная ретроспективная оценка готовых auth-платформ выполняется последующим change. diff --git a/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/audit-remediation-workflow/spec.md b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/audit-remediation-workflow/spec.md new file mode 100644 index 0000000..2fd518a --- /dev/null +++ b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/audit-remediation-workflow/spec.md @@ -0,0 +1,31 @@ +## MODIFIED Requirements + +### Requirement: Реестр remediation отделён от снимка аудита +Система SHALL создавать отдельный неизменяемый versioned audit snapshot в `docs/audits` для каждого завершённого аудита и SHALL поддерживать один актуальный durable remediation registry в `docs/development`, охватывающий findings всех audit snapshots. Каждый snapshot SHALL оставаться source of facts своего аудита и MUST NOT редактироваться для отражения последующей remediation. Registry SHALL хранить текущее состояние, связанный canonical change, следующее действие и completion evidence каждой записи, MUST ссылаться на однозначный Audit ID и исходный snapshot и MUST NOT дублировать полный текст finding, если он уже содержится в snapshot. + +#### Scenario: Агент открывает работу по аудиту в новой сессии +- **WHEN** агент получает задачу устранить или продолжить finding из любого завершённого аудита +- **THEN** он находит в едином registry исходный snapshot и Audit ID, текущий статус, связанный OpenSpec change, evidence и следующее действие без повторной интерпретации всех аудитов + +#### Scenario: Проводится повторный аудит +- **WHEN** новый аудит завершён после предыдущего audit snapshot +- **THEN** система добавляет новый immutable snapshot и обновляет тот же live registry, не переписывая предыдущий snapshot и не создавая конкурирующий registry + +#### Scenario: Обновляется прогресс remediation +- **WHEN** работа по finding меняет статус +- **THEN** versioned audit snapshots не редактируются, а изменение фиксируется только в live registry с датой и необходимым evidence + +### Requirement: Registry задаёт однозначный статус и следующий change +Каждая audit-derived запись SHALL иметь ровно один статус из `planned`, `active`, `done`, `deferred` или `accepted`. `planned` MUST означать согласованную работу, которую можно начать без внешнего review trigger; запись, ожидающая версии зависимости, внешнего события или отдельного решения владельца, MUST иметь статус `deferred` с условием пересмотра. Registry MUST содержать не более одного `active` remediation change и ровно одну следующую рекомендуемую задачу, пока существуют findings со статусом `planned`. + +#### Scenario: В рабочей области нет активного remediation change +- **WHEN** агент открывает registry и все незакрытые немедленно исполнимые findings имеют статус `planned` +- **THEN** он может выбрать ровно одну строку, отмеченную как следующая рекомендуемая задача, и создать связанный canonical OpenSpec change + +#### Scenario: В рабочей области уже есть активный remediation change +- **WHEN** registry содержит запись со статусом `active` +- **THEN** агент продолжает связанный change и не создаёт второй remediation change без явного решения владельца + +#### Scenario: Finding зависит от будущего trigger +- **WHEN** remediation нельзя обоснованно начать до указанной версии зависимости, внешнего события или решения владельца +- **THEN** registry хранит статус `deferred`, rationale и проверяемое условие пересмотра вместо представления finding как готового `planned` work diff --git a/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/engineering-change-governance/spec.md b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/engineering-change-governance/spec.md new file mode 100644 index 0000000..2985957 --- /dev/null +++ b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/engineering-change-governance/spec.md @@ -0,0 +1,67 @@ +## Purpose + +Определяет соразмерные и проверяемые правила инженерных решений AI-агентов, чтобы WealthLedger переиспользовал зрелые решения, тестировал существенные риски и локально отклонял код, нарушающий инварианты проекта. + +## ADDED Requirements + +### Requirement: Готовые решения оцениваются до собственной реализации + +Изменение, которое вводит или существенно заменяет механизм авторизации, безопасности, хранения данных, внешней интеграции, наблюдаемости, кэширования, конкурентного доступа либо общей инфраструктуры и tooling, MUST до утверждения архитектурного решения оценить существующие поддерживаемые решения. Оценка MUST сравнивать применимые варианты по соответствию требованиям, зрелости, безопасности, эксплуатационной стоимости, ограничениям и стоимости миграции. Собственная реализация SHALL допускаться только когда подходящего готового решения нет либо его существенная несовместимость явно зафиксирована вместе с рисками такого выбора. Для изменений вне перечисленных областей отдельная оценка MUST NOT быть обязательной без конкретного риска или дорогостоящего необратимого решения. + +#### Scenario: Существует совместимое зрелое решение + +- **WHEN** change затрагивает одну из обязательных для оценки областей и найдено поддерживаемое решение, удовлетворяющее требованиям без неприемлемых ограничений +- **THEN** архитектурное решение использует это решение либо явно объясняет, почему его совокупная стоимость или риск выше выбранной альтернативы + +#### Scenario: Подходящего решения нет + +- **WHEN** рассмотренные зрелые решения не выполняют существенные требования или создают неприемлемый риск +- **THEN** собственная реализация допускается только после фиксации проверенных вариантов, конкретных разрывов, принятых рисков и условия повторного пересмотра + +#### Scenario: Изменение не требует solution assessment + +- **WHEN** change не относится к обязательным областям и не содержит отдельного дорогостоящего или необратимого решения +- **THEN** отсутствие формальной оценки готовых решений не блокирует SDD lifecycle и не создаёт дополнительный артефакт ради процесса + +### Requirement: Тестирование определяется риском поведения + +План изменения MUST требовать автоматизированные тесты для security- и privacy-sensitive поведения, денежных расчётов, целостности и миграции данных, конкурентного доступа, публичных контрактов, критических пользовательских сценариев и подтверждённых регрессий. Изменение MUST NOT требовать новый тест только из-за появления или изменения файла. Простые декларативные структуры, DTO без собственной логики, тонкие адаптеры, прямолинейная оркестрация, hygiene scripts и поведение сторонней библиотеки SHALL проверяться существующим контрактным или интеграционным gate без отдельного unit test, если они не содержат самостоятельного ветвления, преобразования, инварианта либо ранее найденной регрессии. Существующий frontend coverage gate SHALL использоваться только как anti-regression constraint, а не как основание создавать малоценные тесты. Backend MUST NOT получать общий числовой coverage threshold только ради симметрии или процессного соответствия; такой gate требует отдельного утверждённого обоснования защищаемого риска. + +#### Scenario: Изменяется критический инвариант + +- **WHEN** change меняет безопасность, денежный результат, целостность данных, конкурентное поведение, публичный контракт, критический journey или исправляет регрессию +- **THEN** checklist содержит тест соответствующего уровня, который наблюдаемо подтверждает новый или исправленный результат + +#### Scenario: Добавлен простой служебный скрипт + +- **WHEN** скрипт только последовательно запускает существующие проверяемые команды, не содержит самостоятельной бизнес-логики, ветвления или преобразования данных +- **THEN** отдельный unit test для скрипта не является обязательным, а корректность результата подтверждается выполнением самого локального gate + +#### Scenario: Coverage можно повысить только малоценным тестом + +- **WHEN** новый тест повторял бы декларативную структуру или внутреннее поведение зависимости и не защищал бы самостоятельный риск проекта +- **THEN** агент не создаёт такой тест только ради процента coverage и сохраняет существующий anti-regression threshold + +#### Scenario: Backend не имеет числового coverage threshold + +- **WHEN** обязательные risk-based тесты backend проходят, а отдельный измеримый риск для общего coverage threshold не утверждён +- **THEN** отсутствие глобального числового threshold не считается пробелом и не блокирует change + +### Requirement: Enforceable Engineering Invariant имеет локальную проверку + +Каждое правило, обозначенное как обязательный Enforceable Engineering Invariant, MUST иметь детерминированную non-mutating локальную проверку и MUST блокировать завершение работы при нарушении. Такие инварианты SHALL охватывать применимые правила стиля проекта, статическую корректность, архитектурные границы, публичные контракты, безопасность и критические доменные ограничения. Рекомендация, которую невозможно надёжно проверить локально, MUST быть обозначена как guidance и MUST NOT выдаваться за hard guardrail. Проверка самого hard guardrail MUST иметь evidence, что она отклоняет хотя бы одно контролируемое репрезентативное нарушение; это evidence MUST NOT превращаться в требование unit-тестировать каждый вспомогательный скрипт. + +#### Scenario: Агент пишет код не в стиле проекта + +- **WHEN** изменение нарушает проверяемое правило форматирования, lint, типов, импортных границ или публичного контракта проекта +- **THEN** обязательный локальный gate завершается с ошибкой и работа не считается завершённой + +#### Scenario: Правило является только рекомендацией + +- **WHEN** команда не может определить детерминированную локальную проверку сформулированного предпочтения +- **THEN** правило документируется как guidance, а агент не использует его как самостоятельную причину объявить корректную реализацию невалидной + +#### Scenario: Добавляется новый hard guardrail + +- **WHEN** change объявляет новое правило блокирующим +- **THEN** completion evidence подтверждает как успешный compliant case, так и обнаружение контролируемого representative violation diff --git a/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/multi-repository-delivery/spec.md b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/multi-repository-delivery/spec.md new file mode 100644 index 0000000..10fad9a --- /dev/null +++ b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/multi-repository-delivery/spec.md @@ -0,0 +1,61 @@ +## Purpose + +Определяет полную поставку одного SDD-изменения через независимые frontend, backend, specs и docs репозитории без потерянных областей, фиктивных коммитов и преждевременного статуса done. + +## ADDED Requirements + +### Requirement: Каждый change содержит полный Delivery Map + +Каждый versioned change MUST оценивать delivery areas `frontend`, `backend`, `specs` и `docs` и для каждой области указывать `affected` либо `N/A` с конкретной причиной. `specs` SHALL быть affected для каждого versioned SDD change. `docs` SHALL быть affected для каждой поставленной пользовательской фичи; для технического или процессного change она MAY быть `N/A` только когда фактическая устойчивая документация не изменяется. `frontend` и `backend` SHALL быть affected только когда меняется их поведение, контракт, реализация или обязательный локальный gate. Пустой коммит MUST NOT использоваться для имитации участия незатронутого репозитория. + +#### Scenario: Фича затрагивает клиент и API + +- **WHEN** change меняет пользовательский поток и соответствующее API-поведение +- **THEN** Delivery Map отмечает frontend, backend, specs и docs как affected и описывает ожидаемый результат каждой области без реализации по файлам + +#### Scenario: Область не затронута + +- **WHEN** поведение, контракт, реализация, guardrails и фактическая документация области не меняются +- **THEN** Delivery Map содержит проверяемую причину `N/A`, а delivery не требует пустого коммита этого репозитория + +### Requirement: Частичная multi-repository delivery не считается завершённой + +Change MUST оставаться active, пока каждая affected область не реализована и не прошла свои обязательные локальные gates. Успех одной области MUST NOT позволять архивировать change, если другая affected область отсутствует, не проверена либо не соответствует согласованному поведению. После archive change MUST NOT получить terminal status `done`, пока фактические результаты всех четырёх delivery areas не представлены в Completion Evidence. + +#### Scenario: Backend готов, а frontend ещё не реализован + +- **WHEN** Delivery Map помечает frontend и backend как affected, но завершён и проверен только backend +- **THEN** change остаётся active и не может быть архивирован + +#### Scenario: Все affected области готовы + +- **WHEN** каждая affected область реализована, согласована по общим контрактам и прошла требуемые локальные gates +- **THEN** change может перейти к семантической верификации и archive, после которого формируется Completion Evidence для terminal status + +### Requirement: Completion Evidence содержит только наблюдённые результаты + +Completion Evidence MUST создаваться после выполнения работы и MUST связывать canonical change с commit identifier каждого изменённого Git-репозитория, точными выполненными non-mutating verification commands и их наблюдёнными результатами. Для каждой области с `N/A` evidence SHALL сохранять согласованную причину отсутствия изменения. Planned commands, ожидаемые результаты, незавершённые checklist items и предполагаемые commit identifiers MUST NOT представляться как completion evidence. + +#### Scenario: Change готовится к terminal status + +- **WHEN** implementer заявляет, что multi-repository change завершён +- **THEN** reviewer может сопоставить Delivery Map с фактическими commits, результатами gates и причинами `N/A` для всех четырёх областей + +#### Scenario: Команда ещё не была выполнена + +- **WHEN** verification command только запланирована или её результат не сохранён +- **THEN** она остаётся implementation checklist item и не засчитывается как Completion Evidence + +### Requirement: Общий локальный verifier сохраняет gates репозиториев + +Workspace SHALL предоставлять один non-mutating локальный verification entrypoint для multi-repository delivery. Он MUST проверять совместимость runtime до application gates, запускать канонический gate каждой selected affected области и сохранять их ошибки как blocking result. Общий verifier MUST NOT заменять или ослаблять локальные gates независимых репозиториев. + +#### Scenario: Запущен неподдерживаемый runtime + +- **WHEN** multi-repository verifier запускается с runtime, не соответствующим объявленному проектом контракту +- **THEN** проверка завершается ошибкой до получения вводящего в заблуждение результата application tests + +#### Scenario: Один repository gate завершается ошибкой + +- **WHEN** общий verifier проверяет несколько affected областей и канонический gate одной из них не проходит +- **THEN** общий результат является неуспешным и явно указывает failing area без обхода её локального gate diff --git a/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/openspec-authority-and-lifecycle/spec.md b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/openspec-authority-and-lifecycle/spec.md new file mode 100644 index 0000000..06f1555 --- /dev/null +++ b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/openspec-authority-and-lifecycle/spec.md @@ -0,0 +1,88 @@ +## ADDED Requirements + +### Requirement: SDD-артефакты имеют непересекающиеся полномочия + +Proposal SHALL выражать причину, намерение, границы и ожидаемый эффект change языком владельца и MUST NOT содержать решения по технологиям, структуре кода, файлам, API или зависимостям. Delta Specs SHALL определять только добавленное, изменённое или удалённое наблюдаемое поведение и инварианты системы без описания изменений кода. Design SHALL объяснять архитектурный способ выполнения утверждённых Specs, существенные решения, риски и альтернативы крупными частями и MUST NOT становиться построчной инструкцией реализации. Tasks SHALL быть implementation checklist, достаточным для выполнения Design и Specs, и MUST NOT содержать ещё не наблюдённые completion results, commit identifiers или post-archive bookkeeping. Completion Evidence SHALL фиксироваться только после фактической реализации и верификации и MUST NOT подменять planning artifact. + +#### Scenario: Product Owner формулирует Proposal + +- **WHEN** владелец описывает требуемое изменение, не зная структуры кода и файлов +- **THEN** Proposal остаётся полноценным утверждаемым намерением без необходимости принимать архитектурные решения + +#### Scenario: Агент подготавливает Tasks + +- **WHEN** Proposal, Delta Specs и Design уже утверждены +- **THEN** Tasks перечисляет конкретные действия реализации и проверки, но не заявляет будущие результаты уже выполненными + +### Requirement: Artifact graph применяет последовательные approval gates + +Versioned SDD change SHALL проходить последовательность `Proposal → Delta Specs → Design → Tasks → Apply`. AI-агент MAY подготовить черновик текущего разрешённого артефакта, но MUST NOT считать его утверждённым самостоятельно или создавать downstream artifact до явного решения Change Owner. Для change, определяющего продуктовое поведение, Change Owner SHALL быть Product Owner; для технического или процессного change — Engineering Owner. Каждый из четырёх planning artifacts MUST существовать и быть утверждён до Apply. + +#### Scenario: Proposal ещё не утверждён + +- **WHEN** AI-агент завершил черновик Proposal, но Change Owner не дал явного согласия +- **THEN** Delta Specs, Design и Tasks остаются недоступны для создания + +#### Scenario: Delta Specs утверждены + +- **WHEN** Change Owner явно подтверждает Delta Specs после утверждённого Proposal +- **THEN** Design становится следующим разрешённым planning artifact, а Tasks и Apply остаются заблокированы + +### Requirement: Изменение upstream artifact требует каскадной проверки + +Изменение утверждённого Proposal MUST инициировать повторную проверку Delta Specs, Design и Tasks; изменение утверждённых Delta Specs MUST инициировать повторную проверку Design и Tasks; изменение утверждённого Design MUST инициировать повторную проверку Tasks. Изменение Tasks MUST NOT неявно менять scope, наблюдаемое поведение или архитектурные решения upstream artifacts; при таком обнаружении workflow SHALL вернуть работу к соответствующему upstream artifact и его approval gate. + +#### Scenario: После Design изменилось намерение + +- **WHEN** владелец меняет scope или ожидаемый эффект Proposal +- **THEN** зависимые Delta Specs, Design и Tasks теряют прежнее подтверждение до повторной согласованной проверки + +#### Scenario: Task вводит новое поведение + +- **WHEN** implementation checklist требует поведение, которого нет в утверждённых Delta Specs +- **THEN** агент не расширяет scope через Tasks и возвращает change к Delta Specs + +### Requirement: OpenSpec tooling имеет проверяемый version contract + +SDD workflow MUST объявлять поддерживаемую версию OpenSpec CLI и проверять фактическую версию до команд, читающих или изменяющих canonical change. Несовместимая либо неопределённая версия MUST давать actionable blocking result и MUST NOT приводить к молчаливому изменению artifact graph, templates или project-owned entrypoints. + +#### Scenario: Версия CLI соответствует контракту + +- **WHEN** агент начинает работу с canonical change поддерживаемой версией OpenSpec +- **THEN** workflow продолжает работу с объявленной схемой и canonical store + +#### Scenario: Версия CLI не соответствует контракту + +- **WHEN** доступная версия OpenSpec не совпадает с объявленным совместимым контрактом +- **THEN** локальная preflight-проверка блокирует SDD-операцию и сообщает ожидаемую и фактическую версии + +### Requirement: Structural и semantic verification являются разными gates + +OpenSpec structural validation SHALL проверять schema, artifact graph и формальную корректность specs, но MUST NOT считаться доказательством соответствия реализации. До terminal status change MUST пройти semantic verification реализации против Proposal, Delta Specs, Design и Tasks, а затем независимый read-only review. Если основной agent entrypoint semantic verification недоступен, workflow SHALL использовать versioned эквивалентную процедуру с теми же входными артефактами, категориями проверки и наблюдаемым evidence. + +#### Scenario: Structural validation прошла без ошибок + +- **WHEN** все planning artifacts формально валидны, но реализация ещё не сопоставлена с ними +- **THEN** change не получает terminal status только на основании structural validation + +#### Scenario: Slash workflow недоступен агенту + +- **WHEN** среда не предоставляет установленный semantic verification entrypoint +- **THEN** агент выполняет документированную эквивалентную read-only проверку и сохраняет её результат вместо пропуска gate + +## MODIFIED Requirements + +### Requirement: Archive блокируется незавершёнными tasks +Project-owned archive workflow MUST отклонять archive, если отсутствует требуемый planning artifact, любой обязательный artifact не утверждён, `tasks.md` отсутствует или содержит unchecked task, semantic verification либо независимый read-only review не завершены успешно, или любая affected delivery area не реализована и не прошла обязательные pre-archive gates. Workflow MUST NOT предлагать confirmation override для этих blocking conditions. Post-archive bookkeeping MUST NOT появляться как unchecked task; он SHALL фиксироваться через детерминированное Completion Evidence после успешного archive, после чего связанная delivery может получить terminal status. + +#### Scenario: Change имеет unchecked task +- **WHEN** implementer запрашивает archive и остаётся хотя бы один unchecked task +- **THEN** workflow не архивирует change и сообщает incomplete tasks как blocking condition без возможности confirmation override + +#### Scenario: Change не прошёл required verification +- **WHEN** planning artifacts и tasks завершены, но semantic verification, independent review, implementation или pre-archive gate affected area отсутствуют либо неуспешны +- **THEN** workflow не архивирует change и перечисляет недостающие blocking conditions + +#### Scenario: Change завершил все tasks +- **WHEN** каждый planning artifact утверждён, каждый task отмечен, required verification, implementation и pre-archive gates всех affected areas успешно завершены +- **THEN** workflow допускает archive, после которого его результат фиксируется через определённый completion-evidence path без создания post-archive task diff --git a/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/project-documentation/spec.md b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/project-documentation/spec.md new file mode 100644 index 0000000..48dfce7 --- /dev/null +++ b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/project-documentation/spec.md @@ -0,0 +1,32 @@ +## ADDED Requirements + +### Requirement: Completion Evidence сохраняет фактическое завершение change + +Durable development documentation SHALL хранить для завершённого change ссылку на canonical OpenSpec archive, Delivery Map, commit identifiers изменённых репозиториев, точные выполненные verification commands, их наблюдённые результаты и итог independent read-only review. Completion Evidence MUST создаваться из фактов после выполнения работы, MUST быть доступно из устойчивого index или registry и MUST NOT дублироваться как unchecked task либо планируемый результат внутри archived change. + +#### Scenario: Участник проверяет основание terminal status + +- **WHEN** участник открывает evidence завершённого change в новой сессии +- **THEN** он может проследить связь от change и Delivery Map к фактическим commits, локальным gates и independent review без восстановления контекста из чата + +#### Scenario: Реализация ещё продолжается + +- **WHEN** часть commands, commits или review ещё не существует +- **THEN** documentation не представляет ожидаемые значения как Completion Evidence и change остаётся незавершённым + +## MODIFIED Requirements + +### Requirement: Durable documentation is not a parallel SDD store +Репозиторий `docs` SHALL хранить только долговечную architecture, development, feature, audit и remediation documentation вместе с completion evidence. Документация MUST описывать фактическое текущее состояние поставленной системы и MUST NOT представлять планируемое или частично реализованное поведение как доступное. Change-specific requirements, proposals, designs, delta specifications и tasks MUST храниться только в canonical OpenSpec store и MUST NOT пересказываться в `docs` как параллельная спецификация в другом формате. Docs SHALL обновляться после реализации и проверки соответствующей области; она MAY ссылаться на canonical OpenSpec change, но MUST сохранять собственную as-built задачу и не копировать его нормативный текст. + +#### Scenario: Change требует постоянной документации +- **WHEN** завершённый change должен оставить устойчивое объяснение фактического решения или evidence +- **THEN** documentation фиксирует реализованное состояние или completion evidence и ссылается на canonical OpenSpec change без дублирования его requirements, design или tasks + +#### Scenario: Agent планирует незавершённый change +- **WHEN** агент создаёт requirements, design или tasks для незавершённого изменения +- **THEN** он сохраняет их под `specs/openspec` и не создаёт framework-specific planning document или описание будущего поведения в `docs` + +#### Scenario: Реализация расходится с прежней документацией +- **WHEN** проверенный change изменяет поставленное поведение, архитектурную границу или устойчивое решение +- **THEN** affected docs обновляется до фактического текущего состояния до terminal status и не сохраняет прежнее утверждение как действующее diff --git a/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/project-foundation/spec.md b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/project-foundation/spec.md new file mode 100644 index 0000000..8e9061c --- /dev/null +++ b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/specs/project-foundation/spec.md @@ -0,0 +1,36 @@ +## ADDED Requirements + +### Requirement: Application repositories имеют канонический локальный gate + +Frontend и backend SHALL предоставлять по одному каноническому non-mutating verification entrypoint, который проверяет все обязательные для соответствующего репозитория Enforceable Engineering Invariants. Каждый entrypoint MUST отклонять неподдерживаемый Node runtime до запуска зависимых application checks, MUST возвращать ненулевой результат при ошибке любого обязательного stage и MUST быть одинаковым для человека, AI-агента и общего workspace verifier. Отдельные auto-fix commands MUST NOT использоваться как verification entrypoint. + +#### Scenario: Агент завершает frontend-изменение + +- **WHEN** агент считает frontend implementation готовой +- **THEN** он запускает один documented frontend gate и получает совокупный non-mutating результат всех обязательных frontend checks + +#### Scenario: Агент запускает backend gate с неверным Node + +- **WHEN** фактическая major/minor версия Node не соответствует объявленному runtime contract backend +- **THEN** gate завершается ошибкой до application checks и сообщает ожидаемую и фактическую версии + +## MODIFIED Requirements + +### Requirement: Репозитории содержат локальные инструкции для AI-агентов +Система SHALL содержать обзорный `AGENTS.md` в корне рабочей области и отдельный `AGENTS.md` в репозиториях frontend, backend, specs и docs. Корневая инструкция MUST содержать только общую карту workspace, Single Source of Truth, cross-repository workflow и общие hard constraints; локальная инструкция MUST добавлять относящиеся к своему репозиторию команды, проверяемые правила стиля и границ, не копируя изменчивые требования, архитектуру или feature documentation. Инструкции MUST описывать назначение области, канонический non-mutating verification entrypoint, границы ответственности и ссылки на authoritative SDD и durable documentation. Каждая инструкция MUST объявлять `wealth-ledger-specs` и `specs/openspec` как canonical OpenSpec authority, требовать явный `--store wealth-ledger-specs` для поддерживаемых OpenSpec операций и запрещать versioned framework-specific planning artifacts вне canonical store. Локальные инструкции MUST направлять агента к durable documentation, относящейся к его области, и к durable remediation registry, когда задача связана с findings технического аудита. Enforceable Engineering Invariants MUST быть сформулированы как проверяемые обязательные правила; непроверяемые предпочтения MUST быть отделены как guidance. Backend instructions MUST различать non-mutating verification commands и явные auto-fix commands. + +#### Scenario: Агент начинает работу в отдельном репозитории +- **WHEN** агент открывает любой из репозиториев frontend, backend, specs или docs +- **THEN** он может определить локальные правила работы, канонический verification entrypoint, проверяемый стиль и границы, canonical OpenSpec authority и относящийся к области durable documentation без чтения дублирующих требований + +#### Scenario: Агент получает audit-derived задачу из отдельного репозитория +- **WHEN** задача ссылается на finding технического аудита +- **THEN** локальный `AGENTS.md` указывает на remediation registry и canonical OpenSpec workflow с явным store selection до начала изменения кода + +#### Scenario: Агент выбирает backend quality gate +- **WHEN** агент читает backend instructions перед локальной проверкой +- **THEN** он запускает документированный канонический non-mutating gate и не получает auto-fix как неявную часть verification + +#### Scenario: Архитектурное устройство изменилось +- **WHEN** durable architecture documentation обновлена после поставленного change +- **THEN** `AGENTS.md` продолжает ссылаться на authoritative документ и не требует синхронного копирования его описательного содержимого diff --git a/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/tasks.md b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/tasks.md new file mode 100644 index 0000000..838e113 --- /dev/null +++ b/openspec/changes/archive/2026-08-24-harden-agent-sdd-governance/tasks.md @@ -0,0 +1,45 @@ +## 1. Контракт версии OpenSpec и проектная схема + +- [x] 1.1 Добавить точный контракт CLI `1.10.0` и тонкий version preflight в `specs/openspec` и `specs/scripts`, вызывать его до project-owned операций со store и проверить реальный успешный случай `1.10.0` и контролируемый временный wrong-version failure без отдельного unit-test suite для скрипта. +- [x] 1.2 Создать native fork схемы `spec-driven` в `specs/openspec/schemas/wealth-ledger-sdd`, изменить dependency graph на `proposal → specs → design → tasks → apply` и проверить успешный `openspec schema validate wealth-ledger-sdd --verbose` и project-local source в `openspec schema which wealth-ledger-sdd --json`. +- [x] 1.3 Настроить templates и instructions `wealth-ledger-sdd`, чтобы Proposal, Delta Specs, Design и Tasks сохраняли согласованные непересекающиеся роли, Design требовал Delivery Map четырёх областей и условный Solution Assessment, а Tasks применял risk-based testing и исключал observed evidence/archive bookkeeping; проверить принятие всех templates schema validator без нового обязательного артефакта. +- [x] 1.4 Выбрать `wealth-ledger-sdd` default-схемой в `specs/openspec/config.yaml`, добавить только компактный workspace context и additive lifecycle rules и на disposable project-local change проверить последовательную готовность артефактов, сохранив bootstrap change `harden-agent-sdd-governance` на `spec-driven`. + +## 2. OpenSpec authority и workspace orchestration + +- [x] 2.1 Перегенерировать OpenSpec 1.10 agent entrypoints в isolated staging, перенести upstream delta в корневую `.opencode` projection, повторно наложить только fixed `wealth-ledger-specs`, one-artifact-at-a-time и hard archive-blocker overlays и проверить, что второй workspace `openspec` root не создан, а каждый generated entrypoint указывает OpenSpec 1.10. +- [x] 2.2 Расширить `specs/scripts/verify-openspec-authority.sh` и существующие hard-guardrail fixtures, чтобы отклонять неверный CLI/schema contract, implicit или conditional store selection, непоследовательный artifact graph, permissive archive и competing planning root при сохранении валидного projection case; проверить `bash specs/scripts/verify-openspec-authority.test.sh`. +- [x] 2.3 Добавить non-mutating workspace dispatcher в `specs/scripts`: принимать canonical change, проверять решения для frontend, backend, specs и docs, всегда запускать specs gates, делегировать только affected repository gates и условно добавлять runtime OpenAPI comparison; проверить выбор всех четырёх областей этого change и отказ для disposable неполного Delivery Map без постоянного unit test оркестрационного скрипта. +- [x] 2.4 Обновить project-owned semantic verification и archive entrypoints: требовать завершённые affected-area gates, semantic verification и independent read-only review без confirmation override; проверить, что authority fixture отклоняет репрезентативные варианты с отсутствующей verification и разрешённым override. + +## 3. Канонический локальный gate frontend + +- [x] 3.1 Добавить тонкий Node runtime preflight frontend из `engines`/`.nvmrc`, поставить его первым в canonical `npm run verify` и проверить успешный запуск под Node 22 и остановку до application checks под контролируемым неподдерживаемым Node без отдельного unit test. +- [x] 3.2 Удалить повторный вызов `test:run` из composite verifier frontend, сохранив один coverage-backed запуск Vitest и все OpenAPI, hygiene, type, Biome, Knip, dependency, build, bundle и coverage ratchets; проверить по полному выводу `npm run verify` один запуск Vitest suite и выполнение всех обязательных stages. +- [x] 3.3 Согласовать `frontend/README.md` и `frontend/docs/TESTING.md` с canonical gate и risk-based выбором тестов, сохранить существующие hard-guardrail fixtures и обозначить coverage как anti-regression constraint, а не причину тестировать декларативные файлы; проверить разрешение задокументированных команд и ссылок из frontend repository. + +## 4. Канонический локальный gate backend + +- [x] 4.1 Добавить тонкий Node runtime preflight backend из `engines`/`.nvmrc`, поставить его первым в новом canonical verification entrypoint и проверить успешный запуск под Node 22 и остановку до application checks под контролируемым неподдерживаемым Node без отдельного unit test. +- [x] 4.2 Добавить backend `npm run verify` как fail-fast non-mutating chain для runtime, hygiene, lint, application/test typechecks, Jest и build, явно исключив deferred Prisma e2e и новый global coverage threshold; проверить полный gate под Node 22 и ненулевой общий результат при контролируемом failure одного child stage. +- [x] 4.3 Обновить `backend/README.md` и `docs/development/backend-workflow.md`, обозначив только `npm run verify` completion gate, оставив `lint:fix`, coverage и deferred e2e отдельными, и проверить соответствие документированных команд `backend/package.json` при сохранённом WL-P2-05 review trigger. + +## 5. Docs-as-code и устойчивая governance-документация + +- [x] 5.1 Добавить Node 22 lockfile-backed toolchain docs с `markdownlint-cli2`, отключить в committed configuration только MD013, предоставить один non-mutating `npm run verify` и проверить `npm ci` и полный docs gate на текущем Markdown baseline без auto-fix и network/browser link checking. +- [x] 5.2 Создать authoritative development policy для Change Owner, artifact approvals, Delivery Map, Completion Evidence, Enforceable Engineering Invariant, risk-based testing, build-vs-buy Solution Assessment и SSOT boundaries; добавить ссылку в `docs/development/README.md`, привести `docs/development/openspec-authority-and-lifecycle.md` к as-built custom-schema workflow без копирования schema instructions и проверить разрешение всех local links. +- [x] 5.3 Добавить ADR 010 о native OpenSpec schema и минимальной local orchestration, проиндексировать его в `docs/adr/README.md` и проверить, что ADR фиксирует alternatives, consequences и reconsideration triggers без пересказа requirements change. +- [x] 5.4 Создать immutable `docs/audits/audit-24-08-2026.md`, добавить его в `docs/audits/README.md`, расширить единый live remediation registry на все audit snapshots, сделать `harden-agent-sdd-governance` единственным active remediation change и перевести WL-P3-04 в `deferred` с accessibility trigger; проверить разрешение каждого Audit ID в один snapshot и не более одной active записи. +- [x] 5.5 Исправить подтверждённые current-state contradictions исторических A-15 и A-18 в authoritative ADR и основной spec `user-authentication`, не редактируя immutable audit snapshots; проверить разрешение implementation-status links ADR и успешную strict validation всех основных specs. + +## 6. Слоистые agent instructions и onboarding + +- [x] 6.1 Переписать слои корневого, frontend, backend, specs и docs `AGENTS.md`: оставить в корне только workspace-wide SSOT/lifecycle constraints, а в каждом репозитории — canonical gate, enforceable style/boundary sources, маршруты к durable docs и audit registry, явный `--store wealth-ledger-specs` и запрет parallel planning stores; проверить authority fixture и все repository-local link/path checks. +- [x] 6.2 Обновить onboarding references frontend, backend и specs на новую governance policy, custom schema и workspace dispatcher без копирования architecture или feature content в AGENTS/README; проверить, что читатель из каждого репозитория достигает canonical SDD authority, local gate и относящейся к области durable documentation. + +## 7. Интегрированная pre-archive verification + +- [x] 7.1 Запустить workspace dispatcher для `harden-agent-sdd-governance` под Node 22 и проверить успешные canonical results frontend, backend, specs и docs без fallback, auto-fix или запуска deferred e2e. +- [x] 7.2 Запустить `bash specs/scripts/verify-runtime-openapi.sh` под Node 22 и проверить соответствие backend runtime contract committed OpenAPI snapshot frontend, поскольку обе contract sides входят в Delivery Map этого change. +- [x] 7.3 Запустить project-local schema validation, strict validation `harden-agent-sdd-governance`, strict validation всех canonical specs, OpenSpec authority fixtures и `git diff --check` в каждом affected Git repository; проверить успешное завершение всех structural и repository hygiene gates. +- [x] 7.4 Выполнить semantic verification реализации против Proposal, всех 19 требований Delta Specs, Design и этого checklist, затем провести independent read-only standards/spec review и проверить отсутствие Critical и Important findings до запроса archive. diff --git a/openspec/config.yaml b/openspec/config.yaml index 392946c..79fc962 100644 --- a/openspec/config.yaml +++ b/openspec/config.yaml @@ -1,20 +1,18 @@ -schema: spec-driven +schema: wealth-ledger-sdd -# Project context (optional) -# This is shown to AI when creating artifacts. -# Add your tech stack, conventions, style guides, domain knowledge, etc. -# Example: -# context: | -# Tech stack: TypeScript, React, Node.js -# We use conventional commits -# Domain: e-commerce platform +context: | + WealthLedger состоит из независимых frontend, backend, specs и docs Git-репозиториев. + Canonical OpenSpec authority — зарегистрированный store wealth-ledger-specs в specs/openspec. + Docs описывает только фактическое as-built состояние; устойчивые process policies находятся в docs/development. + Локальная разработка и verification выполняются под Node 22 без CI. -# Per-artifact rules (optional) -# Add custom rules for specific artifacts. -# Example: -# rules: -# proposal: -# - Keep proposals under 500 words -# - Always include a "Non-goals" section -# tasks: -# - Break tasks into chunks of max 2 hours +rules: + proposal: + - Формулировать owner-утверждаемое намерение без технологий, API, файлов и зависимостей. + specs: + - Описывать только изменение наблюдаемого поведения и инвариантов, не изменение кода. + design: + - Всегда включать Delivery Map для frontend, backend, specs и docs. + - Добавлять Solution Assessment только при build-vs-buy trigger из schema instructions. + tasks: + - Включать planned verification каждой affected области, но не observed results, commit IDs или post-archive bookkeeping. diff --git a/openspec/schemas/wealth-ledger-sdd/schema.yaml b/openspec/schemas/wealth-ledger-sdd/schema.yaml new file mode 100644 index 0000000..18adb2f --- /dev/null +++ b/openspec/schemas/wealth-ledger-sdd/schema.yaml @@ -0,0 +1,244 @@ +name: wealth-ledger-sdd +version: 1 +description: WealthLedger SDD workflow - proposal → specs → design → tasks +artifacts: + - id: proposal + generates: proposal.md + description: Owner-approved intent without implementation details + template: proposal.md + instruction: | + Создай Proposal, который формулирует намерение и объясняет, ПОЧЕМУ + изменение нужно. Его должен понимать и утверждать владелец продукта или + процесса без знания структуры кода. + + Sections: + Разделы: + - **Why**: проблема или возможность и причина заняться ею сейчас. + - **What Changes**: намерение, ожидаемый результат и явные non-goals. + - **Capabilities**: какие поведенческие specs появятся или изменятся: + - **New Capabilities**: List capabilities being introduced. Each becomes a new `specs//spec.md`. Use kebab-case for path segments you introduce (e.g., `user-auth` or `identity/user-auth`) and follow the project's existing spec organization. + - **Modified Capabilities**: List existing capabilities whose REQUIREMENTS are changing. Only include if spec-level behavior changes (not just implementation details). Each needs a delta spec file. Use the exact existing path under `openspec/specs/`. Leave empty if no requirement changes. + - **Impact**: затронутые пользователи, процессы или части системы только + на уровне scope. + + IMPORTANT: The Capabilities section is critical. It creates the contract between + proposal and specs phases. Research existing specs before filling this in. + Each capability listed here will need a corresponding spec file. + + Every change must either declare at least one capability (new or + modified) or explicitly opt out of specs: `openspec validate` rejects a + change with zero deltas unless the change's `.openspec.yaml` sets + `skip_specs: true`. Use `skip_specs: true` only when no spec-level + behavior changes (pure refactor, tooling, docs) - specs describe + behavior, so if behavior does not change, no spec should change either. + Do not invent a requirement just to satisfy validation. + + MUST NOT включать технологии, библиотеки, API signatures, имена файлов, + зависимости, классы или пошаговую реализацию. Эти решения появляются + только после Delta Specs в Design. + + This is the foundation - specs, design, and tasks all build on this. + requires: [] + + - id: specs + generates: "specs/**/*.md" + description: Observable behavior and invariants changed by the proposal + template: spec.md + instruction: | + Создай Delta Specs, определяющие, ЧТО наблюдаемо изменяется в системе. + + Spec является behavior contract, а не планом изменения кода. + + Good spec content: + - Observable behavior users or downstream systems rely on + - Inputs, outputs, and error conditions + - External constraints (security, privacy, reliability, compatibility) + - Scenarios that can be tested or explicitly validated + + Не включай в specs: + - Internal class/function names + - Library or framework choices + - Step-by-step implementation details + - Detailed execution plans (those belong in design.md or tasks.md) + + Quick test: if the implementation can change without changing externally + visible behavior, it likely does not belong in the spec. + + Create one spec file per capability listed in the proposal's Capabilities section. + `` is the spec directory relative to `specs/` (for example, + `user-auth` or `identity/user-auth`). Preserve the full path: + - New capabilities: use the exact path from the proposal at `specs//spec.md`. Any path segment newly introduced in the proposal must be kebab-case. Follow the project's existing organization; do not add a new domain level when the project uses a flat layout. + - Modified capabilities: use the exact existing path from `openspec/specs//` when creating the delta at `specs//spec.md`. Do not move or rename the capability. + + There must be at least one spec file unless the change's `.openspec.yaml` + sets `skip_specs: true` (no spec-level behavior change) - `openspec validate` + rejects a zero-delta change without that marker. If the proposal lists no + capabilities and `skip_specs` is not set, revisit the proposal first. + + Delta operations (use ## headers): + - **ADDED Requirements**: New capabilities + - **MODIFIED Requirements**: Changed behavior - MUST include full updated content + - **REMOVED Requirements**: Deprecated features - MUST include **Reason** and **Migration** + - **RENAMED Requirements**: Name changes only - use FROM:/TO: format + + Format requirements: + - Each requirement: `### Requirement: ` followed by description + - Use SHALL/MUST for normative requirements (avoid should/may) + - Each scenario: `#### Scenario: ` with WHEN/THEN format + - **CRITICAL**: Scenarios MUST use exactly 4 hashtags (`####`). Using 3 hashtags or bullets will fail silently. + - Every requirement MUST have at least one scenario. + + New capabilities only: start the delta spec with a `## Purpose` section - + one or two sentences (50+ characters, or `openspec validate --strict` + reports it as too brief) describing what the capability is for. Archive + copies it into the main spec it creates; without it the new main spec is + left with a `TBD ... Update Purpose after archive` placeholder to fill in + by hand. Do NOT add `## Purpose` to a delta for an existing capability - + that spec already has one and the delta's is ignored. To change an + existing capability's Purpose - including a leftover `TBD` placeholder - + edit `/openspec/specs//spec.md` + directly. `planningHome.root` comes from the `openspec instructions ... + --json` response. Always use it rather than a repo-relative path: it + resolves to the store whenever the change lives in one - whether that + came from `--store`, a project `store:` pointer, or a global default + store - and to the current repository otherwise. Do not try to work out + which case applies; the field already has. + + MODIFIED requirements workflow: + 1. Locate the existing requirement in `/openspec/specs//spec.md` (the same store-aware root as above) + 2. Copy the ENTIRE requirement block (from `### Requirement:` through all scenarios) + 3. Paste under `## MODIFIED Requirements` and edit to reflect new behavior + 4. Ensure header text matches exactly (whitespace-insensitive) + + Common pitfall: Using MODIFIED with partial content loses detail at archive time. + If adding new concerns without changing existing behavior, use ADDED instead. + + Example (a new capability, so it opens with `## Purpose`): + ``` + ## Purpose + + Lets users take their data out of the product in a portable format. + + ## ADDED Requirements + + ### Requirement: User can export data + The system SHALL allow users to export their data in CSV format. + + #### Scenario: Successful export + - **WHEN** user clicks "Export" button + - **THEN** system downloads a CSV file with all user data + + ## REMOVED Requirements + + ### Requirement: Legacy export + **Reason**: Replaced by new export system + **Migration**: Use new export endpoint at /api/v2/export + ``` + + Specs должны быть проверяемыми, но scenario не означает автоматический + unit test: уровень проверки выбирается по риску поведения. + requires: + - proposal + + - id: design + generates: design.md + description: Architectural implementation approach and delivery decisions + template: design.md + instruction: | + Создай Design, объясняющий, КАК архитектурно выполнить утверждённые + Delta Specs. Не превращай его в построчную инструкцию или список правок. + + Обязательные разделы: + - **Context**: только текущее состояние и ограничения подхода. + - **Goals / Non-Goals**: технические границы, не пересказ Proposal. + - **Decisions**: крупные решения, rationale и рассмотренные alternatives. + - **Delivery Map**: ровно frontend, backend, specs и docs; для каждой + области `affected` с ожидаемым архитектурным результатом либо `N/A` с + конкретной причиной. `specs` всегда affected. Здесь же зафиксируй + Contract Gate Decision для `runtime-openapi`: `required`, только когда + change затрагивает обе стороны API contract, либо `N/A` с причиной. + - **Risks / Trade-offs**: риск и mitigation. + - **Migration Plan**: порядок поставки и rollback, если применимо. + + Добавь **Solution Assessment**, если изменение вводит или существенно + заменяет auth, security, storage, external integration, observability, + caching, concurrency или общую infrastructure/tooling либо содержит + другое дорогостоящее необратимое решение. Сравни зрелые готовые решения + по fit, maturity, security, operating cost, constraints и migration cost. + Custom implementation допустима только после фиксации несовместимости + подходящих alternatives и принятых рисков. Не создавай отдельный artifact. + + **Open Questions** допустим только для неизвестного, которое не меняет + Specs, выбранный подход или Tasks. Иначе остановись и запроси решение + владельца до сохранения Design. + + Open questions are for genuinely deferrable unknowns, not decisions you + skipped. If a question would change the specs, the chosen approach, or + the task breakdown, resolve it now - ask the user instead of guessing. + + Design формируется только после явного owner approval Delta Specs. + requires: + - specs + + - id: tasks + generates: tasks.md + description: Implementation checklist with trackable tasks + template: tasks.md + instruction: | + Создай implementation checklist, достаточный для выполнения Design и + Delta Specs. Это конкретное DO, а не ещё один архитектурный документ. + + Before writing tasks, check design.md for Open Questions. If any of them + would change what gets built, resolve them with the user first - do not + bake an unstated assumption into the task list. + + **IMPORTANT: Follow the template below exactly.** The apply phase parses + checkbox format to track progress. Tasks not using `- [ ]` won't be tracked. + + Правила: + - Группируй задачи под numbered `##` headings и располагай по dependencies. + - Каждая задача MUST иметь формат `- [ ] X.Y ...` и быть выполнимой за + одну рабочую сессию. + - Для каждой `affected` области Delivery Map должна существовать задача + реализации и её canonical local gate; пустые commits запрещены. + - Каждая задача MUST указывать planned verification action: команду, + проверку наблюдаемого поведения или delivered artifact. + - Автоматические тесты обязательны для security/privacy, денежных + расчётов, data integrity/migration, concurrency, public contracts, + critical journeys и подтверждённых regressions. + - Не требуй отдельный unit test только из-за изменения файла. DTO без + логики, declarative structures, thin adapters, прямолинейная + orchestration, hygiene scripts и third-party behavior проверяются + существующим integration/contract gate, если нет собственного + branching, transformation, invariant или regression. + - Перед custom implementation в обязательных областях включи действие по + утверждённому Solution Assessment из Design. + - MUST NOT записывать ещё не наблюдённые результаты как выполненные, + предполагаемые commit identifiers, archive path или post-archive + Completion Evidence. Такое evidence создаётся только после факта. + + Example: + ``` + ## 1. Setup + + - [ ] 1.1 Create new module structure and verify expected files are present + - [ ] 1.2 Add dependencies to package.json and verify package installation succeeds + + ## 2. Core Implementation + + - [ ] 2.1 Implement data export function and verify the export test passes + - [ ] 2.2 Add CSV formatting utilities and verify unit tests cover quoting and delimiters + ``` + + Reference specs for what needs to be built, design for how to build it. + requires: + - design + +apply: + requires: [ tasks ] + tracks: tasks.md + instruction: | + Сначала проверь exact OpenSpec version contract. Работай только с change в + canonical store `wealth-ledger-specs` и не создавай parallel planning root. + Read context files, work through pending tasks, mark complete as you go. + Pause if you hit blockers or need clarification. diff --git a/openspec/schemas/wealth-ledger-sdd/templates/design.md b/openspec/schemas/wealth-ledger-sdd/templates/design.md new file mode 100644 index 0000000..fe383de --- /dev/null +++ b/openspec/schemas/wealth-ledger-sdd/templates/design.md @@ -0,0 +1,48 @@ +## Context + + + +## Goals / Non-Goals + +**Goals:** + + +**Non-Goals:** + + +## Decisions + + + +## Delivery Map + +| Area | Status | Architectural outcome or N/A reason | +| --- | --- | --- | +| frontend | `affected` or `N/A` | | +| backend | `affected` or `N/A` | | +| specs | `affected` | | +| docs | `affected` or `N/A` | | + +### Contract Gate Decision + +| Gate | Status | Reason | +| --- | --- | --- | +| runtime-openapi | `required` or `N/A` | | + +## Solution Assessment + + + +## Risks / Trade-offs + + + +## Migration Plan + + + +## Open Questions + + diff --git a/openspec/schemas/wealth-ledger-sdd/templates/proposal.md b/openspec/schemas/wealth-ledger-sdd/templates/proposal.md new file mode 100644 index 0000000..a18873e --- /dev/null +++ b/openspec/schemas/wealth-ledger-sdd/templates/proposal.md @@ -0,0 +1,30 @@ +## Why + + + +## What Changes + + + +## Capabilities + +### New Capabilities + +- ``: + +### Modified Capabilities + +- ``: + +## Impact + + diff --git a/openspec/schemas/wealth-ledger-sdd/templates/spec.md b/openspec/schemas/wealth-ledger-sdd/templates/spec.md new file mode 100644 index 0000000..c12f44d --- /dev/null +++ b/openspec/schemas/wealth-ledger-sdd/templates/spec.md @@ -0,0 +1,11 @@ +## Purpose + + +## ADDED Requirements + +### Requirement: + + +#### Scenario: +- **WHEN** +- **THEN** diff --git a/openspec/schemas/wealth-ledger-sdd/templates/tasks.md b/openspec/schemas/wealth-ledger-sdd/templates/tasks.md new file mode 100644 index 0000000..86b8ae8 --- /dev/null +++ b/openspec/schemas/wealth-ledger-sdd/templates/tasks.md @@ -0,0 +1,9 @@ +## 1. + +- [ ] 1.1 +- [ ] 1.2 + +## 2. + +- [ ] 2.1 +- [ ] 2.2 diff --git a/openspec/specs/audit-remediation-workflow/spec.md b/openspec/specs/audit-remediation-workflow/spec.md index 88169dd..2d2a6a4 100644 --- a/openspec/specs/audit-remediation-workflow/spec.md +++ b/openspec/specs/audit-remediation-workflow/spec.md @@ -7,27 +7,35 @@ ## Requirements ### Requirement: Реестр remediation отделён от снимка аудита -Система SHALL хранить неизменяемый versioned audit snapshot в `docs/audits` и durable remediation registry в `docs/development`. Snapshot SHALL оставаться source of facts; registry SHALL хранить только текущее состояние remediation. Каждая запись registry MUST ссылаться на Audit ID и не дублировать полный текст finding, если он уже содержится в snapshot. +Система SHALL создавать отдельный неизменяемый versioned audit snapshot в `docs/audits` для каждого завершённого аудита и SHALL поддерживать один актуальный durable remediation registry в `docs/development`, охватывающий findings всех audit snapshots. Каждый snapshot SHALL оставаться source of facts своего аудита и MUST NOT редактироваться для отражения последующей remediation. Registry SHALL хранить текущее состояние, связанный canonical change, следующее действие и completion evidence каждой записи, MUST ссылаться на однозначный Audit ID и исходный snapshot и MUST NOT дублировать полный текст finding, если он уже содержится в snapshot. #### Scenario: Агент открывает работу по аудиту в новой сессии -- **WHEN** агент получает задачу устранить или продолжить audit finding -- **THEN** он находит linked registry, исходный Audit ID, текущий статус, связанный OpenSpec change и следующее действие без повторной интерпретации всего аудита +- **WHEN** агент получает задачу устранить или продолжить finding из любого завершённого аудита +- **THEN** он находит в едином registry исходный snapshot и Audit ID, текущий статус, связанный OpenSpec change, evidence и следующее действие без повторной интерпретации всех аудитов + +#### Scenario: Проводится повторный аудит +- **WHEN** новый аудит завершён после предыдущего audit snapshot +- **THEN** система добавляет новый immutable snapshot и обновляет тот же live registry, не переписывая предыдущий snapshot и не создавая конкурирующий registry #### Scenario: Обновляется прогресс remediation - **WHEN** работа по finding меняет статус -- **THEN** versioned audit snapshot не редактируется, а изменение фиксируется только в registry с датой и необходимым evidence +- **THEN** versioned audit snapshots не редактируются, а изменение фиксируется только в live registry с датой и необходимым evidence ### Requirement: Registry задаёт однозначный статус и следующий change -Каждая audit-derived запись SHALL иметь ровно один статус из `planned`, `active`, `done`, `deferred` или `accepted`. Registry MUST содержать не более одного `active` change и ровно одну следующую рекомендуемую задачу, пока остаются findings со статусом `planned`. +Каждая audit-derived запись SHALL иметь ровно один статус из `planned`, `active`, `done`, `deferred` или `accepted`. `planned` MUST означать согласованную работу, которую можно начать без внешнего review trigger; запись, ожидающая версии зависимости, внешнего события или отдельного решения владельца, MUST иметь статус `deferred` с условием пересмотра. Registry MUST содержать не более одного `active` remediation change и ровно одну следующую рекомендуемую задачу, пока существуют findings со статусом `planned`. #### Scenario: В рабочей области нет активного remediation change -- **WHEN** агент открывает registry и все незакрытые findings имеют статус `planned` +- **WHEN** агент открывает registry и все незакрытые немедленно исполнимые findings имеют статус `planned` - **THEN** он может выбрать ровно одну строку, отмеченную как следующая рекомендуемая задача, и создать связанный canonical OpenSpec change #### Scenario: В рабочей области уже есть активный remediation change - **WHEN** registry содержит запись со статусом `active` - **THEN** агент продолжает связанный change и не создаёт второй remediation change без явного решения владельца +#### Scenario: Finding зависит от будущего trigger +- **WHEN** remediation нельзя обоснованно начать до указанной версии зависимости, внешнего события или решения владельца +- **THEN** registry хранит статус `deferred`, rationale и проверяемое условие пересмотра вместо представления finding как готового `planned` work + ### Requirement: Terminal status подтверждён проверяемым evidence Registry SHALL NOT представлять finding как `done` без даты, archive path связанного OpenSpec change, commit identifiers для каждого затронутого Git-репозитория и точных non-mutating verification commands с результатами. Архивированный audit-derived change MUST иметь все tasks завершёнными до archive; completion evidence после archive MUST быть отдельной записью registry или history, а не незакрытым task в archived change. Статусы `deferred` и `accepted` MUST содержать дату, rationale и условие пересмотра либо ссылку на явное решение владельца. diff --git a/openspec/specs/engineering-change-governance/spec.md b/openspec/specs/engineering-change-governance/spec.md new file mode 100644 index 0000000..b04312e --- /dev/null +++ b/openspec/specs/engineering-change-governance/spec.md @@ -0,0 +1,69 @@ +# engineering-change-governance Specification + +## Purpose + +Определяет соразмерные и проверяемые правила инженерных решений AI-агентов, чтобы WealthLedger переиспользовал зрелые решения, тестировал существенные риски и локально отклонял код, нарушающий инварианты проекта. + +## Requirements + +### Requirement: Готовые решения оцениваются до собственной реализации + +Изменение, которое вводит или существенно заменяет механизм авторизации, безопасности, хранения данных, внешней интеграции, наблюдаемости, кэширования, конкурентного доступа либо общей инфраструктуры и tooling, MUST до утверждения архитектурного решения оценить существующие поддерживаемые решения. Оценка MUST сравнивать применимые варианты по соответствию требованиям, зрелости, безопасности, эксплуатационной стоимости, ограничениям и стоимости миграции. Собственная реализация SHALL допускаться только когда подходящего готового решения нет либо его существенная несовместимость явно зафиксирована вместе с рисками такого выбора. Для изменений вне перечисленных областей отдельная оценка MUST NOT быть обязательной без конкретного риска или дорогостоящего необратимого решения. + +#### Scenario: Существует совместимое зрелое решение + +- **WHEN** change затрагивает одну из обязательных для оценки областей и найдено поддерживаемое решение, удовлетворяющее требованиям без неприемлемых ограничений +- **THEN** архитектурное решение использует это решение либо явно объясняет, почему его совокупная стоимость или риск выше выбранной альтернативы + +#### Scenario: Подходящего решения нет + +- **WHEN** рассмотренные зрелые решения не выполняют существенные требования или создают неприемлемый риск +- **THEN** собственная реализация допускается только после фиксации проверенных вариантов, конкретных разрывов, принятых рисков и условия повторного пересмотра + +#### Scenario: Изменение не требует solution assessment + +- **WHEN** change не относится к обязательным областям и не содержит отдельного дорогостоящего или необратимого решения +- **THEN** отсутствие формальной оценки готовых решений не блокирует SDD lifecycle и не создаёт дополнительный артефакт ради процесса + +### Requirement: Тестирование определяется риском поведения + +План изменения MUST требовать автоматизированные тесты для security- и privacy-sensitive поведения, денежных расчётов, целостности и миграции данных, конкурентного доступа, публичных контрактов, критических пользовательских сценариев и подтверждённых регрессий. Изменение MUST NOT требовать новый тест только из-за появления или изменения файла. Простые декларативные структуры, DTO без собственной логики, тонкие адаптеры, прямолинейная оркестрация, hygiene scripts и поведение сторонней библиотеки SHALL проверяться существующим контрактным или интеграционным gate без отдельного unit test, если они не содержат самостоятельного ветвления, преобразования, инварианта либо ранее найденной регрессии. Существующий frontend coverage gate SHALL использоваться только как anti-regression constraint, а не как основание создавать малоценные тесты. Backend MUST NOT получать общий числовой coverage threshold только ради симметрии или процессного соответствия; такой gate требует отдельного утверждённого обоснования защищаемого риска. + +#### Scenario: Изменяется критический инвариант + +- **WHEN** change меняет безопасность, денежный результат, целостность данных, конкурентное поведение, публичный контракт, критический journey или исправляет регрессию +- **THEN** checklist содержит тест соответствующего уровня, который наблюдаемо подтверждает новый или исправленный результат + +#### Scenario: Добавлен простой служебный скрипт + +- **WHEN** скрипт только последовательно запускает существующие проверяемые команды, не содержит самостоятельной бизнес-логики, ветвления или преобразования данных +- **THEN** отдельный unit test для скрипта не является обязательным, а корректность результата подтверждается выполнением самого локального gate + +#### Scenario: Coverage можно повысить только малоценным тестом + +- **WHEN** новый тест повторял бы декларативную структуру или внутреннее поведение зависимости и не защищал бы самостоятельный риск проекта +- **THEN** агент не создаёт такой тест только ради процента coverage и сохраняет существующий anti-regression threshold + +#### Scenario: Backend не имеет числового coverage threshold + +- **WHEN** обязательные risk-based тесты backend проходят, а отдельный измеримый риск для общего coverage threshold не утверждён +- **THEN** отсутствие глобального числового threshold не считается пробелом и не блокирует change + +### Requirement: Enforceable Engineering Invariant имеет локальную проверку + +Каждое правило, обозначенное как обязательный Enforceable Engineering Invariant, MUST иметь детерминированную non-mutating локальную проверку и MUST блокировать завершение работы при нарушении. Такие инварианты SHALL охватывать применимые правила стиля проекта, статическую корректность, архитектурные границы, публичные контракты, безопасность и критические доменные ограничения. Рекомендация, которую невозможно надёжно проверить локально, MUST быть обозначена как guidance и MUST NOT выдаваться за hard guardrail. Проверка самого hard guardrail MUST иметь evidence, что она отклоняет хотя бы одно контролируемое репрезентативное нарушение; это evidence MUST NOT превращаться в требование unit-тестировать каждый вспомогательный скрипт. + +#### Scenario: Агент пишет код не в стиле проекта + +- **WHEN** изменение нарушает проверяемое правило форматирования, lint, типов, импортных границ или публичного контракта проекта +- **THEN** обязательный локальный gate завершается с ошибкой и работа не считается завершённой + +#### Scenario: Правило является только рекомендацией + +- **WHEN** команда не может определить детерминированную локальную проверку сформулированного предпочтения +- **THEN** правило документируется как guidance, а агент не использует его как самостоятельную причину объявить корректную реализацию невалидной + +#### Scenario: Добавляется новый hard guardrail + +- **WHEN** change объявляет новое правило блокирующим +- **THEN** completion evidence подтверждает как успешный compliant case, так и обнаружение контролируемого representative violation diff --git a/openspec/specs/multi-repository-delivery/spec.md b/openspec/specs/multi-repository-delivery/spec.md new file mode 100644 index 0000000..044a717 --- /dev/null +++ b/openspec/specs/multi-repository-delivery/spec.md @@ -0,0 +1,63 @@ +# multi-repository-delivery Specification + +## Purpose + +Определяет полную поставку одного SDD-изменения через независимые frontend, backend, specs и docs репозитории без потерянных областей, фиктивных коммитов и преждевременного статуса done. + +## Requirements + +### Requirement: Каждый change содержит полный Delivery Map + +Каждый versioned change MUST оценивать delivery areas `frontend`, `backend`, `specs` и `docs` и для каждой области указывать `affected` либо `N/A` с конкретной причиной. `specs` SHALL быть affected для каждого versioned SDD change. `docs` SHALL быть affected для каждой поставленной пользовательской фичи; для технического или процессного change она MAY быть `N/A` только когда фактическая устойчивая документация не изменяется. `frontend` и `backend` SHALL быть affected только когда меняется их поведение, контракт, реализация или обязательный локальный gate. Пустой коммит MUST NOT использоваться для имитации участия незатронутого репозитория. + +#### Scenario: Фича затрагивает клиент и API + +- **WHEN** change меняет пользовательский поток и соответствующее API-поведение +- **THEN** Delivery Map отмечает frontend, backend, specs и docs как affected и описывает ожидаемый результат каждой области без реализации по файлам + +#### Scenario: Область не затронута + +- **WHEN** поведение, контракт, реализация, guardrails и фактическая документация области не меняются +- **THEN** Delivery Map содержит проверяемую причину `N/A`, а delivery не требует пустого коммита этого репозитория + +### Requirement: Частичная multi-repository delivery не считается завершённой + +Change MUST оставаться active, пока каждая affected область не реализована и не прошла свои обязательные локальные gates. Успех одной области MUST NOT позволять архивировать change, если другая affected область отсутствует, не проверена либо не соответствует согласованному поведению. После archive change MUST NOT получить terminal status `done`, пока фактические результаты всех четырёх delivery areas не представлены в Completion Evidence. + +#### Scenario: Backend готов, а frontend ещё не реализован + +- **WHEN** Delivery Map помечает frontend и backend как affected, но завершён и проверен только backend +- **THEN** change остаётся active и не может быть архивирован + +#### Scenario: Все affected области готовы + +- **WHEN** каждая affected область реализована, согласована по общим контрактам и прошла требуемые локальные gates +- **THEN** change может перейти к семантической верификации и archive, после которого формируется Completion Evidence для terminal status + +### Requirement: Completion Evidence содержит только наблюдённые результаты + +Completion Evidence MUST создаваться после выполнения работы и MUST связывать canonical change с commit identifier каждого изменённого Git-репозитория, точными выполненными non-mutating verification commands и их наблюдёнными результатами. Для каждой области с `N/A` evidence SHALL сохранять согласованную причину отсутствия изменения. Planned commands, ожидаемые результаты, незавершённые checklist items и предполагаемые commit identifiers MUST NOT представляться как completion evidence. + +#### Scenario: Change готовится к terminal status + +- **WHEN** implementer заявляет, что multi-repository change завершён +- **THEN** reviewer может сопоставить Delivery Map с фактическими commits, результатами gates и причинами `N/A` для всех четырёх областей + +#### Scenario: Команда ещё не была выполнена + +- **WHEN** verification command только запланирована или её результат не сохранён +- **THEN** она остаётся implementation checklist item и не засчитывается как Completion Evidence + +### Requirement: Общий локальный verifier сохраняет gates репозиториев + +Workspace SHALL предоставлять один non-mutating локальный verification entrypoint для multi-repository delivery. Он MUST проверять совместимость runtime до application gates, запускать канонический gate каждой selected affected области и сохранять их ошибки как blocking result. Общий verifier MUST NOT заменять или ослаблять локальные gates независимых репозиториев. + +#### Scenario: Запущен неподдерживаемый runtime + +- **WHEN** multi-repository verifier запускается с runtime, не соответствующим объявленному проектом контракту +- **THEN** проверка завершается ошибкой до получения вводящего в заблуждение результата application tests + +#### Scenario: Один repository gate завершается ошибкой + +- **WHEN** общий verifier проверяет несколько affected областей и канонический gate одной из них не проходит +- **THEN** общий результат является неуспешным и явно указывает failing area без обхода её локального gate diff --git a/openspec/specs/openspec-authority-and-lifecycle/spec.md b/openspec/specs/openspec-authority-and-lifecycle/spec.md index 3fac624..09027ef 100644 --- a/openspec/specs/openspec-authority-and-lifecycle/spec.md +++ b/openspec/specs/openspec-authority-and-lifecycle/spec.md @@ -5,6 +5,48 @@ ## Requirements +### Requirement: SDD-артефакты имеют непересекающиеся полномочия + +Proposal SHALL выражать причину, намерение, границы и ожидаемый эффект change языком владельца и MUST NOT содержать решения по технологиям, структуре кода, файлам, API или зависимостям. Delta Specs SHALL определять только добавленное, изменённое или удалённое наблюдаемое поведение и инварианты системы без описания изменений кода. Design SHALL объяснять архитектурный способ выполнения утверждённых Specs, существенные решения, риски и альтернативы крупными частями и MUST NOT становиться построчной инструкцией реализации. Tasks SHALL быть implementation checklist, достаточным для выполнения Design и Specs, и MUST NOT содержать ещё не наблюдённые completion results, commit identifiers или post-archive bookkeeping. Completion Evidence SHALL фиксироваться только после фактической реализации и верификации и MUST NOT подменять planning artifact. + +#### Scenario: Product Owner формулирует Proposal + +- **WHEN** владелец описывает требуемое изменение, не зная структуры кода и файлов +- **THEN** Proposal остаётся полноценным утверждаемым намерением без необходимости принимать архитектурные решения + +#### Scenario: Агент подготавливает Tasks + +- **WHEN** Proposal, Delta Specs и Design уже утверждены +- **THEN** Tasks перечисляет конкретные действия реализации и проверки, но не заявляет будущие результаты уже выполненными + +### Requirement: Artifact graph применяет последовательные approval gates + +Versioned SDD change SHALL проходить последовательность `Proposal → Delta Specs → Design → Tasks → Apply`. AI-агент MAY подготовить черновик текущего разрешённого артефакта, но MUST NOT считать его утверждённым самостоятельно или создавать downstream artifact до явного решения Change Owner. Для change, определяющего продуктовое поведение, Change Owner SHALL быть Product Owner; для технического или процессного change — Engineering Owner. Каждый из четырёх planning artifacts MUST существовать и быть утверждён до Apply. + +#### Scenario: Proposal ещё не утверждён + +- **WHEN** AI-агент завершил черновик Proposal, но Change Owner не дал явного согласия +- **THEN** Delta Specs, Design и Tasks остаются недоступны для создания + +#### Scenario: Delta Specs утверждены + +- **WHEN** Change Owner явно подтверждает Delta Specs после утверждённого Proposal +- **THEN** Design становится следующим разрешённым planning artifact, а Tasks и Apply остаются заблокированы + +### Requirement: Изменение upstream artifact требует каскадной проверки + +Изменение утверждённого Proposal MUST инициировать повторную проверку Delta Specs, Design и Tasks; изменение утверждённых Delta Specs MUST инициировать повторную проверку Design и Tasks; изменение утверждённого Design MUST инициировать повторную проверку Tasks. Изменение Tasks MUST NOT неявно менять scope, наблюдаемое поведение или архитектурные решения upstream artifacts; при таком обнаружении workflow SHALL вернуть работу к соответствующему upstream artifact и его approval gate. + +#### Scenario: После Design изменилось намерение + +- **WHEN** владелец меняет scope или ожидаемый эффект Proposal +- **THEN** зависимые Delta Specs, Design и Tasks теряют прежнее подтверждение до повторной согласованной проверки + +#### Scenario: Task вводит новое поведение + +- **WHEN** implementation checklist требует поведение, которого нет в утверждённых Delta Specs +- **THEN** агент не расширяет scope через Tasks и возвращает change к Delta Specs + ### Requirement: Канонический authority OpenSpec задан явно WealthLedger SHALL использовать зарегистрированный store `wealth-ledger-specs` с физическим OpenSpec root `specs/openspec` как единственный поддерживаемый authority для versioned SDD artifacts. Каждый project-owned OpenSpec entrypoint и documented OpenSpec command MUST явно выбирать `--store wealth-ledger-specs`; он MUST NOT выбирать store из ближайшего root, текущей директории или глобального значения по умолчанию машины. @@ -38,13 +80,45 @@ Canonical store и policy расположения artifacts SHALL иметь do - **WHEN** project-owned OpenSpec entrypoint допускает выбор nearest-root или global-default - **THEN** verifier завершается ошибкой и указывает non-compliant entrypoint +### Requirement: OpenSpec tooling имеет проверяемый version contract + +SDD workflow MUST объявлять поддерживаемую версию OpenSpec CLI и проверять фактическую версию до команд, читающих или изменяющих canonical change. Несовместимая либо неопределённая версия MUST давать actionable blocking result и MUST NOT приводить к молчаливому изменению artifact graph, templates или project-owned entrypoints. + +#### Scenario: Версия CLI соответствует контракту + +- **WHEN** агент начинает работу с canonical change поддерживаемой версией OpenSpec +- **THEN** workflow продолжает работу с объявленной схемой и canonical store + +#### Scenario: Версия CLI не соответствует контракту + +- **WHEN** доступная версия OpenSpec не совпадает с объявленным совместимым контрактом +- **THEN** локальная preflight-проверка блокирует SDD-операцию и сообщает ожидаемую и фактическую версии + +### Requirement: Structural и semantic verification являются разными gates + +OpenSpec structural validation SHALL проверять schema, artifact graph и формальную корректность specs, но MUST NOT считаться доказательством соответствия реализации. До terminal status change MUST пройти semantic verification реализации против Proposal, Delta Specs, Design и Tasks, а затем независимый read-only review. Если основной agent entrypoint semantic verification недоступен, workflow SHALL использовать versioned эквивалентную процедуру с теми же входными артефактами, категориями проверки и наблюдаемым evidence. + +#### Scenario: Structural validation прошла без ошибок + +- **WHEN** все planning artifacts формально валидны, но реализация ещё не сопоставлена с ними +- **THEN** change не получает terminal status только на основании structural validation + +#### Scenario: Slash workflow недоступен агенту + +- **WHEN** среда не предоставляет установленный semantic verification entrypoint +- **THEN** агент выполняет документированную эквивалентную read-only проверку и сохраняет её результат вместо пропуска gate + ### Requirement: Archive блокируется незавершёнными tasks -Project-owned archive workflow MUST отклонять archive, пока его `tasks.md` содержит любой unchecked task. Post-archive bookkeeping MUST NOT появляться как unchecked task; он SHALL фиксироваться через детерминированное completion evidence после успешного archive. +Project-owned archive workflow MUST отклонять archive, если отсутствует требуемый planning artifact, любой обязательный artifact не утверждён, `tasks.md` отсутствует или содержит unchecked task, semantic verification либо независимый read-only review не завершены успешно, или любая affected delivery area не реализована и не прошла обязательные pre-archive gates. Workflow MUST NOT предлагать confirmation override для этих blocking conditions. Post-archive bookkeeping MUST NOT появляться как unchecked task; он SHALL фиксироваться через детерминированное Completion Evidence после успешного archive, после чего связанная delivery может получить terminal status. #### Scenario: Change имеет unchecked task - **WHEN** implementer запрашивает archive и остаётся хотя бы один unchecked task -- **THEN** workflow не архивирует change и сообщает incomplete tasks как blocking condition +- **THEN** workflow не архивирует change и сообщает incomplete tasks как blocking condition без возможности confirmation override + +#### Scenario: Change не прошёл required verification +- **WHEN** planning artifacts и tasks завершены, но semantic verification, independent review, implementation или pre-archive gate affected area отсутствуют либо неуспешны +- **THEN** workflow не архивирует change и перечисляет недостающие blocking conditions #### Scenario: Change завершил все tasks -- **WHEN** каждый task отмечен и required verification успешно завершена +- **WHEN** каждый planning artifact утверждён, каждый task отмечен, required verification, implementation и pre-archive gates всех affected areas успешно завершены - **THEN** workflow допускает archive и фиксирует его результат через определённый completion-evidence path без создания post-archive task diff --git a/openspec/specs/project-documentation/spec.md b/openspec/specs/project-documentation/spec.md index 1d4b87d..c3e1bad 100644 --- a/openspec/specs/project-documentation/spec.md +++ b/openspec/specs/project-documentation/spec.md @@ -6,6 +6,20 @@ ## Requirements +### Requirement: Completion Evidence сохраняет фактическое завершение change + +Durable development documentation SHALL хранить для завершённого change ссылку на canonical OpenSpec archive, Delivery Map, commit identifiers изменённых репозиториев, точные выполненные verification commands, их наблюдённые результаты и итог independent read-only review. Completion Evidence MUST создаваться из фактов после выполнения работы, MUST быть доступно из устойчивого index или registry и MUST NOT дублироваться как unchecked task либо планируемый результат внутри archived change. + +#### Scenario: Участник проверяет основание terminal status + +- **WHEN** участник открывает evidence завершённого change в новой сессии +- **THEN** он может проследить связь от change и Delivery Map к фактическим commits, локальным gates и independent review без восстановления контекста из чата + +#### Scenario: Реализация ещё продолжается + +- **WHEN** часть commands, commits или review ещё не существует +- **THEN** documentation не представляет ожидаемые значения как Completion Evidence и change остаётся незавершённым + ### Requirement: Важные архитектурные решения фиксируются в ADR Репозиторий docs SHALL содержать ADR для выбора локального хранилища, API-контракта, gRPC-интеграции T-Bank, хранения T-Bank токенов, устойчивости upstream-вызовов, auth-сессий и frontend-кэша. Каждый ADR MUST описывать контекст, решение и последствия. @@ -39,15 +53,19 @@ - **THEN** registry обновляется с archive path, commits затронутых репозиториев и результатами exact verification commands ### Requirement: Durable documentation is not a parallel SDD store -Репозиторий `docs` SHALL хранить только долговечную architecture, development, feature, audit и remediation documentation вместе с completion evidence. Change-specific requirements, designs, delta specifications и tasks MUST храниться только в canonical OpenSpec store и MUST NOT создаваться как framework-specific planning artifacts в `docs`. +Репозиторий `docs` SHALL хранить только долговечную architecture, development, feature, audit и remediation documentation вместе с completion evidence. Документация MUST описывать фактическое текущее состояние поставленной системы и MUST NOT представлять планируемое или частично реализованное поведение как доступное. Change-specific requirements, proposals, designs, delta specifications и tasks MUST храниться только в canonical OpenSpec store и MUST NOT пересказываться в `docs` как параллельная спецификация в другом формате. Docs SHALL обновляться после реализации и проверки соответствующей области; она MAY ссылаться на canonical OpenSpec change, но MUST сохранять собственную as-built задачу и не копировать его нормативный текст. #### Scenario: Change требует постоянной документации - **WHEN** завершённый change должен оставить устойчивое объяснение решения или evidence -- **THEN** documentation фиксирует реализованное решение или completion evidence и ссылается на canonical OpenSpec change без дублирования его requirements, design или tasks +- **THEN** documentation фиксирует реализованное состояние или completion evidence и ссылается на canonical OpenSpec change без дублирования его requirements, design или tasks #### Scenario: Agent планирует незавершённый change - **WHEN** агент создаёт requirements, design или tasks для незавершённого изменения -- **THEN** он сохраняет их под `specs/openspec` и не создаёт framework-specific planning document в `docs` +- **THEN** он сохраняет их под `specs/openspec` и не создаёт framework-specific planning document или описание будущего поведения в `docs` + +#### Scenario: Реализация расходится с прежней документацией +- **WHEN** проверенный change изменяет поставленное поведение, архитектурную границу или устойчивое решение +- **THEN** affected docs обновляется до фактического текущего состояния до terminal status и не сохраняет прежнее утверждение как действующее ### Requirement: Устойчивая документация имеет доступные фактические точки входа Репозиторий `docs` SHALL содержать indexes архитектуры, разработки и фич, diff --git a/openspec/specs/project-foundation/spec.md b/openspec/specs/project-foundation/spec.md index 5961929..5fc2ce3 100644 --- a/openspec/specs/project-foundation/spec.md +++ b/openspec/specs/project-foundation/spec.md @@ -7,24 +7,11 @@ ## Requirements ### Requirement: Репозитории содержат локальные инструкции для AI-агентов -Система SHALL содержать обзорный `AGENTS.md` в корне рабочей области и -отдельный `AGENTS.md` в репозиториях frontend, backend, specs и docs. -Инструкции MUST описывать назначение области, локальные команды проверки, -границы ответственности и связь с SDD-артефактами. Каждая инструкция MUST -объявлять `wealth-ledger-specs` и `specs/openspec` как canonical OpenSpec -authority, требовать явный `--store wealth-ledger-specs` для поддерживаемых -OpenSpec операций и запрещать versioned framework-specific planning artifacts -вне canonical store. Локальные инструкции MUST направлять агента к durable -documentation, относящейся к его области, и к durable remediation registry, -когда задача связана с findings технического аудита. Backend instructions MUST -различать non-mutating verification commands и явные auto-fix commands. +Система SHALL содержать обзорный `AGENTS.md` в корне рабочей области и отдельный `AGENTS.md` в репозиториях frontend, backend, specs и docs. Корневая инструкция MUST содержать только общую карту workspace, Single Source of Truth, cross-repository workflow и общие hard constraints; локальная инструкция MUST добавлять относящиеся к своему репозиторию команды, проверяемые правила стиля и границ, не копируя изменчивые требования, архитектуру или feature documentation. Инструкции MUST описывать назначение области, канонический non-mutating verification entrypoint, границы ответственности и ссылки на authoritative SDD и durable documentation. Каждая инструкция MUST объявлять `wealth-ledger-specs` и `specs/openspec` как canonical OpenSpec authority, требовать явный `--store wealth-ledger-specs` для поддерживаемых OpenSpec операций и запрещать versioned framework-specific planning artifacts вне canonical store. Локальные инструкции MUST направлять агента к durable documentation, относящейся к его области, и к durable remediation registry, когда задача связана с findings технического аудита. Enforceable Engineering Invariants MUST быть сформулированы как проверяемые обязательные правила; непроверяемые предпочтения MUST быть отделены как guidance. Backend instructions MUST различать non-mutating verification commands и явные auto-fix commands. #### Scenario: Агент начинает работу в отдельном репозитории -- **WHEN** агент открывает любой из репозиториев frontend, backend, specs или - docs -- **THEN** он может определить локальные правила работы, canonical OpenSpec - authority, источник связанных спецификаций и относящийся к области durable - documentation из `AGENTS.md` этого репозитория +- **WHEN** агент открывает любой из репозиториев frontend, backend, specs или docs +- **THEN** он может определить локальные правила работы, канонический verification entrypoint, проверяемый стиль и границы, canonical OpenSpec authority и относящийся к области durable documentation без чтения дублирующих требований #### Scenario: Агент получает audit-derived задачу из отдельного репозитория - **WHEN** задача ссылается на finding технического аудита @@ -33,8 +20,11 @@ documentation, относящейся к его области, и к durable re #### Scenario: Агент выбирает backend quality gate - **WHEN** агент читает backend instructions перед локальной проверкой -- **THEN** он запускает документированные non-mutating lint/typecheck commands - и не получает auto-fix как неявный quality gate +- **THEN** он запускает документированный канонический non-mutating gate и не получает auto-fix как неявную часть verification + +#### Scenario: Архитектурное устройство изменилось +- **WHEN** durable architecture documentation обновлена после поставленного change +- **THEN** `AGENTS.md` продолжает ссылаться на authoritative документ и не требует синхронного копирования его описательного содержимого ### Requirement: Корень рабочей области не хранит delivery-plan файл Корень рабочей области MUST NOT содержать `MVP.md` или другой versioned @@ -72,3 +62,17 @@ Frontend MUST включать TypeScript strict mode для application source #### Scenario: Agent проверяет frontend перед завершением задачи - **WHEN** агент запускает documented frontend verification или его typecheck stage - **THEN** проверка выполняет strict TypeScript compilation application и Vite tooling source и сообщает non-zero exit code при strict diagnostic + +### Requirement: Application repositories имеют канонический локальный gate + +Frontend и backend SHALL предоставлять по одному каноническому non-mutating verification entrypoint, который проверяет все обязательные для соответствующего репозитория Enforceable Engineering Invariants. Каждый entrypoint MUST отклонять неподдерживаемый Node runtime до запуска зависимых application checks, MUST возвращать ненулевой результат при ошибке любого обязательного stage и MUST быть одинаковым для человека, AI-агента и общего workspace verifier. Отдельные auto-fix commands MUST NOT использоваться как verification entrypoint. + +#### Scenario: Агент завершает frontend-изменение + +- **WHEN** агент считает frontend implementation готовой +- **THEN** он запускает один documented frontend gate и получает совокупный non-mutating результат всех обязательных frontend checks + +#### Scenario: Агент запускает backend gate с неверным Node + +- **WHEN** фактическая major/minor версия Node не соответствует объявленному runtime contract backend +- **THEN** gate завершается ошибкой до application checks и сообщает ожидаемую и фактическую версии diff --git a/openspec/specs/user-authentication/spec.md b/openspec/specs/user-authentication/spec.md index aaf2b1b..7f77af7 100644 --- a/openspec/specs/user-authentication/spec.md +++ b/openspec/specs/user-authentication/spec.md @@ -1,3 +1,5 @@ +# user-authentication Specification + ## Purpose Позволяет пользователю создать и восстановить личную сессию, чтобы его данные и будущие подключения к брокеру были доступны только ему. diff --git a/scripts/verify-openspec-authority.sh b/scripts/verify-openspec-authority.sh index 6c91e92..5aca31b 100644 --- a/scripts/verify-openspec-authority.sh +++ b/scripts/verify-openspec-authority.sh @@ -5,6 +5,8 @@ script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P) workspace=${WEALTH_LEDGER_WORKSPACE:-$(cd "$script_dir/../.." && pwd -P)} failures=0 +bash "$script_dir/verify-openspec-version.sh" "$workspace/specs/openspec/.cli-version" + fail() { printf 'FAIL: %s\n' "$1" >&2 failures=$((failures + 1)) @@ -21,6 +23,27 @@ require_file_contains() { fi } +require_schema_edge() { + local file=$1 + local artifact=$2 + local dependency=$3 + + if [[ ! -f "$file" ]]; then + fail "missing required file: ${file#$workspace/}" + return + fi + + if ! awk -v artifact="$artifact" -v dependency="$dependency" ' + $0 == " - id: " artifact { in_artifact = 1; in_requires = 0; next } + in_artifact && /^ - id:/ { in_artifact = 0; in_requires = 0 } + in_artifact && $0 == " requires:" { in_requires = 1; next } + in_artifact && in_requires && $0 == " - " dependency { found = 1 } + END { exit(found ? 0 : 1) } + ' "$file"; then + fail "${file#$workspace/} must require $artifact <- $dependency" + fi +} + store_file="$workspace/specs/.openspec-store/store.yaml" require_file_contains "$store_file" 'id: wealth-ledger-specs' @@ -29,6 +52,27 @@ if [[ ! -d "$canonical_root" ]]; then fail "missing canonical OpenSpec root: specs/openspec" fi +config_file="$canonical_root/config.yaml" +require_file_contains "$config_file" 'schema: wealth-ledger-sdd' + +schema_file="$canonical_root/schemas/wealth-ledger-sdd/schema.yaml" +require_file_contains "$schema_file" 'name: wealth-ledger-sdd' +require_schema_edge "$schema_file" 'specs' 'proposal' +require_schema_edge "$schema_file" 'design' 'specs' +require_schema_edge "$schema_file" 'tasks' 'design' +require_file_contains "$schema_file" 'requires: [ tasks ]' + +if [[ -d "$workspace/specs" ]]; then + if ! schema_validation=$(cd "$workspace/specs" && openspec schema validate wealth-ledger-sdd 2>&1); then + fail "wealth-ledger-sdd schema validation failed: $schema_validation" + fi + if ! schema_source=$(cd "$workspace/specs" && openspec schema which wealth-ledger-sdd --json 2>&1); then + fail "wealth-ledger-sdd schema resolution failed: $schema_source" + elif ! grep -Fq '"source": "project"' <<<"$schema_source"; then + fail "wealth-ledger-sdd must resolve from the project-local schema" + fi +fi + openspec_roots=() while IFS= read -r root; do openspec_roots+=("$root") @@ -72,6 +116,7 @@ entrypoints=( for relative_path in "${entrypoints[@]}"; do file="$workspace/$relative_path" require_file_contains "$file" '--store wealth-ledger-specs' + require_file_contains "$file" 'bash specs/scripts/verify-openspec-version.sh' if [[ -f "$file" ]] && grep -Eqi 'nearest local openspec|global default(store)?|defaultstore|without a store|store: pointer|--store |--store ""|when applicable' "$file"; then fail "$relative_path permits conditional OpenSpec store selection" fi @@ -84,18 +129,75 @@ for relative_path in "${entrypoints[@]}"; do fi done +skill_entrypoints=( + .opencode/skills/openspec-apply-change/SKILL.md + .opencode/skills/openspec-archive-change/SKILL.md + .opencode/skills/openspec-continue-change/SKILL.md + .opencode/skills/openspec-explore/SKILL.md + .opencode/skills/openspec-new-change/SKILL.md + .opencode/skills/openspec-propose/SKILL.md + .opencode/skills/openspec-sync-specs/SKILL.md + .opencode/skills/openspec-verify-change/SKILL.md +) +for relative_path in "${skill_entrypoints[@]}"; do + require_file_contains "$workspace/$relative_path" 'generatedBy: "1.10.0"' +done + +one_artifact_entrypoints=( + .opencode/commands/opsx-continue.md + .opencode/commands/opsx-explore.md + .opencode/commands/opsx-propose.md + .opencode/skills/openspec-continue-change/SKILL.md + .opencode/skills/openspec-explore/SKILL.md + .opencode/skills/openspec-propose/SKILL.md +) +for relative_path in "${one_artifact_entrypoints[@]}"; do + file="$workspace/$relative_path" + require_file_contains "$file" 'Create at most ONE planning artifact per invocation' + require_file_contains "$file" 'STOP for explicit Change Owner approval' + if [[ -f "$file" ]] && grep -Eqi 'generate all artifacts|create every artifact|until every requested artifact|continue until every requested artifact' "$file"; then + fail "$relative_path permits multi-artifact generation without owner checkpoints" + fi +done + +approval_blocker_entrypoints=( + .opencode/commands/opsx-apply.md + .opencode/commands/opsx-archive.md + .opencode/skills/openspec-apply-change/SKILL.md + .opencode/skills/openspec-archive-change/SKILL.md +) +for relative_path in "${approval_blocker_entrypoints[@]}"; do + file="$workspace/$relative_path" + require_file_contains "$file" 'explicit Change Owner approval' + require_file_contains "$file" 'invalidate dependent approvals' +done + archive_entrypoints=( .opencode/commands/opsx-archive.md .opencode/skills/openspec-archive-change/SKILL.md ) for relative_path in "${archive_entrypoints[@]}"; do file="$workspace/$relative_path" + require_file_contains "$file" 'affected delivery area' + require_file_contains "$file" 'semantic verification' + require_file_contains "$file" 'independent read-only review' require_file_contains "$file" 'Do not ask for or accept a confirmation override.' if [[ -f "$file" ]] && grep -Eqi 'archive complete \(with warnings\)|don.t block archive on warnings|archived with [0-9]+ incomplete' "$file"; then fail "$relative_path permits archive with incomplete work" fi done +verification_entrypoints=( + .opencode/commands/opsx-verify.md + .opencode/skills/openspec-verify-change/SKILL.md +) +for relative_path in "${verification_entrypoints[@]}"; do + file="$workspace/$relative_path" + require_file_contains "$file" 'affected delivery area' + require_file_contains "$file" 'workspace verifier' + require_file_contains "$file" 'independent read-only review' +done + for relative_path in docs/superpowers/plans superpowers/plans .superpowers; do if [[ -e "$workspace/$relative_path" ]]; then fail "prohibited framework planning location: $relative_path" diff --git a/scripts/verify-openspec-authority.test.sh b/scripts/verify-openspec-authority.test.sh index 3c53d71..acc7b6c 100644 --- a/scripts/verify-openspec-authority.test.sh +++ b/scripts/verify-openspec-authority.test.sh @@ -21,6 +21,10 @@ write_file() { write_file "specs/.openspec-store/store.yaml" $'version: 1\nid: wealth-ledger-specs' mkdir -p "$fixture/specs/openspec" +write_file "specs/openspec/.cli-version" '1.10.0' +write_file "specs/openspec/config.yaml" 'schema: wealth-ledger-sdd' +mkdir -p "$fixture/specs/openspec/schemas" +cp -R "$script_dir/../openspec/schemas/wealth-ledger-sdd" "$fixture/specs/openspec/schemas/wealth-ledger-sdd" for path in AGENTS.md frontend/AGENTS.md backend/AGENTS.md specs/AGENTS.md docs/AGENTS.md; do write_file "$path" $'OpenSpec store: wealth-ledger-specs\nUse --store wealth-ledger-specs\nSDD artifacts only in specs/openspec\nreferences/** is read-only.' @@ -46,13 +50,36 @@ entrypoints=( ) for path in "${entrypoints[@]}"; do - write_file "$path" 'openspec status --store wealth-ledger-specs' + content=$'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs' + if [[ "$path" == .opencode/skills/* ]]; then + content=$'generatedBy: "1.10.0"\n'"$content" + fi + if [[ "$path" == *continue* || "$path" == *explore* || "$path" == *propose* ]]; then + content="$content"$'\nCreate at most ONE planning artifact per invocation.\nSTOP for explicit Change Owner approval.' + fi + if [[ "$path" == *apply* || "$path" == *archive* ]]; then + content="$content"$'\nRequire explicit Change Owner approval and invalidate dependent approvals after upstream edits.' + fi + write_file "$path" "$content" done -archive_gate='openspec status --store wealth-ledger-specs +archive_gate='bash specs/scripts/verify-openspec-version.sh +openspec status --store wealth-ledger-specs +Require affected delivery area gates, semantic verification and independent read-only review. +Require explicit Change Owner approval and invalidate dependent approvals after upstream edits. Do not ask for or accept a confirmation override.' write_file ".opencode/commands/opsx-archive.md" "$archive_gate" -write_file ".opencode/skills/openspec-archive-change/SKILL.md" "$archive_gate" +write_file ".opencode/skills/openspec-archive-change/SKILL.md" $'generatedBy: "1.10.0"\n'"$archive_gate" + +verification_gate='bash specs/scripts/verify-openspec-version.sh +openspec status --store wealth-ledger-specs +Check every affected delivery area with the workspace verifier and require independent read-only review.' +write_file ".opencode/commands/opsx-verify.md" "$verification_gate" +write_file ".opencode/skills/openspec-verify-change/SKILL.md" $'generatedBy: "1.10.0"\n'"$verification_gate" + +apply_gate='bash specs/scripts/verify-openspec-version.sh +openspec status --store wealth-ledger-specs +Require explicit Change Owner approval and invalidate dependent approvals after upstream edits.' run_verifier() { WEALTH_LEDGER_WORKSPACE="$fixture" bash "$verifier" @@ -60,6 +87,28 @@ run_verifier() { run_verifier +write_file "specs/openspec/.cli-version" '9.9.9' +if run_verifier; then + echo "expected wrong OpenSpec version contract to fail" >&2 + exit 1 +fi +write_file "specs/openspec/.cli-version" '1.10.0' + +write_file "specs/openspec/config.yaml" 'schema: spec-driven' +if run_verifier; then + echo "expected non-project default schema to fail" >&2 + exit 1 +fi +write_file "specs/openspec/config.yaml" 'schema: wealth-ledger-sdd' + +write_file "specs/openspec/schemas/wealth-ledger-sdd/schema.yaml" $'name: wealth-ledger-sdd\nversion: 1' +if run_verifier; then + echo "expected incomplete project schema graph to fail" >&2 + exit 1 +fi +rm -rf "$fixture/specs/openspec/schemas/wealth-ledger-sdd" +cp -R "$script_dir/../openspec/schemas/wealth-ledger-sdd" "$fixture/specs/openspec/schemas/wealth-ledger-sdd" + mkdir -p "$fixture/frontend/openspec" if run_verifier; then echo "expected additional OpenSpec root to fail" >&2 @@ -67,41 +116,62 @@ if run_verifier; then fi rmdir "$fixture/frontend/openspec" -write_file ".opencode/commands/opsx-apply.md" 'Without a store, commands act on the nearest local openspec root.' +write_file ".opencode/commands/opsx-apply.md" $'bash specs/scripts/verify-openspec-version.sh\nWithout a store, commands act on the nearest local openspec root.' if run_verifier; then echo "expected implicit store selection to fail" >&2 exit 1 fi -write_file ".opencode/commands/opsx-apply.md" 'openspec status --store wealth-ledger-specs' +write_file ".opencode/commands/opsx-apply.md" "$apply_gate" -write_file ".opencode/commands/opsx-apply.md" $'openspec status --store wealth-ledger-specs\nFor another store, append --store "" when applicable.' +write_file ".opencode/commands/opsx-apply.md" $'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs\nFor another store, append --store "" when applicable.' if run_verifier; then echo "expected conditional store selection to fail" >&2 exit 1 fi -write_file ".opencode/commands/opsx-apply.md" 'openspec status --store wealth-ledger-specs' +write_file ".opencode/commands/opsx-apply.md" "$apply_gate" -write_file ".opencode/commands/opsx-apply.md" $'openspec status --store wealth-ledger-specs\nRun `openspec status --change "example" --json` before continuing.' +write_file ".opencode/commands/opsx-apply.md" $'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs\nRun `openspec status --change "example" --json` before continuing.' if run_verifier; then echo "expected unscoped OpenSpec invocation to fail" >&2 exit 1 fi -write_file ".opencode/commands/opsx-apply.md" 'openspec status --store wealth-ledger-specs' +write_file ".opencode/commands/opsx-apply.md" "$apply_gate" -write_file ".opencode/commands/opsx-apply.md" $'openspec status --store wealth-ledger-specs\nUse artifact graph (openspec status --change "example" --json) before continuing.' +write_file ".opencode/commands/opsx-apply.md" $'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs\nUse artifact graph (openspec status --change "example" --json) before continuing.' if run_verifier; then echo "expected parenthesized unscoped OpenSpec invocation to fail" >&2 exit 1 fi -write_file ".opencode/commands/opsx-apply.md" 'openspec status --store wealth-ledger-specs' +write_file ".opencode/commands/opsx-apply.md" "$apply_gate" -write_file ".opencode/commands/opsx-archive.md" $'openspec status --store wealth-ledger-specs\nDon\x27t block archive on warnings - just inform and confirm.' +write_file ".opencode/commands/opsx-propose.md" $'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs\nCreate every artifact in the required set.\nSTOP for explicit Change Owner approval.' +if run_verifier; then + echo "expected multi-artifact proposal guidance to fail" >&2 + exit 1 +fi +write_file ".opencode/commands/opsx-propose.md" $'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs\nCreate at most ONE planning artifact per invocation.\nSTOP for explicit Change Owner approval.' + +write_file ".opencode/commands/opsx-archive.md" $'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs\nDon\x27t block archive on warnings - just inform and confirm.' if run_verifier; then echo "expected archive override guidance to fail" >&2 exit 1 fi write_file ".opencode/commands/opsx-archive.md" "$archive_gate" +write_file ".opencode/commands/opsx-archive.md" $'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs\nDo not ask for or accept a confirmation override.' +if run_verifier; then + echo "expected archive without required verification to fail" >&2 + exit 1 +fi +write_file ".opencode/commands/opsx-archive.md" "$archive_gate" + +write_file ".opencode/commands/opsx-verify.md" $'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs' +if run_verifier; then + echo "expected semantic verifier without affected-area review to fail" >&2 + exit 1 +fi +write_file ".opencode/commands/opsx-verify.md" "$verification_gate" + mkdir -p "$fixture/docs/superpowers/plans" if run_verifier; then echo "expected prohibited planning location to fail" >&2 diff --git a/scripts/verify-openspec-version.sh b/scripts/verify-openspec-version.sh new file mode 100755 index 0000000..11041ce --- /dev/null +++ b/scripts/verify-openspec-version.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P) +contract_file=${1:-"$script_dir/../openspec/.cli-version"} + +if [[ ! -f "$contract_file" ]]; then + printf 'OpenSpec version contract is missing: %s\n' "$contract_file" >&2 + exit 1 +fi + +expected_version=$(tr -d '[:space:]' < "$contract_file") +if [[ -z "$expected_version" ]]; then + printf 'OpenSpec version contract is empty: %s\n' "$contract_file" >&2 + exit 1 +fi + +if ! command -v openspec >/dev/null 2>&1; then + printf 'OpenSpec CLI %s is required, but openspec is not available in PATH.\n' "$expected_version" >&2 + exit 1 +fi + +actual_version=$(openspec --version 2>/dev/null | tr -d '\r\n') +if [[ "$actual_version" != "$expected_version" ]]; then + printf 'Unsupported OpenSpec CLI version: expected %s, actual %s.\n' "$expected_version" "${actual_version:-unknown}" >&2 + exit 1 +fi + +printf 'OpenSpec CLI version verified: %s\n' "$actual_version" diff --git a/scripts/verify-workspace-change.sh b/scripts/verify-workspace-change.sh new file mode 100755 index 0000000..5583b00 --- /dev/null +++ b/scripts/verify-workspace-change.sh @@ -0,0 +1,193 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -ne 1 ]]; then + printf 'Usage: %s \n' "${0##*/}" >&2 + exit 2 +fi + +change=$1 +if [[ ! "$change" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then + printf 'Invalid OpenSpec change name: %s\n' "$change" >&2 + exit 2 +fi + +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P) +workspace=$(cd "$script_dir/../.." && pwd -P) +change_dir="$workspace/specs/openspec/changes/$change" +metadata_file="$change_dir/.openspec.yaml" +design_file="$change_dir/design.md" + +for required_file in "$metadata_file" "$design_file"; do + if [[ ! -f "$required_file" ]]; then + printf 'Missing canonical change input: %s\n' "${required_file#$workspace/}" >&2 + exit 1 + fi +done + +areas=(frontend backend specs docs) +affected_flags=(0 0 0 0) +map_statuses=('' '' '' '') +map_reasons=('' '' '' '') +contract_status='' +contract_reason='' + +area_index() { + case "$1" in + frontend) printf '0' ;; + backend) printf '1' ;; + specs) printf '2' ;; + docs) printf '3' ;; + *) return 1 ;; + esac +} + +while IFS= read -r area; do + [[ -n "$area" ]] || continue + if ! index=$(area_index "$area"); then + printf 'Unknown affected area in %s: %s\n' "${metadata_file#$workspace/}" "$area" >&2 + exit 1 + fi + if [[ "${affected_flags[$index]}" -eq 1 ]]; then + printf 'Duplicate affected area in %s: %s\n' "${metadata_file#$workspace/}" "$area" >&2 + exit 1 + fi + affected_flags[$index]=1 +done < <( + awk ' + $0 == "affected_areas:" { in_areas = 1; next } + in_areas && /^ - / { sub(/^ - /, ""); print; next } + in_areas { exit } + ' "$metadata_file" +) + +if [[ "${affected_flags[2]}" -ne 1 ]]; then + printf 'Delivery Map violation: specs must be affected for every versioned change.\n' >&2 + exit 1 +fi + +trim() { + local value=$1 + value=${value#"${value%%[![:space:]]*}"} + value=${value%"${value##*[![:space:]]}"} + printf '%s' "$value" +} + +while IFS='|' read -r _ raw_area raw_status raw_reason _; do + area=$(trim "$raw_area") + case "$area" in + frontend|backend|specs|docs) ;; + *) continue ;; + esac + index=$(area_index "$area") + + if [[ -n "${map_statuses[$index]}" ]]; then + printf 'Delivery Map contains duplicate row for %s.\n' "$area" >&2 + exit 1 + fi + + status=$(trim "$raw_status") + status=${status//\`/} + reason=$(trim "$raw_reason") + map_statuses[$index]=$status + map_reasons[$index]=$reason +done < "$design_file" + +while IFS='|' read -r _ raw_gate raw_status raw_reason _; do + gate=$(trim "$raw_gate") + [[ "$gate" == "runtime-openapi" ]] || continue + if [[ -n "$contract_status" ]]; then + printf 'Contract Gate Decision contains duplicate runtime-openapi row.\n' >&2 + exit 1 + fi + contract_status=$(trim "$raw_status") + contract_status=${contract_status//\`/} + contract_reason=$(trim "$raw_reason") +done < "$design_file" + +for index in 0 1 2 3; do + area=${areas[$index]} + status=${map_statuses[$index]} + reason=${map_reasons[$index]} + if [[ -z "$status" ]]; then + printf 'Delivery Map is missing area: %s\n' "$area" >&2 + exit 1 + fi + + if [[ "${affected_flags[$index]}" -eq 1 ]]; then + if [[ "$status" != "affected" ]]; then + printf 'Delivery Map mismatch: %s is listed as affected in metadata but has status %s.\n' "$area" "$status" >&2 + exit 1 + fi + if [[ -z "$reason" || "$reason" == "-" || "$reason" == "—" || "$reason" == *"