docs: record AI governance audit

This commit is contained in:
2026-08-24 19:55:28 +03:00
parent eb69300ebe
commit 1944f2fc97
21 changed files with 1764 additions and 44 deletions
+1
View File
@@ -0,0 +1 @@
node_modules/
+5
View File
@@ -0,0 +1,5 @@
{
"config": {
"MD013": false
}
}
+1
View File
@@ -0,0 +1 @@
22
+18 -12
View File
@@ -1,21 +1,27 @@
# Docs
## Назначение
## Назначение и authority
Репозиторий постоянной документации WealthLedger. Функциональные изменения планируются в `../specs/openspec` до реализации; docs фиксирует согласованные и фактически реализованные решения.
Этот репозиторий хранит durable as-built документацию WealthLedger. Canonical OpenSpec store — `wealth-ledger-specs` в `../specs/openspec`; OpenSpec commands, читающие или изменяющие change, всегда выполняются с `--store wealth-ledger-specs`. Proposal, Delta Specs, Design, Tasks и другие versioned planning artifacts вне canonical store запрещены, включая `superpowers/plans`; `../references/**` read-only.
## Проверка
Docs обновляется до фактического проверенного состояния affected change и не представляет planned behavior как поставленное. Artifact ownership и Completion Evidence определены в [`development/engineering-governance.md`](development/engineering-governance.md); audit-derived работа начинается с [`development/audit-remediation.md`](development/audit-remediation.md).
## Canonical gate
Node 22 обязателен. После lockfile install:
```bash
git status --short
bash ../specs/scripts/verify-runtime-openapi.sh
npm ci
npm run verify
```
## Границы
Gate non-mutating и запускает runtime preflight, committed Markdown rules и `git diff --check`. Auto-fix и network/browser link checking в gate не входят; local links affected documentation проверяются scoped review.
- `adr/` - долгоживущие решения, `architecture/` - устройство системы, `development/` - процесс разработки, `features/` - фактическое поведение завершенных фич.
- Перед изменением фактического описания системы сверяться с [`architecture/system-overview.md`](architecture/system-overview.md) и [`architecture/domain-glossary.md`](architecture/domain-glossary.md); development-документы индексируются в [`development/README.md`](development/README.md).
- Для диаграмм использовать Mermaid в Markdown. Feature-документация описывает пользовательский поток, API-сценарий и ограничения.
- Не хранить OpenSpec-артефакты, code приложений или секреты; requirements, design, delta-specs и tasks остаются только в `../specs/openspec`.
- Не создавать и не коммитить framework-specific planning/spec/task/design artifacts, включая `superpowers/plans`; `../references/**` остаётся read-only исключением.
- Для задачи по Audit ID, продолжения remediation или выбора следующего улучшения сначала прочитать [`development/audit-remediation.md`](development/audit-remediation.md); canonical OpenSpec store — `wealth-ledger-specs` в `../specs/openspec`, а OpenSpec commands, читающие или изменяющие change, выполнять с `--store wealth-ledger-specs`.
## Boundaries
- `architecture/` — текущее устройство, `features/` — поставленное поведение, `adr/` — устойчивые решения, `development/` — процесс и Completion Evidence, `audits/` — immutable snapshots.
- Перед изменением current state сверяться с [`architecture/system-overview.md`](architecture/system-overview.md) и [`architecture/domain-glossary.md`](architecture/domain-glossary.md); indexes должны вести к новым документам.
- Feature docs описывают фактический поток, API и ограничения, но не повторяют OpenSpec requirements/design/tasks.
- Для диаграмм использовать Mermaid в Markdown. Не хранить application code, secrets или competing SDD artifacts.
Markdown lint и whitespace checks — hard guardrails. Стилистические пожелания без локального checker являются guidance.
+1 -1
View File
@@ -18,4 +18,4 @@ flowchart LR
## Consequences
Контроль секретов, повторов и лимитов централизован на сервере. Реализация boundary будет добавлена будущим OpenSpec change подключения T-Bank.
Контроль секретов, повторов и лимитов централизован на сервере. Boundary реализована и используется поставленными сценариями; текущее API, resilience и ограничения описаны в [Подключении T-Bank](../features/tbank-connection.md).
+1 -1
View File
@@ -12,4 +12,4 @@
## Consequences
Ключ обязателен только в server environment и не логируется. Ротация ключей, схема хранения и реализация будут добавлены в будущем change подключения T-Bank.
Ключ обязателен только в server environment и не логируется. AES-256-GCM storage и per-user connection реализованы; current-state contract и ограничение отсутствующей ротации ключа описаны в [Подключении T-Bank](../features/tbank-connection.md).
+1 -1
View File
@@ -12,4 +12,4 @@ Access token живёт 15 минут только в памяти frontend. Rot
## Consequences
Перезагрузка страницы требует обновления access token через cookie-сессию. Полная реализация сессий, хранилища и отзыва будет добавлена change авторизации.
Перезагрузка страницы восстанавливает access token через cookie-сессию. Rotating sessions, logout и bounded revocation model реализованы; access token остаётся действительным не более 15 минут без database lookup на каждый запрос. Текущее поведение описано в [Аутентификации](../features/authentication.md).
+2 -2
View File
@@ -8,8 +8,8 @@
## Decision
React Query запрашивает серверные данные только при открытии соответствующего экрана. Refetch по возврату фокуса отключён, обновление запускается пользователем вручную; backend TTL-кэш остаётся защитой от дублирующих запросов.
React Query запрашивает серверные данные при открытии соответствующего экрана и не делает refetch при возврате фокуса. После `staleTime` повторное открытие может запустить background refetch; последний успешный cached snapshot остаётся видимым вместе с отдельным pending или error feedback. Backend cache применяется только там, где он явно описан соответствующей feature.
## Consequences
Пользователь может видеть данные до ручного обновления или следующего открытия экрана. Live-обновления и иные триггеры появятся только при подтверждённой продуктовой необходимости.
Пользователь может видеть cached snapshot до успешного background response, а ошибка обновления не превращает известные данные в пустой экран. Конкретные freshness intervals и UI-поведение описаны в [Brokerage Accounts](../features/brokerage-accounts.md) и [Portfolio](../features/portfolio-view.md). Live updates и focus-triggered refetch требуют отдельной продуктовой необходимости.
@@ -0,0 +1,19 @@
---
status: accepted
---
# Native OpenSpec SDD и минимальная local orchestration
WealthLedger использует project-local schema `wealth-ledger-sdd` OpenSpec 1.10 с последовательностью `Proposal → Delta Specs → Design → Tasks → Apply` и тонкий dispatcher существующих repository gates. Это сохраняет один lifecycle authority в `specs/openspec`, выражает проектные approval boundaries нативными extension points и не вводит второй workflow engine или monorepo control plane для четырёх независимых Git-репозиториев.
## Рассмотренные варианты
- Встроенная `spec-driven` schema отклонена: она не выражает обязательный переход Specs перед Design и не задаёт Delivery Map или проектные роли артефактов.
- Отдельный workflow engine или custom generator отклонён: он создал бы конкурирующий формат и lifecycle authority.
- Nx, Turborepo, Bazel, Make или just отклонены для текущего масштаба: workspace не имеет общего dependency graph, build cache или CI, а репозитории уже владеют canonical gates.
## Последствия
OpenSpec CLI закреплён exact version contract, а upgrade требует staged generation и проверки generated root `.opencode` projection. Dispatcher знает четыре workspace area, но не реализует build или test logic: он только валидирует Delivery Map и делегирует в repo-owned commands. Approval identity остаётся человеческим workflow constraint, потому что schema моделирует порядок артефактов, но не личность утвердившего.
Решение пересматривается, если OpenSpec перестанет поддерживать нужный artifact graph, появится обязательный общий CI/build graph или стоимость последовательной локальной orchestration станет существенной. В этих случаях новый ADR сравнивает native evolution с внешним engine либо monorepo platform.
+11
View File
@@ -1,3 +1,14 @@
# ADR
Здесь фиксируются долгоживущие технические решения. Новый ADR описывает контекст, решение и последствия; заменяемое решение получает новый ADR со ссылкой на прежний.
- [001 — Prisma и SQLite для локального MVP](001-prisma-sqlite-local-mvp.md)
- [002 — Nest-generated OpenAPI contract](002-nest-generated-openapi-contract.md)
- [003 — Server-side gRPC boundary T-Bank](003-tbank-server-side-grpc-boundary.md)
- [004 — Encrypted per-user T-Bank token](004-encrypted-per-user-tbank-token.md)
- [005 — T-Bank upstream resilience](005-tbank-upstream-resilience.md)
- [006 — Auth session policy](006-auth-session-policy.md)
- [007 — React Query fetch policy](007-react-query-fetch-policy.md)
- [008 — Pino backend logging](008-pino-backend-logging.md)
- [009 — Concurrent refresh rotation policy](009-concurrent-refresh-rotation-policy.md)
- [010 — Native OpenSpec SDD и local orchestration](010-native-openspec-sdd-and-local-orchestration.md)
+1
View File
@@ -6,3 +6,4 @@
- [Аудит 13.08.2026](audit-13-08-2026.md)
- [Аудит 20.08.2026](audit-20-08-2026.md)
- [Аудит 24.08.2026](audit-24-08-2026.md)
+66
View File
@@ -0,0 +1,66 @@
# Технический аудит WealthLedger — 24.08.2026
## Статус и охват
Это неизменяемый snapshot состояния на начало повторного аудита 24.08.2026, до реализации change `harden-agent-sdd-governance`. Проверены workspace root и независимые репозитории `frontend`, `backend`, `specs`, `docs`: SDD authority, OpenSpec artifacts, agent entrypoints, локальные gates, docs-as-code, testing policy, build-versus-buy и audit traceability.
Аудит не оценивал продуктовые требования, live T-Bank, deployment или CI: текущая рабочая модель локальная. Последующие исправления отражаются в [live remediation registry](../development/audit-remediation.md), а не в этом файле.
## Итог
Предыдущая remediation существенно усилила runtime contracts, frontend boundaries, concurrency, hygiene и OpenSpec authority. Репозиторий уже имел полезные негативные fixtures, strict validation и durable architecture/features docs. Главный оставшийся риск был процессным: правила существовали фрагментами, но не образовывали один исполняемый SDD contract, который не позволит AI-агенту обойти стиль, пропустить репозиторий, переусложнить тестирование или начать custom infrastructure без оценки готового решения.
## Подтверждённые сильные стороны
- Единственный canonical store уже зарегистрирован как `wealth-ledger-specs` с root `specs/openspec`.
- Frontend имел strict TypeScript, Biome, dependency-cruiser, Knip, OpenAPI, coverage и bundle ratchets с representative negative fixtures.
- Backend имел раздельные non-mutating lint, typecheck, Jest и build commands; auth concurrency regressions защищены тестами.
- Runtime OpenAPI можно было сравнить с committed frontend snapshot отдельным read-only script.
- `docs/architecture` и `docs/features` описывали as-built состояние, ADR фиксировали важные решения.
- Authority verifier отклонял второй OpenSpec root, implicit store selection и framework planning artifacts вне store.
## Findings
### AUD24-01 — Нет единой risk-based testing policy
**Приоритет:** P1. Frontend `verify` последовательно запускал одинаковый Vitest suite через `test:run` и coverage, а общая policy не отличала тесты критического поведения от тестов DTO, декларативных файлов и hygiene scripts. Это увеличивало локальную стоимость и подталкивало агента тестировать структуру ради coverage вместо риска.
### AUD24-02 — Build-versus-buy не является обязательным архитектурным шагом
**Приоритет:** P1. Ни OpenSpec schema, ни Design template не требовали до custom auth, security, storage, integration или tooling сравнить зрелые решения. Текущая собственная auth implementation не имела ретроспективной оценки против поддерживаемых платформ, включая Better Auth; аудит не утверждает, что миграция необходима, но подтверждает отсутствие decision evidence.
### AUD24-03 — OpenSpec graph и роли артефактов недостаточно строгие
**Приоритет:** P1. Default `spec-driven` позволял Design сразу после Proposal. Project config оставался недостаточным для разделения Proposal как intent, Delta Specs как behavior, Design как architecture и Tasks как implementation checklist. Delivery Map четырёх репозиториев и последовательные owner approvals не были частью schema contract.
### AUD24-04 — Agent projection могла дрейфовать и архивировать непроверенное
**Приоритет:** P1. Root `.opencode` указывал generated OpenSpec 1.9 при установленной CLI 1.10. Upstream archive workflow допускал продолжение после warnings; project overlays не требовали всех affected-area gates, semantic verification и independent review как безусловных blockers.
### AUD24-05 — Нет согласованного canonical local gate для workspace
**Приоритет:** P1. Frontend не отклонял Node 26 до application checks и повторял tests; backend не имел одного `verify`; docs не имел validator. Четыре независимых Git-root нельзя было проверить одним dispatcher, который понимает Delivery Map и условный runtime OpenAPI contract.
### AUD24-06 — Docs-as-code и process documentation неполны
**Приоритет:** P2. Docs не имел lockfile-backed Markdown gate. OpenSpec lifecycle doc фиксировал store boundaries, но не определял Change Owner, Completion Evidence, hard-versus-guidance, test matrix или build-versus-buy. Эти правила нельзя было устойчиво обнаружить из новой agent session.
### AUD24-07 — AGENTS слои не отделяют routing от policy
**Приоритет:** P2. Root и repository-local instructions содержали часть общих правил, но не давали одинакового пути к canonical local gate, engineering governance, repository style/boundary sources и audit registry. Проверяемые invariants и guidance не были явно разделены.
### AUD24-08 — Live remediation registry не охватывает все snapshots
**Приоритет:** P2. Registry ссылался только на аудит 20.08.2026: Audit IDs A-01–A-18 из snapshot 13.08.2026 не имели однозначного текущего статуса. WL-P3-04 был `planned`, хотя ожидал отдельного accessibility scope trigger и по собственным правилам должен был быть `deferred`.
### AUD24-09 — Сохранились подтверждённые current-state contradictions
**Приоритет:** P3. ADR 003, 004 и 006 говорили о будущей реализации уже поставленных возможностей; ADR 007 требовал ручного refresh, не поясняя сохранение cached data во время background refetch. Основная spec `user-authentication` не имела H1, зафиксированного A-18.
## Рекомендуемая remediation
AUD24-01 и AUD24-03–AUD24-09 объединяются одним process change `harden-agent-sdd-governance`, потому что вместе формируют один enforceable workflow contract. AUD24-02 после него требует отдельного `assess-auth-platform-options`: оценка существующей auth должна использовать новую Solution Assessment policy и не предрешать миграцию.
## Воспроизводимая база snapshot
На входе были просмотрены OpenSpec schema/config/templates, все root `.opencode` entrypoints, пять `AGENTS.md`, repository package scripts, существующие audits/registry, ADR и main specs. Локальные проверки показали OpenSpec 1.10.0, frontend test suite дважды в composite command, backend tests под Node 22 — 19 suites / 59 tests, отсутствие docs package/lockfile и отсутствие workspace dispatcher. Первичные исходные результаты сохранены смысловыми findings выше; observed remediation evidence появится только после archive в live registry.
+1
View File
@@ -7,5 +7,6 @@
- [Backend workflow](backend-workflow.md) — bootstrap backend, локальные
non-mutating gates и границы e2e.
- [Audit remediation registry](audit-remediation.md) — текущий статус findings, следующий OpenSpec change и evidence завершённых улучшений.
- [Engineering governance](engineering-governance.md) — Change Owner, SDD approvals, Delivery Map, risk-based testing, build-versus-buy и hard guardrails.
- [OpenSpec authority и lifecycle](openspec-authority-and-lifecycle.md) — единственный SDD store, границы постоянной документации и условия archive.
- [Проверка runtime OpenAPI](runtime-openapi-verification.md) — отдельный read-only contract gate и его границы.
+47 -7
View File
@@ -2,12 +2,12 @@
## Назначение
Это versioned реестр текущего состояния remediation для findings из [технического аудита 20.08.2026](../audits/audit-20-08-2026.md). Аудит — неизменяемый source of facts; этот документ хранит только приоритет, статус, путь продолжения и evidence последующих решений.
Это единый versioned реестр текущего состояния remediation для findings из всех [технических audit snapshots](../audits/README.md). Каждый аудит — неизменяемый source of facts; этот документ хранит только текущий статус, путь продолжения и evidence последующих решений, не копируя полный текст finding.
## Правила работы
- Каждая audit-derived запись имеет один статус: `planned`, `active`, `done`, `deferred` или `accepted`.
- Одновременно допускается не более одного `active` remediation change. При отсутствии active change раздел «Следующая задача» содержит ровно один рекомендуемый change.
- Одновременно допускается не более одного `active` remediation change. Пока он существует, продолжается только он. При наличии `planned` ровно одна запись отмечается следующей рекомендуемой задачей, но она не запускается параллельно active change.
- `done` требует даты, archive path OpenSpec change, commit для каждого затронутого Git-репозитория и точных non-mutating verification commands с observed results.
- `deferred` и `accepted` требуют даты, rationale и review trigger либо ссылки на явное решение владельца.
- При смене статуса обновляется только этот реестр; versioned audit snapshot не редактируется.
@@ -16,15 +16,55 @@
- Bootstrap change: [`2026-08-23-establish-audit-remediation-workflow`](../../specs/openspec/changes/archive/2026-08-23-establish-audit-remediation-workflow/) — `archived`; это process foundation и не закрывает ни одного Audit ID.
- Последний завершённый audit remediation change: [`2026-08-24-tighten-frontend-quality-guardrails`](../../specs/openspec/changes/archive/2026-08-24-tighten-frontend-quality-guardrails/) — `archived`; WL-P3-02, WL-P3-03, WL-P3-05 и WL-P3-06 закрыты.
- Активных audit remediation changes нет.
- Единственный active change: [`harden-agent-sdd-governance`](../../specs/openspec/changes/harden-agent-sdd-governance/) — AUD24-01 и AUD24-03–AUD24-09, а также A-14–A-16 и A-18.
## Следующая задача
## Текущая задача
`tighten-backend-request-feedback`: выбрать policy для unknown request fields и
зафиксировать её в новом OpenSpec change для WL-P3-01.
Завершить `harden-agent-sdd-governance`. Пока change active, новый remediation change не создаётся.
## Следующая рекомендуемая задача
`assess-auth-platform-options` для AUD24-02. Она начинается только после archive текущего active change, применяет Solution Assessment к существующей реализации и зрелым auth platforms, включая Better Auth, и не предрешает миграцию.
## Реестр findings
### Аудит 13.08.2026
| Audit ID | Текущий статус | Связь и следующее действие | Terminal evidence или trigger |
| --- | --- | --- | --- |
| A-01 | done | См. WL-P2-03. | CAS rotation и regression test, 2026-08-23. |
| A-02 | accepted | Ограниченная revocation model закреплена в ADR 006; access token живёт 15 минут. | Пересмотреть, если продукт потребует немедленный отзыв access token. |
| A-03 | deferred | Production transport исключён из local MVP scope. | Пересмотреть перед hosted deployment или reverse-proxy contract. |
| A-04 | done | `docs/features/tbank-connection.md` описывает поставленные Accounts, Portfolio, Ledger и Future Events. | Current-state docs проверены 2026-08-24. |
| A-05 | done | См. WL-P1-03 и WL-P1-04. | Canonical root и hard archive lifecycle, 2026-08-23. |
| A-06 | done | См. WL-P2-10. | Architecture/development onboarding и link review, 2026-08-24. |
| A-07 | done | См. WL-P2-02. | P2002 mapping и concurrent registration regression, 2026-08-23. |
| A-08 | planned | Объединить validation payload review с `tighten-backend-request-feedback`. | Готово к выбору после active change. |
| A-09 | planned | Operations cache закрыт WL-P2-01; отдельно оценить session retention/index. | Создать scoped change после решения приоритета. |
| A-10 | deferred | Текущая operational mitigation описана в T-Bank feature doc. | Пересмотреть при наблюдаемой потере metadata или новом large-portfolio SLA. |
| A-11 | done | Исправлено и подтверждено самим snapshot 13.08.2026. | Transport tests и единый Bearer owner. |
| A-12 | done | Исправлено в snapshot; дополнительно защищено WL-P3-03. | Dependency boundary fixture passed, 2026-08-24. |
| A-13 | deferred | Frontend behavior закрыт; backend e2e зависит от WL-P2-05. | Тот же stable Prisma trigger, что у WL-P2-05. |
| A-14 | active | `harden-agent-sdd-governance`. | Completion Evidence только после archive. |
| A-15 | active | `harden-agent-sdd-governance`. | Обновить current-state ADR и links. |
| A-16 | active | `harden-agent-sdd-governance`. | Слоистые AGENTS и onboarding. |
| A-17 | deferred | Совпадает с accessibility scope WL-P3-04. | Пересмотреть при включении accessibility/second locale в MVP scope. |
| A-18 | active | `harden-agent-sdd-governance`. | Нормализовать H1 main spec и пройти strict validation. |
### Аудит 24.08.2026
| Audit ID | Цель | Статус | Связанный change | Следующее действие / evidence |
| --- | --- | --- | --- | --- |
| AUD24-01 | Ввести risk-based testing без тестов ради файла или coverage. | active | [`harden-agent-sdd-governance`](../../specs/openspec/changes/harden-agent-sdd-governance/) | Завершить gates и archive. |
| AUD24-02 | Оценивать mature solutions и ретроспективно проверить auth platform. | planned | `assess-auth-platform-options` | Начать только после active governance change; миграция не предрешена. |
| AUD24-03 | Закрепить строгий artifact graph и роли OpenSpec. | active | [`harden-agent-sdd-governance`](../../specs/openspec/changes/harden-agent-sdd-governance/) | Завершить gates и archive. |
| AUD24-04 | Синхронизировать agent projection и hard archive blockers. | active | [`harden-agent-sdd-governance`](../../specs/openspec/changes/harden-agent-sdd-governance/) | Завершить gates и archive. |
| AUD24-05 | Добавить canonical repo gates и workspace dispatcher. | active | [`harden-agent-sdd-governance`](../../specs/openspec/changes/harden-agent-sdd-governance/) | Завершить gates и archive. |
| AUD24-06 | Ввести docs-as-code gate и authoritative process policy. | active | [`harden-agent-sdd-governance`](../../specs/openspec/changes/harden-agent-sdd-governance/) | Завершить gates и archive. |
| AUD24-07 | Сделать AGENTS компактными routing/enforcement layers. | active | [`harden-agent-sdd-governance`](../../specs/openspec/changes/harden-agent-sdd-governance/) | Завершить gates и archive. |
| AUD24-08 | Охватить одним registry все audit snapshots и исправить stale status. | active | [`harden-agent-sdd-governance`](../../specs/openspec/changes/harden-agent-sdd-governance/) | Завершить gates и archive. |
| AUD24-09 | Исправить current-state ADR/spec contradictions. | active | [`harden-agent-sdd-governance`](../../specs/openspec/changes/harden-agent-sdd-governance/) | Завершить gates и archive. |
### P1
| Audit ID | Цель | Репозитории | Статус | Связанный change | Следующее действие | Terminal evidence |
@@ -60,7 +100,7 @@
| WL-P3-01 | Сделать unknown request fields явной ошибкой или документированной policy. | backend | planned | `tighten-backend-request-feedback` (ещё не создан) | Выбрать validation policy. | — |
| WL-P3-02 | Устранить shared i18n import cycle. | frontend | done | [`2026-08-24-tighten-frontend-quality-guardrails`](../../specs/openspec/changes/archive/2026-08-24-tighten-frontend-quality-guardrails/) | — | 2026-08-24; frontend `1fc269a`, specs `2029519`, docs `fa5db07`; Node 22 `npm run verify` — passed. |
| WL-P3-03 | Восстановить FSD public API boundary. | frontend | done | [`2026-08-24-tighten-frontend-quality-guardrails`](../../specs/openspec/changes/archive/2026-08-24-tighten-frontend-quality-guardrails/) | — | 2026-08-24; frontend `1fc269a`, specs `2029519`, docs `fa5db07`; dependency fixture gate — passed. |
| WL-P3-04 | Исправить базовые language/loading accessibility semantics. | frontend | planned | — | Пересмотреть при включении accessibility в MVP scope. | — |
| WL-P3-04 | Исправить базовые language/loading accessibility semantics. | frontend | deferred | — | Пересмотреть при включении accessibility в MVP scope. | 2026-08-24; текущий local MVP scope не включает accessibility remediation. |
| WL-P3-05 | Ввести пропорциональный bundle regression budget. | frontend | done | [`2026-08-24-tighten-frontend-quality-guardrails`](../../specs/openspec/changes/archive/2026-08-24-tighten-frontend-quality-guardrails/) | — | 2026-08-24; frontend `1fc269a`, specs `2029519`, docs `fa5db07`; initial JS payload 509,165 B ≤ 512,000 B. |
| WL-P3-06 | Добавить coverage ratchet только как regression signal. | frontend | done | [`2026-08-24-tighten-frontend-quality-guardrails`](../../specs/openspec/changes/archive/2026-08-24-tighten-frontend-quality-guardrails/) | — | 2026-08-24; frontend `1fc269a`, specs `2029519`, docs `fa5db07`; coverage 82.57/76.08/77.35/83.48% — passed. |
| WL-P3-07 | Защитить рабочий `.env` от случайного commit. | frontend, specs, docs | done | [`2026-08-24-address-dependency-advisories-and-repo-hygiene`](../../specs/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/) | — | 2026-08-24; frontend `826936c`, specs `8897bd9`, docs `60a1c33`; hygiene check passed. |
+6 -7
View File
@@ -14,17 +14,16 @@ npm ci
## Локальная проверка
Следующие команды не изменяют versioned-файлы:
Canonical gate не изменяет versioned-файлы:
```bash
npm run lint
npm run typecheck:app
npm run typecheck:test
npm test -- --runInBand
npm run verify
```
`npm run lint:fix` — явная записывающая команда. Runtime OpenAPI сверяется с
frontend snapshot из workspace:
Он проверяет Node 22 до application stages и последовательно запускает hygiene,
lint, application/test TypeScript, Jest и build. `npm run lint:fix` — явная
записывающая команда, а `npm run test:cov` — отдельная диагностика без общего
числового threshold. Runtime OpenAPI сверяется с frontend snapshot из workspace:
```bash
bash specs/scripts/verify-runtime-openapi.sh
+116
View File
@@ -0,0 +1,116 @@
# Engineering governance
## Назначение
Этот документ — единственный источник устойчивой инженерной policy WealthLedger. Он определяет, как планировать и проверять изменения, но не хранит требования, design или tasks конкретного change. Нормативные change-specific артефакты находятся только в canonical OpenSpec store `wealth-ledger-specs` (`specs/openspec`).
## Термины
**Change Owner** — человек, который принимает текущий planning artifact и разрешает переход к следующему. Для продуктового поведения это Product Owner, для технического или процессного изменения — Engineering Owner.
**Delivery Map** — решение по каждой области `frontend`, `backend`, `specs` и `docs`: `affected` с ожидаемым результатом либо `N/A` с конкретной проверяемой причиной.
**Completion Evidence** — созданная после реализации и archive запись о фактической поставке: Delivery Map, archive path, commits изменённых репозиториев, точные verification commands с наблюдёнными результатами и итог independent read-only review.
**Enforceable Engineering Invariant** — обязательное правило с детерминированной non-mutating локальной проверкой, нарушение которой блокирует завершение change. Непроверяемое предпочтение является guidance, а не hard guardrail.
## Последовательность SDD
Каждый versioned change проходит один граф:
```text
Proposal → Delta Specs → Design → Tasks → Apply → Verify → Archive
```
- Proposal формулирует намерение, границы и ожидаемый результат без технологий, API, файлов и зависимостей.
- Delta Specs описывают изменение наблюдаемого поведения и инвариантов без изменений кода.
- Design объясняет архитектурный способ реализации крупными частями, риски и альтернативы; он не является построчной инструкцией.
- Tasks — implementation checklist, достаточный для выполнения Design и Specs. Он содержит планируемые проверки, но не будущие результаты, commits или post-archive bookkeeping.
AI-агент готовит только текущий разрешённый артефакт, показывает его Change Owner и останавливается. Downstream artifact создаётся только после явного approval. Если новая сессия не может подтвердить approval из доступного контекста, агент запрашивает его повторно.
Изменение принятого upstream artifact инвалидирует approval зависимых артефактов: Proposal — Specs, Design и Tasks; Specs — Design и Tasks; Design — Tasks. Tasks не могут неявно расширять scope или менять поведение и архитектуру: работа возвращается к соответствующему upstream artifact.
## Delivery Map и multi-repository delivery
Design каждого change оценивает все четыре области:
- `specs` всегда `affected` для versioned SDD change;
- `docs` всегда `affected` для поставленной пользовательской фичи; для технического изменения допустимо `N/A`, только если as-built документация действительно не меняется;
- `frontend` и `backend` являются `affected`, когда меняются их поведение, контракт, реализация или обязательный local gate;
- `N/A` требует конкретной причины; пустой commit не имитирует участие репозитория.
Change остаётся active, пока каждая affected область не реализована и не прошла свой canonical gate. Design содержит Contract Gate Decision: `runtime-openapi` имеет статус `required`, когда изменение затрагивает frontend и backend стороны API contract, иначе `N/A` с конкретной причиной. Успех одного репозитория не компенсирует отсутствие или failure другого.
## Risk-based testing
Автоматизированный тест обязателен, когда изменение затрагивает хотя бы один существенный риск:
- security- или privacy-sensitive поведение;
- денежные вычисления;
- целостность или миграцию данных;
- конкурентный доступ;
- публичный контракт;
- критический пользовательский journey;
- подтверждённую регрессию.
Уровень теста выбирается по наблюдаемому поведению и наиболее дешёвой надёжной границе. Тест не создаётся только потому, что появился или изменился файл. DTO без собственной логики, декларативная конфигурация, тонкий адаптер, прямолинейная оркестрация, hygiene script и поведение сторонней библиотеки проверяются существующим contract или integration gate без отдельного unit test, пока в проектном коде нет самостоятельного ветвления, преобразования, инварианта либо регрессии.
Frontend coverage gate — anti-regression constraint. Он не является причиной писать малоценные тесты декларативных файлов. Для backend нет общего числового coverage threshold; новый threshold допустим только через отдельное утверждённое обоснование защищаемого риска.
Проверка самого нового hard guardrail должна показать успешный compliant case и отказ на одном контролируемом репрезентативном нарушении. Это не превращает каждый вспомогательный script в объект unit testing.
## Build versus buy
До утверждения Design обязательна оценка зрелых поддерживаемых решений, если change вводит или существенно заменяет:
- авторизацию или иной security-механизм;
- хранение данных;
- внешнюю интеграцию;
- observability;
- caching или concurrency control;
- общую инфраструктуру или tooling.
Solution Assessment сравнивает применимые варианты по соответствию требованиям, зрелости, безопасности, эксплуатационной стоимости, ограничениям и стоимости миграции. Поддерживаемое совместимое решение используется либо Design конкретно объясняет, почему его совокупная стоимость или риск выше выбранной альтернативы.
Собственная реализация допустима, только если подходящего решения нет или доказана существенная несовместимость. Тогда Design фиксирует проверенные варианты, конкретные gaps, принятые риски и trigger повторного рассмотрения. Для обратимого изменения вне перечисленных областей отдельная формальная оценка не создаётся ради процесса.
## Single Source of Truth
| Вид знания | Authoritative location |
| --- | --- |
| Намерение, требования, Design, Tasks, changes и archives | `specs/openspec` |
| Исполняемое поведение | `frontend` и `backend` code и risk-based tests |
| Публичный API contract | backend runtime OpenAPI и committed frontend snapshot |
| Текущее устройство и поставленные возможности | `docs/architecture` и `docs/features` |
| Устойчивые архитектурные решения и причины | `docs/adr` |
| Инженерная policy и completion evidence | `docs/development` |
| Компактная маршрутизация AI-агентов | root и repository-local `AGENTS.md` |
`docs` описывает только фактическое текущее состояние и не пересказывает Proposal, Delta Specs, Design или Tasks другим форматом. `AGENTS.md` не копирует архитектуру или feature documentation: он направляет к authority и перечисляет только применимые hard constraints и canonical commands.
## Guardrails и local gates
CI пока отсутствует, поэтому обязательные gates выполняются локально одним и тем же способом человеком, AI-агентом и workspace verifier:
| Область | Canonical gate |
| --- | --- |
| frontend | `npm run verify` в `frontend` |
| backend | `npm run verify` в `backend` |
| specs | `bash specs/scripts/verify-workspace-change.sh <change>` из workspace root |
| docs | `npm run verify` в `docs` |
Каждый gate non-mutating и fail-fast. Auto-fix commands выполняются отдельно и не служат доказательством корректности. Runtime preflight отклоняет неподдерживаемый Node до application checks; OpenSpec preflight аналогично отклоняет несовместимую CLI version до операций со store.
Hard guardrail должен иметь исполняемую локальную проверку. Правило без надёжной проверки помечается как guidance и учитывается в review, но не выдаётся за автоматический запрет. Новые frameworks, checkers и thresholds добавляются только после оценки поддерживаемого решения, maintenance cost и реально защищаемого риска.
## Verify, archive и Completion Evidence
Structural validation OpenSpec проверяет schema и форму артефактов, но не соответствие реализации. До archive обязательны:
1. успешные canonical gates всех affected areas;
2. semantic verification реализации против Proposal, Delta Specs, Design и Tasks;
3. independent read-only review без Critical и Important findings;
4. завершённый checklist без unchecked tasks.
Archive не имеет confirmation override для этих blockers. После успешного archive применяется двухфазная фиксация: сначала commits поставленных изменений и archive/sync, затем Completion Evidence с уже существующими delivery commit IDs, после чего отдельный final docs commit сохраняет evidence. Evidence ссылается на предшествующий as-built docs commit, если docs affected; при `N/A` сохраняет причину и не выдумывает implementation commit. Собственный final evidence commit не может ссылаться сам на себя и сообщается итогом archive workflow. Только фактические commits, выполненные команды и наблюдённые результаты могут быть evidence; planned значения и предположения не считаются завершением.
+5 -1
View File
@@ -7,7 +7,11 @@ npm ci
npm run verify
```
`verify` проверяет OpenAPI drift, TypeScript, Biome, unit tests и coverage, Knip, FSD dependency rules и production build. Он работает без backend.
`verify` сначала отклоняет runtime вне Node 22, затем проверяет OpenAPI drift,
repository hygiene, TypeScript, Biome, один coverage-backed запуск Vitest,
Knip, FSD dependency rules, production build и bundle budget. Он работает без
backend. Coverage остаётся anti-regression constraint; правила выбора тестов
зафиксированы в [engineering governance](engineering-governance.md).
Backend остаётся источником OpenAPI. После изменения опубликованного backend-контракта разработчик запускает в `frontend/`:
+50 -12
View File
@@ -2,29 +2,67 @@
## Назначение
Этот документ фиксирует постоянные границы SDD-процесса WealthLedger. Он не содержит requirements, design, delta-specs или tasks конкретного change: они живут только в canonical OpenSpec store.
Этот документ описывает фактически настроенный OpenSpec workflow WealthLedger. Общие определения, approval policy, risk-based testing и build-versus-buy находятся в [Engineering governance](engineering-governance.md).
## Единственный SDD store
- Canonical OpenSpec store: `wealth-ledger-specs`.
- Canonical store: `wealth-ledger-specs`.
- Физический root: `specs/openspec` относительно workspace.
- Requirements, design, delta-specs, tasks, changes и archives создаются и коммитятся только в этом store.
- Любая OpenSpec command, читающая или изменяющая change, явно использует `--store wealth-ledger-specs`; cwd, ближайший root и глобальная конфигурация машины не выбирают store проекта.
- Requirements, Delta Specs, Design, Tasks, changes и archives хранятся только в этом store.
- Команда, читающая или изменяющая change, всегда получает `--store wealth-ledger-specs`; cwd и nearest-root discovery не выбирают authority проекта.
- Versioned framework-specific planning artifacts вне `specs/openspec`, включая `superpowers/plans`, запрещены. `references/**` остаётся read-only исключением.
## Границы артефактов
Exact поддерживаемая OpenSpec CLI version хранится в `specs/openspec/.cli-version`. Перед project-owned операциями выполняется:
- `docs` хранит только долговечную architecture, development, feature, audit и remediation documentation, включая completion evidence после archive.
- `frontend` и `backend` хранят runtime code и tests, но не framework-specific planning artifacts.
- Framework-specific requirements, plans, specs, design и task artifacts вне `specs/openspec` не создаются и не коммитятся; это включает `superpowers/plans`.
- `references/**` — read-only reference content. Его framework artifacts не являются нарушением и не подлежат переносу или очистке без отдельной задачи.
```bash
bash specs/scripts/verify-openspec-version.sh
```
## Завершение change
Несовпадение version блокирует операцию до чтения или изменения store.
Archive разрешён только после завершения всех planning artifacts и всех tasks. Post-archive bookkeeping не может быть незакрытым task: после успешного archive durable registry/history фиксирует фактический archive path, commits затронутых репозиториев, команды проверки и observed results.
## Project-local schema
Перед завершением change выполните из workspace:
Новые changes по умолчанию используют schema `wealth-ledger-sdd` из `specs/openspec/schemas/wealth-ledger-sdd`. Её граф:
```text
proposal → specs → design → tasks → apply
```
OpenSpec обеспечивает structural order, а явное решение Change Owner — переход между артефактами. Agent создаёт один текущий artifact и останавливается для approval. Роли артефактов и cascade rules определены в governance policy; исполняемые templates и instructions принадлежат schema.
Project-local schema проверяется из `specs`:
```bash
openspec schema validate wealth-ledger-sdd --verbose
openspec schema which wealth-ledger-sdd --json
```
`schema which` должен указывать project-local source. `specs/openspec/config.yaml` хранит default schema и компактный routing context, а не копию полной policy.
## Agent entrypoints и обновление OpenSpec
Root `.opencode` — generated local projection OpenSpec 1.10 с минимальными WealthLedger overlays: fixed store, one-artifact-at-a-time и hard archive blockers. Она не является SSOT, потому что workspace root не versioned.
`openspec update` не запускается напрямую из workspace root. Новую upstream version сначала генерируют в isolated staging, сравнивают с projection, переносят upstream delta и повторно накладывают project overlays. После этого обязательно выполняют authority fixtures; permissive archive, conditional store selection и второй `openspec` root считаются failures.
## Реализация и проверка change
Design содержит Delivery Map для `frontend`, `backend`, `specs` и `docs`. Из workspace один non-mutating dispatcher проверяет карту и запускает canonical gates affected areas:
```bash
bash specs/scripts/verify-workspace-change.sh <change>
```
`specs` проверяется всегда. Dispatcher читает явный Contract Gate Decision из Design и сравнивает backend runtime OpenAPI с committed frontend snapshot только при `runtime-openapi: required`; этот status допустим лишь при affected frontend и backend. Child failure блокирует общий результат; fallback и auto-fix отсутствуют.
Перед archive отдельно подтверждаются structural и semantic gates:
```bash
bash specs/scripts/verify-openspec-authority.sh
openspec validate <change> --type change --strict --store wealth-ledger-specs
openspec validate --specs --strict --store wealth-ledger-specs
```
Structural success не доказывает соответствие реализации. Project-owned verify workflow сопоставляет реализацию с Proposal, Delta Specs, Design и Tasks, затем требует independent read-only review без Critical и Important findings.
Archive отклоняется при незавершённом artifact approval, unchecked task, failed affected-area gate, отсутствующей semantic verification или independent review. Confirmation override для этих условий отсутствует. Completion Evidence создаётся только после archive и delivery commits по двухфазному протоколу [Engineering governance](engineering-governance.md); final evidence commit не подменяется незакрытым task.
+1370
View File
File diff suppressed because it is too large Load Diff
+16
View File
@@ -0,0 +1,16 @@
{
"name": "wealth-ledger-docs",
"version": "1.0.0",
"private": true,
"engines": {
"node": "22.x"
},
"scripts": {
"runtime:check": "node scripts/verify-node-version.mjs",
"lint": "markdownlint-cli2 \"**/*.md\" \"#node_modules\"",
"verify": "npm run runtime:check && npm run lint && git diff --check"
},
"devDependencies": {
"markdownlint-cli2": "0.23.2"
}
}
+26
View File
@@ -0,0 +1,26 @@
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const packageJson = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'));
const nvmVersion = readFileSync(resolve(root, '.nvmrc'), 'utf8').trim();
const expectedMajor = nvmVersion.replace(/^v/, '').split('.')[0];
const expectedEngine = `${expectedMajor}.x`;
if (packageJson.engines?.node !== expectedEngine) {
throw new Error(
`Node runtime contracts disagree: .nvmrc=${nvmVersion}, package.json engines.node=${packageJson.engines?.node ?? 'missing'}`,
);
}
const actualVersion = process.versions.node;
const actualMajor = actualVersion.split('.')[0];
if (actualMajor !== expectedMajor) {
console.error(
`Unsupported Node.js runtime: expected ${expectedEngine}, actual ${actualVersion}. Activate .nvmrc before running repository checks.`,
);
process.exit(1);
}
console.log(`Node.js runtime verified: ${actualVersion} (${expectedEngine})`);