24 KiB
Context
Мотивация и границы изменения зафиксированы в 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 на:
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
.opencodeprojection не 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
- Зафиксировать OpenSpec 1.10.0 contract и добавить preflight, не меняя schema текущего change.
- Создать native fork
wealth-ledger-sdd, изменить dependency graph/templates, пройти schema validation и только затем сделать его default в config. - Обновить local agent entrypoints через staged 1.10 generation, сохранить fixed-store и hard-archive overlays и доказать authority verifier положительным и representative negative cases.
- Ввести repo-owned runtime/canonical gates и workspace dispatcher; сначала подтвердить controlled Node mismatch, затем выполнить полные gates под Node 22.
- Обновить governance docs, ADR, audit snapshot/registry, indexes, AGENTS и onboarding; исправить только подтверждённые stale statements.
- Выполнить structural validation, все affected repo gates, runtime OpenAPI comparison, semantic verification и independent read-only review.
- После успешного 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 решением.