docs(specs): harden OpenSpec authority lifecycle

This commit is contained in:
2026-08-23 17:49:52 +03:00
parent b8a3f96316
commit 51344d4988
18 changed files with 608 additions and 13 deletions
+4 -1
View File
@@ -2,13 +2,14 @@
## Назначение
Репозиторий SDD-артефактов и OpenSpec store: `openspec/`. Все функциональные изменения планируются в `openspec/changes/<change>/` до реализации в frontend или backend.
Репозиторий единственных versioned SDD-артефактов и canonical OpenSpec store: `wealth-ledger-specs` в `specs/openspec` (относительно workspace). Все функциональные изменения планируются в `openspec/changes/<change>/` до реализации в frontend или backend.
## Проверка
```bash
openspec validate <change> --type change --store wealth-ledger-specs
openspec instructions apply --change <change> --json --store wealth-ledger-specs
bash scripts/verify-openspec-authority.sh
```
## Границы
@@ -17,3 +18,5 @@ openspec instructions apply --change <change> --json --store wealth-ledger-specs
- Реализация отмечается в tasks только после выполненной работы. Перед архивированием change проходит `opsx-verify` и получает связанную документацию в `../docs`.
- Не хранить код приложений и долгоживущие ADR в этом репозитории.
- Для задачи по 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 исключением.
@@ -33,5 +33,16 @@
## 6. Верификация и архив
- [x] 6.1 Прогнать `opsx-verify` по change
- [ ] 6.2 Архив change через `openspec archive` и синхронизация delta в main spec
- [ ] 6.3 Закоммитить по репозиториям: specs, docs, backend, frontend
- [x] 6.2 Архив change через `openspec archive` и синхронизация delta в main spec
- [x] 6.3 Закоммитить по репозиториям: specs, docs, backend, frontend
## Сверка evidence — 2026-08-23
Задачи 6.2–6.3 были незакрытыми administrative tasks после фактического archive. Их статус согласован по текущему read-only evidence; эта запись не меняет archive date, implementation files, delta specs или прошлые Git commits.
- `git -C specs show --stat --oneline --summary 6795ee6` — commit `6795ee6` от 2026-08-17 создаёт `openspec/changes/archive/2026-08-17-redesign-position-cards/` и одновременно изменяет `openspec/specs/portfolio-view/spec.md`; это подтверждает archive и sync delta.
- `git -C docs show --stat --oneline --summary c628535` — commit `c628535` от 2026-08-17 обновляет `features/portfolio-view.md`.
- `git -C backend show --stat --oneline --summary 5aa9bd3` — commit `5aa9bd3` от 2026-08-17 содержит ISIN DTO/service/client/spec changes.
- `git -C frontend show --stat --oneline --summary 5168870` — commit `5168870` от 2026-08-17 содержит Position Card, OpenAPI, i18n и tests changes.
В local history отсутствует отдельный terminal transcript вызова `openspec archive`; evidence выше подтверждает его наблюдаемый результат и связанные commits, не приписывая прошлому workflow незафиксированные команды.
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-08-23
@@ -0,0 +1,81 @@
## Контекст
Мотивация приведена в `proposal.md`, а поведенческий контракт — в delta specs. `specs/openspec` уже является единственным project-owned физическим OpenSpec root, но unscoped OpenSpec CLI resolution сейчас зависит от изменяемого machine default. Workspace и четыре независимых репозитория имеют agent instructions, тогда как восемь `.opencode` commands и восемь соответствующих skills сохраняют сгенерированный selection guidance, допускающий nearest-root fallback. Текущие archive instructions также позволяют owner-confirmed archive с incomplete artifacts или tasks.
`docs/development/audit-remediation.md` является durable evidence, а не вторым SDD store. `references/**` содержит импортированные framework plans и должен остаться нетронутым. Archive `2026-08-17-redesign-position-cards` имеет два unchecked lifecycle tasks, поэтому он является historical evidence, противоречащим целевой policy.
## Цели и нецели
**Цели:**
- Сделать каждую supported OpenSpec operation детерминированной из любого project-owned entrypoint.
- Сохранить единственный versioned SDD authority, оставив `docs` durable documentation и evidence.
- Превратить authority и archive rules в read-only, воспроизводимый verification result.
- Убрать incomplete-task исключение из archive и честно согласовать известное historical exception.
**Не входит в scope:**
- Не изменять OpenSpec CLI, глобальную OpenSpec configuration или несвязанные registered stores.
- Не удалять, не перемещать и не нормализовать artifacts под `references/**`.
- Не вводить Superpowers plans, другой planning framework, CI, runtime application changes или external tracker integration.
- Не переписывать прошлые Git commits и не утверждать, что historical lifecycle steps произошли в другую дату.
## Решения
### Canonical store contract заменяет contextual selection
`wealth-ledger-specs` — фиксированный идентификатор store, а `specs/openspec` — его единственный project-owned artifact root. Root, frontend, backend, specs и docs `AGENTS.md` используют одну краткую policy: requirements, design, delta specs, tasks, changes и archives принадлежат только этому store; все OpenSpec commands, читающие или изменяющие change, используют `--store wealth-ledger-specs`.
Восемь `.opencode/commands/opsx-*.md` и восемь `.opencode/skills/openspec-*/SKILL.md` заменят сгенерированные conditional store-selection blocks на блок для WealthLedger. Каждый конкретный OpenSpec invocation в этих project-owned workflows включает фиксированный flag; archive workflow использует тот же fixed selection. `references/**` исключается, поскольку не является project-owned workflow surface.
Сохранение существующих entrypoints не ломает discovery агентов и имена workflows. Опора на `openspec` root pointer или global default отклонена, поскольку они зависят от текущей директории или состояния машины. Удаление entrypoints отклонено, поскольку это ослабит, а не усилит документированный локальный workflow.
### Границы artifacts определяются их lifecycle role
Policy различает SDD state и durable documentation:
- `specs/openspec` владеет mutable и archived versioned SDD state: specs, changes, proposals, designs, delta specs и tasks.
- `docs` владеет durable architecture, development, feature, audit и remediation documentation, включая completion evidence со ссылкой на archive.
- `frontend` и `backend` владеют runtime code и tests; change planning artifacts в них не создаются.
- `references/**` остаётся read-only и исключён из cleanup и policy scanning.
Instructions запретят коммит framework-specific planning/spec/task/design artifacts вне canonical store, явно включая `superpowers/plans`. Запрет относится к параллельным sources of truth, а не к использованию инструмента или временным заметкам в разговоре. Полный запрет любого Markdown вне `specs` отклонён, поскольку он ошибочно запретит durable docs и существующий reference content.
### Repository-local verifier проверяет стабильные policy signals
Change добавит POSIX shell verifier в репозитории `specs` и документированную command, работающую из любого workspace cwd. Script определяет workspace по собственному расположению, не делает writes и сообщает о каждом нарушенном инварианте перед возвратом ненулевого результата.
Он проверит metadata зарегистрированного store и canonical path `specs/openspec`; отсутствие любого дополнительного project-owned `openspec/` directory; явное canonical-store wording и flag в root и четырёх repository `AGENTS.md`; а также compliance фиксированного набора из шестнадцати `.opencode` entrypoint documents. Он отклонит сгенерированные формулировки nearest-root/global-default и известные framework planning locations вне `specs/openspec`, исключая `references/**`, `.git`, dependencies и generated outputs из discovery.
Verifier намеренно является structural guardrail, а не general natural-language classifier для каждого возможного будущего framework. Policy text запрещает все parallel framework artifacts; verifier защищает known paths и entrypoints, которые могут воспроизвести audited failure. Широкое сканирование всего Markdown или всех directories с именем `plan` отклонено, поскольку оно создаст false positives в durable docs и reference material.
### Archive становится hard gate, а evidence фиксируется post-archive, не в task
Project-owned archive command и skill остановятся до sync или move change, если любой required planning artifact незавершён, если отсутствует `tasks.md` или если он содержит `- [ ]`. Owner-confirmation override отсутствует. До archive workflow также требует normal verification evidence; после archive он указывает implementer обновить durable registry/history evidence и выполнить commits затронутых repositories.
Post-archive work не представляется checkbox в change, потому что archive path нельзя фактически подтвердить до успешного move. Registry/history entry фиксирует actual archive path, commit IDs, commands и observed results после этого события. Это жертвует atomic cross-repository bookkeeping, но не позволяет archived change заявлять о completed tasks при известной incomplete work. Archive workflow, автоматически отмечающий произвольную работу, отклонён, поскольку он производил бы вымышленное evidence.
### Historical reconciliation фиксирует current evidence без изменения history
Historical archive `2026-08-17-redesign-position-cards` будет согласован на месте только после того, как read-only evidence установит actual archive path и commits затронутых repositories. Его две lifecycle tasks будут отмечены complete рядом с dated reconciliation note, отличающей original archive от текущей evidence review. Не изменяются implementation files, delta specs, archive date или past commits.
Оставить его без изменений отклонено, поскольку он останется контрпримером policy. Воссоздать change или изменить Git history отклонено, поскольку это скроет фактическую временную линию.
## Риски и компромиссы
- [Будущая OpenSpec command не содержит fixed store flag] → verifier использует фиксированный manifest всех шестнадцати текущих entrypoints и должен расширяться в том же change, который добавляет entrypoint.
- [Новый framework artifact не распознан path-based detection] → instructions задают широкое ограничение, а review и known-location checks verifier дают многоуровневую защиту без false-positive scanning durable docs.
- [Post-archive registry update прервано] → finding остаётся non-terminal, пока его durable evidence не заполнено; в archive не скрывается incomplete task.
- [Historical commits невозможно доказать из local history] → tasks остаются unresolved, а недостающее evidence фиксируется вместо ложного утверждения о complete.
- [Пользователь вручную запускает raw unscoped OpenSpec CLI] → supported commands и instructions остаются scoped; policy не изменяет внешнее поведение CLI.
## План миграции
1. Добавить формулировки canonical authority и artifact boundaries во все project-owned `AGENTS.md`, затем hard-bind шестнадцать `.opencode` entrypoints.
2. Добавить read-only verifier и запустить его из workspace и каждого independent repository context.
3. Заменить archive confirmation branches для incomplete artifacts/tasks на hard failures, потребовать `tasks.md` и задокументировать post-archive evidence sequence.
4. Добавить durable documentation, объясняющую authority/lifecycle contract, и обновить remediation registry: WL-P1-03 и WL-P1-04 получают статус `active` на время change.
5. Согласовать historical archive только по observed Git/OpenSpec evidence; если evidence неполно, не отмечать его tasks complete.
6. Проверить completed change, sync delta specs, архивировать его только при отмеченных tasks, затем добавить actual archive/commit/check evidence в registry и history.
Откат ограничен revert commits, добавляющими policy и instructions. Runtime data, API contract, package dependency или external configuration не мигрируются.
@@ -0,0 +1,29 @@
## Why
Технический аудит подтвердил, что выбор OpenSpec store зависит от текущей директории и изменяемого глобального значения по умолчанию, а archive workflow допускает незакрытые tasks. Это создаёт два источника правды о SDD-работе и позволяет считать change завершённым без полного доказательства выполнения.
## What Changes
- Объявить `wealth-ledger-specs` с физическим root `specs/openspec` единственным поддерживаемым местом для versioned SDD-артефактов WealthLedger.
- Обязать project-owned OpenSpec entrypoints и agent instructions явно использовать `--store wealth-ledger-specs`; удалить поддержку выбора ближайшего root или fallback через глобальное значение по умолчанию.
- Запретить создание и коммит framework-specific planning/spec/task/design артефактов вне `specs/openspec`, включая `superpowers/plans`; сохранить `references/**` как read-only исключение.
- Разделить SDD-состояние и постоянную документацию: `docs` хранит только долговечную документацию и evidence, но не change-specific requirements, design или tasks.
- Сделать archive невозможным при любом незакрытом task и вынести post-archive bookkeeping из `tasks.md` в детерминированный evidence workflow.
- Добавить read-only verifier authority/lifecycle policy и исправить historical incomplete archive `2026-08-17-redesign-position-cards` проверяемыми фактами без переписывания Git-истории.
## Capabilities
### New Capabilities
- `openspec-authority-and-lifecycle`: canonical store, допустимые locations SDD-артефактов, обязательный scoped entrypoint, archive gate и machine-verifiable policy.
### Modified Capabilities
- `project-foundation`: локальные agent instructions должны однозначно направлять SDD-работу в canonical OpenSpec store и исключать параллельные framework artifacts.
- `audit-remediation-workflow`: terminal evidence audit-derived changes должно опираться на archive только после завершения всех tasks и определённого post-archive evidence workflow.
- `project-documentation`: durable docs отделяются от change-specific SDD-artifacts и фиксируют completion evidence без создания второго SDD source of truth.
- `brokerage-account-ledger`: русские нормативные формулировки используют RFC 2119 маркеры, совместимые со strict OpenSpec validation.
## Impact
Затрагиваются `AGENTS.md` в workspace и независимых репозиториях, `.opencode` OpenSpec commands/skills, `specs/openspec` configuration и verification tooling, historical archive и durable development documentation. Runtime-код frontend/backend, API, зависимости и пользовательское поведение не меняются.
@@ -0,0 +1,12 @@
## MODIFIED Requirements
### 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 и условие пересмотра либо ссылку на явное решение владельца.
#### Scenario: Change готовится к завершению
- **WHEN** implementer хочет поставить связанный finding в `done`
- **THEN** все tasks change и требуемая OpenSpec verification завершены до archive, а registry содержит полный набор post-archive evidence
#### Scenario: Риск сознательно не исправляется сейчас
- **WHEN** владелец переносит finding или принимает риск
- **THEN** registry сохраняет причину решения и условия, при которых оно должно быть пересмотрено
@@ -0,0 +1,56 @@
## MODIFIED Requirements
### Requirement: User can retrieve an account ledger
Система MUST предоставлять аутентифицированный журнал только для чтения одного Brokerage Account, принадлежащего текущему User. Журнал MUST содержать только исполненные операции T-Bank и при отсутствии периода по умолчанию охватывать интервал от начала текущего календарного года до момента запроса.
#### Scenario: Получение журнала с периодом по умолчанию
- **WHEN** аутентифицированный User запрашивает журнал принадлежащего ему Brokerage Account без периода
- **THEN** система возвращает его исполненные операции от начала текущего календарного года до момента запроса
#### Scenario: Отклонение недоступного счёта
- **WHEN** аутентифицированный User запрашивает журнал счёта, который не является открытым поддерживаемым счётом, доступным через его T-Bank connection
- **THEN** система возвращает существующий ответ о недоступности счёта и не раскрывает операции
### Requirement: User can browse a filtered ledger
Система MUST позволять User ограничивать журнал включительным периодом дат и любым подмножеством категорий trade, income, tax, fee, transfer, other. Система MUST разбивать упорядоченный результат на страницы с непрозрачным cursor и возвращать признак доступности следующей страницы.
#### Scenario: Фильтрация доходных операций за период
- **WHEN** User запрашивает период дат и категорию income
- **THEN** результат содержит только исполненные доходные операции с датой в пределах этого периода
#### Scenario: Продолжение истории
- **WHEN** User запрашивает cursor следующей страницы, возвращённый предыдущим ответом журнала
- **THEN** система возвращает следующую страницу без повторения записей предыдущей страницы
### Requirement: Ledger entries preserve broker operation meaning
Система MUST представлять одну upstream-операцию одной записью журнала и MUST передавать её timestamp, тип операции, категорию, описание, доступные идентификаторы инструмента, денежную выплату, количество, цену, НКД и комиссию. Денежные поля MUST сохранять исходную валюту и точное десятичное значение.
#### Scenario: Отображение купонной выплаты
- **WHEN** T-Bank возвращает исполненную купонную операцию с выплатой и данными инструмента
- **THEN** запись журнала определяет её как income и передаёт исходную сумму выплаты, валюту и данные инструмента
#### Scenario: Отображение комиссии сделки без синтетической записи
- **WHEN** T-Bank возвращает исполненную сделку, содержащую выплату и комиссию
- **THEN** журнал содержит одну запись сделки с комиссией в качестве её детали
#### Scenario: Отображение движения бумаг без денег
- **WHEN** T-Bank возвращает исполненную операцию, изменяющую состав инструментов, но без денежной выплаты
- **THEN** запись журнала передаёт доступное количество и не содержит искусственной денежной выплаты с нулевым значением
### Requirement: Account overview includes recent ledger events
Обзор счёта MUST показывать пять последних исполненных записей журнала этого счёта и действие перехода к его полному журналу. Неуспешный или пустой запрос последних записей MUST оставаться локальным состоянием блока последних событий и MUST NOT заменять успешно отображённый обзор Portfolio.
#### Scenario: Отображение последних событий
- **WHEN** загружается обзор счёта и его журнал содержит исполненные операции
- **THEN** обзор показывает не более пяти последних записей и ссылку на полный журнал
#### Scenario: Последние записи недоступны
- **WHEN** обзор счёта успешно загружается, но запрос последних записей завершается ошибкой
- **THEN** обзор Portfolio остаётся доступным, а блок последних событий отображает собственное состояние восстановления
### Requirement: Full ledger presents compact rows
Страница полного журнала MUST показывать для каждой записи дату, тип операции, инструмент и денежное изменение в исходной валюте. Она MUST обозначать записи без движения денег и MUST NOT показывать цену или количество.
#### Scenario: Отображение записи только с инструментом
- **WHEN** полный журнал отображает запись без денежной выплаты
- **THEN** страница определяет её как запись без движения денег
@@ -0,0 +1,49 @@
## Purpose
Определяет единственный источник полномочий для OpenSpec и проверяемый жизненный цикл SDD-изменений независимо от текущей директории, глобальной конфигурации или agent framework.
## ADDED Requirements
### 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, текущей директории или глобального значения по умолчанию машины.
#### Scenario: Агент начинает SDD-работу из репозитория приложения
- **WHEN** агент начинает, продолжает, проверяет, синхронизирует или архивирует OpenSpec change из `frontend`, `backend`, `docs` или workspace root
- **THEN** documented workflow явно выбирает `wealth-ledger-specs` и разрешает artifacts под `specs/openspec`
#### Scenario: В окружении есть другой OpenSpec store или значение по умолчанию
- **WHEN** машина имеет другой зарегистрированный OpenSpec store или другое глобальное значение по умолчанию
- **THEN** project-owned entrypoints всё равно используют `wealth-ledger-specs` и не выполняют fallback к другому root
### Requirement: Versioned planning artifacts имеют единственное допустимое расположение
Система SHALL хранить committed OpenSpec specifications, changes, designs, delta specifications, tasks и archives только под `specs/openspec`. Она MUST NOT создавать или коммитить framework-specific planning, specification, task или design artifacts вне этого расположения, включая `superpowers/plans`. Это ограничение MUST NOT изменять или удалять read-only material под `references/**`.
#### Scenario: Агент фиксирует функциональное изменение
- **WHEN** агенту нужно зафиксировать requirements, design decisions или implementation tasks для функционального change
- **THEN** он создаёт versioned SDD artifacts в canonical OpenSpec store и не создаёт parallel framework artifact вне него
#### Scenario: Агент изучает reference material
- **WHEN** агент встречает framework artifacts под `references/**`
- **THEN** он рассматривает их как read-only reference content и не классифицирует их как нарушение policy
### Requirement: Authority policy имеет read-only verifier
Canonical store и policy расположения artifacts SHALL иметь documented read-only verifier. Verifier MUST возвращать ненулевой результат, когда project-owned OpenSpec entrypoint не выбирает canonical store, когда запрещённый project-owned planning artifact существует вне `specs/openspec`, или когда существует дополнительный project-owned `openspec/` root; он MUST исключать `references/**` из проверок расположения artifacts.
#### Scenario: Canonical authority остаётся целостным
- **WHEN** verifier запускается в compliant workspace
- **THEN** он завершается без изменения tracked files и сообщает об успехе
#### Scenario: Entry point вновь допускает неявный выбор store
- **WHEN** project-owned OpenSpec entrypoint допускает выбор nearest-root или global-default
- **THEN** verifier завершается ошибкой и указывает non-compliant entrypoint
### Requirement: Archive блокируется незавершёнными tasks
Project-owned archive workflow MUST отклонять archive, пока его `tasks.md` содержит любой unchecked task. Post-archive bookkeeping MUST NOT появляться как unchecked task; он SHALL фиксироваться через детерминированное completion evidence после успешного archive.
#### Scenario: Change имеет unchecked task
- **WHEN** implementer запрашивает archive и остаётся хотя бы один unchecked task
- **THEN** workflow не архивирует change и сообщает incomplete tasks как blocking condition
#### Scenario: Change завершил все tasks
- **WHEN** каждый task отмечен и required verification успешно завершена
- **THEN** workflow допускает archive и фиксирует его результат через определённый completion-evidence path без создания post-archive task
@@ -0,0 +1,12 @@
## ADDED Requirements
### 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`.
#### 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`
@@ -0,0 +1,12 @@
## MODIFIED 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 remediation registry, когда задача связана с findings технического аудита.
#### Scenario: Агент начинает работу в отдельном репозитории
- **WHEN** агент открывает любой из репозиториев frontend, backend, specs или docs
- **THEN** он может определить локальные правила работы, canonical OpenSpec authority и источник связанных спецификаций из `AGENTS.md` этого репозитория
#### Scenario: Агент получает audit-derived задачу из отдельного репозитория
- **WHEN** задача ссылается на finding технического аудита
- **THEN** локальный `AGENTS.md` указывает на remediation registry и canonical OpenSpec workflow с явным store selection до начала изменения кода
@@ -0,0 +1,42 @@
## 1. Canonical OpenSpec authority
- [x] 1.1 Обновить корневой `AGENTS.md` и `frontend/AGENTS.md`, `backend/AGENTS.md`, `specs/AGENTS.md`, `docs/AGENTS.md`: объявить `wealth-ledger-specs`/`specs/openspec` единственным SDD store, потребовать `--store wealth-ledger-specs`, запретить versioned framework-specific planning artifacts вне store и сохранить исключение `references/**`.
- [x] 1.2 В каждом из восьми `.opencode/commands/opsx-*.md` и восьми `.opencode/skills/openspec-*/SKILL.md` заменить conditional store-selection guidance на fixed `wealth-ledger-specs`; все OpenSpec commands, читающие или изменяющие change, должны содержать `--store wealth-ledger-specs` и не должны допускать nearest-root/global-default fallback.
- [x] 1.3 Изменить `.opencode/commands/opsx-archive.md` и `.opencode/skills/openspec-archive-change/SKILL.md`: блокировать archive без подтверждающего обхода, если отсутствует `tasks.md`, любой planning artifact не `done`/`skipped` или в tasks есть `- [ ]`; описать post-archive evidence и commits как действие после archive, не как task change.
## 2. Read-only authority verifier
- [x] 2.1 Создать `specs/scripts/verify-openspec-authority.sh`, который по собственному расположению определяет workspace, не делает writes и проверяет `specs/.openspec-store/store.yaml`, единственный project-owned `specs/openspec`, пять `AGENTS.md`, все шестнадцать `.opencode` entrypoints, отсутствие generated fallback wording и известных framework planning locations вне store; исключить `references/**`, `.git`, dependencies и generated outputs.
- [x] 2.2 Добавить в verifier понятные сообщения для каждого нарушенного инварианта и ненулевой exit status; success path должен сообщать проверенное canonical authority без изменения tracked files.
- [x] 2.3 Добавить в `specs/AGENTS.md` documented command verifier и выполнить read-only проверки success path, дополнительного `openspec/` root, неявного entrypoint и запрещённого planning location на временных fixtures, не изменяя project-owned tracked files.
## 3. Durable documentation и remediation state
- [x] 3.1 Создать в `docs/development` краткую durable documentation authority/lifecycle contract: границы `specs/openspec`, `docs`, application repos и `references/**`; объяснить, что requirements, design и tasks не дублируются вне canonical store.
- [x] 3.2 Добавить документ в `docs/development/README.md` и убедиться, что он ссылается на canonical OpenSpec store, а не создаёт второй change-specific SDD artifact.
- [x] 3.3 Обновить `docs/development/audit-remediation.md`: сделать `harden-openspec-authority-and-lifecycle` active change для WL-P1-03/WL-P1-04 и убрать его из формулировки «ещё не создан», не помечая findings как `done` до фактического archive evidence.
## 4. Historical archive reconciliation
- [x] 4.1 Собрать read-only evidence из OpenSpec archive и Git history specs, docs, backend и frontend для `2026-08-17-redesign-position-cards`; установить фактические archive path и commits либо документировать недостающий факт.
- [x] 4.2 Только если evidence подтверждено, отметить tasks 6.2 и 6.3 archived change как complete и добавить dated reconciliation note с exact commands, observed results и различием между исходным archive и текущей проверкой; не менять implementation files, delta specs, archive date или историю Git.
## 5. Pre-archive verification
- [x] 5.1 Запустить authority verifier из workspace root и из `frontend`, `backend`, `specs` и `docs`; зафиксировать в change точные команды и observed results для дальнейшего completion evidence.
- [x] 5.2 Нормализовать RFC 2119 маркеры в `brokerage-account-ledger` через delta-spec без изменения требований или сценариев; выполнить `openspec validate harden-openspec-authority-and-lifecycle --type change --strict --store wealth-ledger-specs`, `openspec validate --specs --strict --store wealth-ledger-specs` и `git diff --check` в каждом затронутом Git repository; устранить все blocking results.
- [x] 5.3 Выполнить независимый read-only review delta specs, policy boundaries, archive gate, verifier exclusions и historical reconciliation; подтвердить, что tasks не содержат post-archive bookkeeping или commit/registry-completion checkbox.
## Pre-archive verification evidence — 2026-08-23
- `bash specs/scripts/verify-openspec-authority.sh` из workspace root — `OpenSpec authority verified: wealth-ledger-specs at specs/openspec`.
- `cd frontend && bash ../specs/scripts/verify-openspec-authority.sh` — success с тем же результатом.
- `cd backend && bash ../specs/scripts/verify-openspec-authority.sh` — success с тем же результатом.
- `cd specs && bash scripts/verify-openspec-authority.sh` — success с тем же результатом.
- `cd docs && bash ../specs/scripts/verify-openspec-authority.sh` — success с тем же результатом.
- `bash specs/scripts/verify-openspec-authority.test.sh` — success; fixture подтверждает success path, дополнительный project-owned OpenSpec root, неявный store selection (включая вызов в скобках), conditional `--store "<id>"`, archive override wording, запрещённый `docs/superpowers/plans` и исключение `references/**`.
- `openspec validate harden-openspec-authority-and-lifecycle --type change --strict --store wealth-ledger-specs` — `Change 'harden-openspec-authority-and-lifecycle' is valid`.
- Первый запуск `openspec validate --specs --strict --store wealth-ledger-specs` выявил baseline `brokerage-account-ledger`: strict validator требует RFC 2119 `SHALL` или `MUST`, тогда как main spec использовала русское «ДОЛЖНА». По явному решению владельца change получил delta-spec, нормализующий только маркеры без изменения requirements или scenarios.
- Повторный `openspec validate --specs --strict --store wealth-ledger-specs` — 14 passed, 0 failed.
- `git diff --check` в frontend, backend, specs и docs — exit 0.
- Независимый read-only review 2026-08-23 — Critical/Important findings отсутствуют; проверены все 16 `.opencode` entrypoints, hard archive gate, exclusions verifier и historical reconciliation.
@@ -29,11 +29,11 @@
- **THEN** агент продолжает связанный change и не создаёт второй remediation change без явного решения владельца
### Requirement: Terminal status подтверждён проверяемым evidence
Registry SHALL NOT представлять finding как `done` без даты, archive path связанного OpenSpec change, commit identifiers для каждого затронутого Git-репозитория и точных non-mutating verification commands с результатами. Статусы `deferred` и `accepted` MUST содержать дату, rationale и условие пересмотра либо ссылку на явное решение владельца.
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 и условие пересмотра либо ссылку на явное решение владельца.
#### Scenario: Change готовится к завершению
- **WHEN** implementer хочет поставить связанный finding в `done`
- **THEN** registry содержит полный набор evidence, а tasks change и требуемая OpenSpec verification завершены до обновления статуса
- **THEN** все tasks change и требуемая OpenSpec verification завершены до archive, а registry содержит полный набор post-archive evidence
#### Scenario: Риск сознательно не исправляется сейчас
- **WHEN** владелец переносит finding или принимает риск
@@ -7,7 +7,7 @@
## Requirements
### Requirement: User can retrieve an account ledger
Система ДОЛЖНА предоставлять аутентифицированный журнал только для чтения одного Brokerage Account, принадлежащего текущему User. Журнал ДОЛЖЕН содержать только исполненные операции T-Bank и при отсутствии периода по умолчанию охватывать интервал от начала текущего календарного года до момента запроса.
Система MUST предоставлять аутентифицированный журнал только для чтения одного Brokerage Account, принадлежащего текущему User. Журнал MUST содержать только исполненные операции T-Bank и при отсутствии периода по умолчанию охватывать интервал от начала текущего календарного года до момента запроса.
#### Scenario: Получение журнала с периодом по умолчанию
- **WHEN** аутентифицированный User запрашивает журнал принадлежащего ему Brokerage Account без периода
@@ -18,7 +18,7 @@
- **THEN** система возвращает существующий ответ о недоступности счёта и не раскрывает операции
### Requirement: User can browse a filtered ledger
Система ДОЛЖНА позволять User ограничивать журнал включительным периодом дат и любым подмножеством категорий trade, income, tax, fee, transfer, other. Система ДОЛЖНА разбивать упорядоченный результат на страницы с непрозрачным cursor и возвращать признак доступности следующей страницы.
Система MUST позволять User ограничивать журнал включительным периодом дат и любым подмножеством категорий trade, income, tax, fee, transfer, other. Система MUST разбивать упорядоченный результат на страницы с непрозрачным cursor и возвращать признак доступности следующей страницы.
#### Scenario: Фильтрация доходных операций за период
- **WHEN** User запрашивает период дат и категорию income
@@ -29,7 +29,7 @@
- **THEN** система возвращает следующую страницу без повторения записей предыдущей страницы
### Requirement: Ledger entries preserve broker operation meaning
Система ДОЛЖНА представлять одну upstream-операцию одной записью журнала и ДОЛЖНА передавать её timestamp, тип операции, категорию, описание, доступные идентификаторы инструмента, денежную выплату, количество, цену, НКД и комиссию. Денежные поля ДОЛЖНЫ сохранять исходную валюту и точное десятичное значение.
Система MUST представлять одну upstream-операцию одной записью журнала и MUST передавать её timestamp, тип операции, категорию, описание, доступные идентификаторы инструмента, денежную выплату, количество, цену, НКД и комиссию. Денежные поля MUST сохранять исходную валюту и точное десятичное значение.
#### Scenario: Отображение купонной выплаты
- **WHEN** T-Bank возвращает исполненную купонную операцию с выплатой и данными инструмента
@@ -44,7 +44,7 @@
- **THEN** запись журнала передаёт доступное количество и не содержит искусственной денежной выплаты с нулевым значением
### Requirement: Account overview includes recent ledger events
Обзор счёта ДОЛЖЕН показывать пять последних исполненных записей журнала этого счёта и действие перехода к его полному журналу. Неуспешный или пустой запрос последних записей ДОЛЖЕН оставаться локальным состоянием блока последних событий и НЕ ДОЛЖЕН заменять успешно отображённый обзор Portfolio.
Обзор счёта MUST показывать пять последних исполненных записей журнала этого счёта и действие перехода к его полному журналу. Неуспешный или пустой запрос последних записей MUST оставаться локальным состоянием блока последних событий и MUST NOT заменять успешно отображённый обзор Portfolio.
#### Scenario: Отображение последних событий
- **WHEN** загружается обзор счёта и его журнал содержит исполненные операции
@@ -55,7 +55,7 @@
- **THEN** обзор Portfolio остаётся доступным, а блок последних событий отображает собственное состояние восстановления
### Requirement: Full ledger presents compact rows
Страница полного журнала ДОЛЖНА показывать для каждой записи дату, тип операции, инструмент и денежное изменение в исходной валюте. Она ДОЛЖНА обозначать записи без движения денег и НЕ ДОЛЖНА показывать цену или количество.
Страница полного журнала MUST показывать для каждой записи дату, тип операции, инструмент и денежное изменение в исходной валюте. Она MUST обозначать записи без движения денег и MUST NOT показывать цену или количество.
#### Scenario: Отображение записи только с инструментом
- **WHEN** полный журнал отображает запись без денежной выплаты
@@ -0,0 +1,50 @@
# openspec-authority-and-lifecycle Specification
## Purpose
Определяет единственный источник полномочий для OpenSpec и проверяемый жизненный цикл SDD-изменений независимо от текущей директории, глобальной конфигурации или agent framework.
## Requirements
### 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, текущей директории или глобального значения по умолчанию машины.
#### Scenario: Агент начинает SDD-работу из репозитория приложения
- **WHEN** агент начинает, продолжает, проверяет, синхронизирует или архивирует OpenSpec change из `frontend`, `backend`, `docs` или workspace root
- **THEN** documented workflow явно выбирает `wealth-ledger-specs` и разрешает artifacts под `specs/openspec`
#### Scenario: В окружении есть другой OpenSpec store или значение по умолчанию
- **WHEN** машина имеет другой зарегистрированный OpenSpec store или другое глобальное значение по умолчанию
- **THEN** project-owned entrypoints всё равно используют `wealth-ledger-specs` и не выполняют fallback к другому root
### Requirement: Versioned planning artifacts имеют единственное допустимое расположение
Система SHALL хранить committed OpenSpec specifications, changes, designs, delta specifications, tasks и archives только под `specs/openspec`. Она MUST NOT создавать или коммитить framework-specific planning, specification, task или design artifacts вне этого расположения, включая `superpowers/plans`. Это ограничение MUST NOT изменять или удалять read-only material под `references/**`.
#### Scenario: Агент фиксирует функциональное изменение
- **WHEN** агенту нужно зафиксировать requirements, design decisions или implementation tasks для функционального change
- **THEN** он создаёт versioned SDD artifacts в canonical OpenSpec store и не создаёт parallel framework artifact вне него
#### Scenario: Агент изучает reference material
- **WHEN** агент встречает framework artifacts под `references/**`
- **THEN** он рассматривает их как read-only reference content и не классифицирует их как нарушение policy
### Requirement: Authority policy имеет read-only verifier
Canonical store и policy расположения artifacts SHALL иметь documented read-only verifier. Verifier MUST возвращать ненулевой результат, когда project-owned OpenSpec entrypoint не выбирает canonical store, когда запрещённый project-owned planning artifact существует вне `specs/openspec`, или когда существует дополнительный project-owned `openspec/` root; он MUST исключать `references/**` из проверок расположения artifacts.
#### Scenario: Canonical authority остаётся целостным
- **WHEN** verifier запускается в compliant workspace
- **THEN** он завершается без изменения tracked files и сообщает об успехе
#### Scenario: Entry point вновь допускает неявный выбор store
- **WHEN** project-owned OpenSpec entrypoint допускает выбор nearest-root или global-default
- **THEN** verifier завершается ошибкой и указывает non-compliant entrypoint
### Requirement: Archive блокируется незавершёнными tasks
Project-owned archive workflow MUST отклонять archive, пока его `tasks.md` содержит любой unchecked task. Post-archive bookkeeping MUST NOT появляться как unchecked task; он SHALL фиксироваться через детерминированное completion evidence после успешного archive.
#### Scenario: Change имеет unchecked task
- **WHEN** implementer запрашивает archive и остаётся хотя бы один unchecked task
- **THEN** workflow не архивирует change и сообщает incomplete tasks как blocking condition
#### Scenario: Change завершил все tasks
- **WHEN** каждый task отмечен и required verification успешно завершена
- **THEN** workflow допускает archive и фиксирует его результат через определённый completion-evidence path без создания post-archive task
@@ -37,3 +37,14 @@
#### Scenario: Завершён audit-derived change
- **WHEN** связанный OpenSpec change архивирован после успешной проверки
- **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`.
#### 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`
+3 -3
View File
@@ -7,15 +7,15 @@
## Requirements
### Requirement: Репозитории содержат локальные инструкции для AI-агентов
Система SHALL содержать обзорный `AGENTS.md` в корне рабочей области и отдельный `AGENTS.md` в репозиториях frontend, backend, specs и docs. Инструкции MUST описывать назначение области, локальные команды проверки, границы ответственности и связь с SDD-артефактами. Локальные инструкции MUST направлять агента к durable remediation registry, когда задача связана с findings технического аудита.
Система 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 remediation registry, когда задача связана с findings технического аудита.
#### Scenario: Агент начинает работу в отдельном репозитории
- **WHEN** агент открывает любой из репозиториев frontend, backend, specs или docs
- **THEN** он может определить локальные правила работы и источник связанных спецификаций из `AGENTS.md` этого репозитория
- **THEN** он может определить локальные правила работы, canonical OpenSpec authority и источник связанных спецификаций из `AGENTS.md` этого репозитория
#### Scenario: Агент получает audit-derived задачу из отдельного репозитория
- **WHEN** задача ссылается на finding технического аудита
- **THEN** локальный `AGENTS.md` указывает на remediation registry и canonical OpenSpec workflow до начала изменения кода
- **THEN** локальный `AGENTS.md` указывает на remediation registry и canonical OpenSpec workflow с явным store selection до начала изменения кода
### Requirement: Локальный план MVP не является источником спецификации
Система SHALL содержать корневой локальный `MVP.md` с границами MVP, принятыми решениями, порядком поставок и критериями готовности. Требования к функциональности MUST храниться в OpenSpec, а устойчивая документация MUST храниться в репозитории docs.
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/env bash
set -euo pipefail
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)
workspace=${WEALTH_LEDGER_WORKSPACE:-$(cd "$script_dir/../.." && pwd -P)}
failures=0
fail() {
printf 'FAIL: %s\n' "$1" >&2
failures=$((failures + 1))
}
require_file_contains() {
local file=$1
local text=$2
if [[ ! -f "$file" ]]; then
fail "missing required file: ${file#$workspace/}"
elif ! grep -Fq -- "$text" "$file"; then
fail "${file#$workspace/} must contain: $text"
fi
}
store_file="$workspace/specs/.openspec-store/store.yaml"
require_file_contains "$store_file" 'id: wealth-ledger-specs'
canonical_root="$workspace/specs/openspec"
if [[ ! -d "$canonical_root" ]]; then
fail "missing canonical OpenSpec root: specs/openspec"
fi
openspec_roots=()
while IFS= read -r root; do
openspec_roots+=("$root")
done < <(
find "$workspace" \
\( -path "$workspace/references" -o -path "$workspace/.git" -o -path '*/node_modules' -o -path '*/dist' -o -path '*/coverage' \) -prune -o \
-type d -name openspec -print | sort
)
if [[ ${#openspec_roots[@]} -ne 1 || ${openspec_roots[0]:-} != "$canonical_root" ]]; then
fail "expected exactly one project-owned OpenSpec root at specs/openspec"
fi
agent_files=(AGENTS.md frontend/AGENTS.md backend/AGENTS.md specs/AGENTS.md docs/AGENTS.md)
for relative_path in "${agent_files[@]}"; do
file="$workspace/$relative_path"
require_file_contains "$file" 'wealth-ledger-specs'
require_file_contains "$file" '--store wealth-ledger-specs'
require_file_contains "$file" 'specs/openspec'
done
entrypoints=(
.opencode/commands/opsx-apply.md
.opencode/commands/opsx-archive.md
.opencode/commands/opsx-continue.md
.opencode/commands/opsx-explore.md
.opencode/commands/opsx-new.md
.opencode/commands/opsx-propose.md
.opencode/commands/opsx-sync.md
.opencode/commands/opsx-verify.md
.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 "${entrypoints[@]}"; do
file="$workspace/$relative_path"
require_file_contains "$file" '--store wealth-ledger-specs'
if [[ -f "$file" ]] && grep -Eqi 'nearest local openspec|global default(store)?|defaultstore|without a store|store: pointer|--store <id>|--store "<id>"|when applicable' "$file"; then
fail "$relative_path permits conditional OpenSpec store selection"
fi
if [[ -f "$file" ]]; then
while IFS= read -r line; do
if [[ $line =~ (^|[^[:alnum:]_])openspec[[:space:]]+(new[[:space:]]+change[[:space:]]+|status[[:space:]]+|instructions[[:space:]]+|list[[:space:]]+|show[[:space:]]+|validate[[:space:]]+|archive[[:space:]]+|doctor[[:space:]]+|context[[:space:]]+|schemas[[:space:]]+|view[[:space:]]+) ]] && [[ $line != *'--store wealth-ledger-specs'* ]]; then
fail "$relative_path contains an unscoped OpenSpec invocation: $line"
fi
done < "$file"
fi
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" '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
for relative_path in docs/superpowers/plans superpowers/plans .superpowers; do
if [[ -e "$workspace/$relative_path" ]]; then
fail "prohibited framework planning location: $relative_path"
fi
done
if [[ $failures -gt 0 ]]; then
exit 1
fi
printf 'OpenSpec authority verified: wealth-ledger-specs at specs/openspec\n'
+116
View File
@@ -0,0 +1,116 @@
#!/usr/bin/env bash
set -euo pipefail
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)
verifier="$script_dir/verify-openspec-authority.sh"
if [[ ! -f "$verifier" ]]; then
echo "expected verifier at $verifier" >&2
exit 1
fi
fixture=$(mktemp -d)
trap 'rm -rf "$fixture"' EXIT
write_file() {
local relative_path=$1
local content=$2
mkdir -p "$fixture/$(dirname "$relative_path")"
printf '%s\n' "$content" > "$fixture/$relative_path"
}
write_file "specs/.openspec-store/store.yaml" $'version: 1\nid: wealth-ledger-specs'
mkdir -p "$fixture/specs/openspec"
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.'
done
entrypoints=(
.opencode/commands/opsx-apply.md
.opencode/commands/opsx-archive.md
.opencode/commands/opsx-continue.md
.opencode/commands/opsx-explore.md
.opencode/commands/opsx-new.md
.opencode/commands/opsx-propose.md
.opencode/commands/opsx-sync.md
.opencode/commands/opsx-verify.md
.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 path in "${entrypoints[@]}"; do
write_file "$path" 'openspec status --store wealth-ledger-specs'
done
archive_gate='openspec status --store wealth-ledger-specs
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"
run_verifier() {
WEALTH_LEDGER_WORKSPACE="$fixture" bash "$verifier"
}
run_verifier
mkdir -p "$fixture/frontend/openspec"
if run_verifier; then
echo "expected additional OpenSpec root to fail" >&2
exit 1
fi
rmdir "$fixture/frontend/openspec"
write_file ".opencode/commands/opsx-apply.md" 'Without 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" $'openspec status --store wealth-ledger-specs\nFor another store, append --store "<id>" 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" $'openspec 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" $'openspec 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-archive.md" $'openspec 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"
mkdir -p "$fixture/docs/superpowers/plans"
if run_verifier; then
echo "expected prohibited planning location to fail" >&2
exit 1
fi
rmdir "$fixture/docs/superpowers/plans"
rmdir "$fixture/docs/superpowers"
mkdir -p "$fixture/references/example/superpowers/plans"
run_verifier
echo "verify-openspec-authority tests passed"