@@ -76,11 +76,11 @@ remediation change создаётся после выбора владельце
| FE26-09 | Убрать механическое обязательное дробление каждого component. | [FE-G] F-07 | already-covered | done | 06.09.2026; [FE26-E]. [UI pattern ](../../frontend/.ai/conventions/frontend-ui.md ) сохраняет semantic ownership и допускает tightly-coupled renderers; это guidance, а не line-count gate. Конкретное разделение крупных modules учтено отдельно FE26-13. |
| FE26-10 | Объединить protected query policy и endpoint query identity ownership. | [FE-G] F-08; [FE-S] F-05 | already-covered | done | 06.09.2026; [FE26-E]. [App defaults ](../../frontend/src/app/ui/App.tsx ), [T-Bank VM ](../../frontend/src/features/tbank-connection/ui/TbankConnectionSection.vm.ts ) и entity-owned options operations/portfolio; status использует общий authenticated query seam. |
| FE26-11 | Централизовать test cleanup и auth reset. | [FE-S] F-02 | already-covered | done | 06.09.2026; [FE26-E]. [Test setup ](../../frontend/src/test/setup.ts ): RTL cleanup, auth reset, MSW handler reset в общем afterEach. |
| FE26-12 | Убрать повтор server identity из Income view/model. | [FE-S] F-03 | confirmed | done | 06.09.2026; [FE26-E]. [Backend income service ](../../backend/src/tbank /income-analytics.service.ts ) передаёт instrumentKey; [Income VM ](../../frontend/src/pages/account-income/ui/AccountIncomePage.vm.ts ) проверяет и группирует готовую связь, не вычисляя identity. |
| FE26-12 | Убрать повтор server identity из Income view/model. | [FE-S] F-03 | confirmed | done | 06.09.2026; [FE26-E]. [Backend income service ](../../backend/src/modules/investments/income /income-analytics.service.ts ) передаёт instrumentKey; [Income VM ](../../frontend/src/pages/account-income/ui/AccountIncomePage.vm.ts ) проверяет и группирует готовую связь, не вычисляя identity. |
| FE26-13 | Выделить самостоятельные ответственности семи крупных TSX modules. | [FE-S] F-04 | already-covered | done | 06.09.2026; [FE26-E]. Income/Events/Accounts/Account state views, [route fallback ](../../frontend/src/app/routes/RouteFallback.tsx ), [guards ](../../frontend/src/app/routes/RouteGuards.tsx ), breadcrumbs и T-Bank loaded section выделены во frontend `c97f62b` . |
| FE26-14 | Устранить повтор test client policy и нестабильный cache lifetime. | [FE-S] F-06 | confirmed | done | 06.09.2026; [FE26-E]. [Test query factory ](../../frontend/src/test/query.tsx ) используется оставшимися auth/T-Bank harnesses; [auth test ](../../frontend/src/features/auth/model/auth.test.tsx ) проверяет сохранение client и seeded cache при rerender. |
| FE26-15 | Перенести компонентные стили из global CSS к владельцам. | [FE-S] F-08 | already-covered | done | 06.09.2026; [FE26-E]. [Global styles ](../../frontend/src/shared/theme/styles.css ) содержат базовые правила; AppShell, breadcrumbs и auth используют CSS Modules, StateView — Mantine props. |
| FE26-16 | Исправить source connectedAt contract вместо String coercion. | [FE-S] F-09 | already-covered | done | 06.09.2026; [FE26-E]. [Backend DTO ](../../backend/src/tbank /tbank-connection.dto.ts ) задаёт nullable date-time string; [frontend consumer ](../../frontend/src/features/tbank-connection/ui/TbankConnectionSectionLoaded.tsx ) не скрывает неверный transport type через String. |
| FE26-16 | Исправить source connectedAt contract вместо String coercion. | [FE-S] F-09 | already-covered | done | 06.09.2026; [FE26-E]. [Backend DTO ](../../backend/src/modules/investments/tbank-connection /tbank-connection.dto.ts ) задаёт nullable date-time string; [frontend consumer ](../../frontend/src/features/tbank-connection/ui/TbankConnectionSectionLoaded.tsx ) не скрывает неверный transport type через String. |
| FE26-17 | Перенести auth validation и payment invariants из JSX к model owners. | [FE-S] F-10 | already-covered | done | 06.09.2026; [FE26-E]. [Auth validation ](../../frontend/src/features/auth/model/validation.ts ), [ledger display ](../../frontend/src/entities/broker-operation/model/display.ts ) владеют соответствующими правилами. |
| FE26-18 | Удалить redundant position modes и test-only proxy exports. | [FE-S] F-11 | already-covered | done | 06.09.2026; [FE26-E]. [PositionCard ](../../frontend/src/pages/account/ui/components/PositionCard.view.tsx ) выводит mode из kind; [StateView ](../../frontend/src/shared/ui/StateView.tsx ) не экспортирует Mantine Button; page barrels сохраняют product surface. |
@@ -226,8 +226,8 @@ authority.
| WL-P2-02 | Вернуть предсказуемый 409 при конкурентной регистрации. | backend, specs, docs | done | [`2026-08-23-harden-auth-and-cache-concurrency` ](../../specs/openspec/changes/archive/2026-08-23-harden-auth-and-cache-concurrency/ ) | — | 2026-08-23; backend `c77b3cf` , specs `6e20cdf` , docs `8568e7b` ; P2002 mapping and barrier regression test passed. |
| WL-P2-03 | Сделать refresh rotation атомарной. | backend, specs, docs | done | [`2026-08-23-harden-auth-and-cache-concurrency` ](../../specs/openspec/changes/archive/2026-08-23-harden-auth-and-cache-concurrency/ ) | — | 2026-08-23; backend `c77b3cf` , specs `6e20cdf` , docs `8568e7b` ; CAS one-winner regression test passed. |
| WL-P2-04 | Синхронизировать runtime, OpenAPI и auth success statuses. | backend, frontend | done | [`2026-08-24-align-api-contract-and-client-resilience` ](../../specs/openspec/changes/archive/2026-08-24-align-api-contract-and-client-resilience/ ) | — | 2026-08-24; backend `9bd3400` , frontend `6d892da` , specs `800450d` , docs `b91280c` ; metadata regression, frontend OpenAPI check и runtime/snapshot SHA совпали. |
| WL-P2-05 | Восстановить runnable backend e2e gate. | backend | deferred | — | Пересмотреть после следующей stable Prisma: три чистых `migrate deploy` на Node 22 долж ны пройти подряд. | 2026-08-23; Prisma 7.9.1 на Node 22 воспроизводимо возвращает пустой schema-engine error даже для fresh SQLite DB; published latest также 7.9.1 . |
| WL-P2-06 | Добавить проходящий app/test TypeScript gate backend. | backend | done | [`2026-08-23-make-local-verification-agent-safe` ](../../specs/openspec/changes/archive/2026-08-23-make-local-verification-agent-safe/ ) | — | 2026-08-23; backend `71d57d6` , specs `72444db` , docs `293df9c` ; `npm run typecheck:app` и `npm run typecheck:test` — passed. |
| WL-P2-05 | Восстановить runnable backend e2e gate. | backend | done | — | — | 2026-09-13; унаследованный RUST_LOG изолирован в Prisma config, 3 последовательных и 2 параллель ных полных e2e passed. [ Результаты ]( #2026-09-13--wl-p2-05-воспроизводимый-sqlite-e2e ) . |
| WL-P2-06 | Добавить проходящий app/test TypeScript gate backend. | backend | done | [`2026-08-23-make-local-verification-agent-safe` ](../../specs/openspec/changes/archive/2026-08-23-make-local-verification-agent-safe/ ) | — | 2026-08-23; backend `71d57d6` , specs `72444db` , docs `293df9c` ; `npm run typecheck:app` и `npm run typecheck:test` — passed. [ 2026-09-13: включён strict по P1-10 ]( #2026-09-13--wl-p2-06-strict-typescript ). |
| WL-P2-07 | Сохранять cached data во время background refetch. | frontend | done | [`2026-08-24-align-api-contract-and-client-resilience` ](../../specs/openspec/changes/archive/2026-08-24-align-api-contract-and-client-resilience/ ) | — | 2026-08-24; frontend `6d892da` , specs `800450d` , docs `b91280c` ; observable Accounts/Portfolio refetch tests и `npm run verify` — passed (17 files, 55 tests). |
| WL-P2-08 | Нормализовать cold-start refresh failure. | frontend | done | [`2026-08-24-align-api-contract-and-client-resilience` ](../../specs/openspec/changes/archive/2026-08-24-align-api-contract-and-client-resilience/ ) | — | 2026-08-24; frontend `6d892da` , specs `800450d` , docs `b91280c` ; cold-start и protected-401 transport-failure tests passed. |
| WL-P2-09 | Проверять backend runtime OpenAPI против frontend snapshot. | backend, frontend | done | [`2026-08-23-make-local-verification-agent-safe` ](../../specs/openspec/changes/archive/2026-08-23-make-local-verification-agent-safe/ ) | — | 2026-08-23; frontend `7a3048c` , backend `71d57d6` , specs `72444db` , docs `293df9c` ; runtime и snapshot SHA-256 совпали, frontend `npm run openapi:check` — passed. |
@@ -249,10 +249,212 @@ authority.
| 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. |
| WL-P3-08 | Исключить runtime SQLite DB из Git. | backend, 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; backend `6052565` , specs `8897bd9` , docs `60a1c33` ; hygiene check passed. |
### 2026-09-13 — WL-P2-11: переход на Node 24 LTS
Продолжение bootstrap policy из WL-P2-11, части 14.backend/frontend/docs
[рабочего TODO ](../../todo/wealthledger-engineering-improvements.md ).
Node 24.21.0 / npm 11.19.0 выбран по [официальному каталогу релизов ](https://nodejs.org/dist/index.json )
и [расписанию поддержки ](https://github.com/nodejs/Release#release-schedule ):
ветка Krypton LTS поддерживается до 30.04.2028.
`.nvmrc` frontend/backend/docs фиксируют 24.21.0, engines — 24.x.
Backend `@types/node` обновлён до 24.13.3; runtime dependencies не обновлялись.
Npm дополнил backend lockfile платформенными optional dependencies существующего
resolver. Для npm 11.19 явно разрешены install scripts сборочных зависимостей
с pin версий. Инструкция переустановки и отката — в
[локальном окружении ](local-workspace.md#версия-node ).
Specs продолжает наследовать frontend runtime; самостоятельный bootstrap CLI
из части 14.specs и CI остаются отдельными незавершёнными задачами.
Проверки относятся к frontend `53c852b` , backend `ce24a84` , docs `c74c573` ,
specs `834f2d1` с текущим diff перехода Node:
- `npm ci` в frontend/backend/docs — PASS; backend native modules установлены
под Node 24, `npm run build` с генерацией Prisma client — PASS.
- Frontend `npm run verify` — PASS: 46 files, 268 tests, coverage, OpenAPI drift,
TypeScript, Biome, Knip, dependency boundaries, приложение и Storybook.
Прогон одновременно с установкой backend упирался в UI timeout; отдельный
повтор полного gate прошёл без изменения тестов или их таймаутов.
- Backend `npm run verify` — PASS: 35 suites, 257 tests, lint, оба typecheck и build.
- Backend `npm run test:e2e` — PASS: 8 suites, 98 tests; новая SQLite и штатные
migrations для каждой suite, включая runtime OpenAPI. Для HTTP-портов нужен
запуск вне sandbox. Рабочая БД не использовалась.
- Docs `npm run verify` — PASS: 54 Markdown-файла, 0 issues;
`git diff --check` во всех четырёх repos — PASS.
- OpenSpec CLI 1.10.0, существующая установка, исполненная Node 24.21.0:
`schema validate wealth-ledger-sdd --verbose` и
`validate --specs --strict --store wealth-ledger-specs` — PASS, 25 specs.
## История registry
Terminal evidence добавляется сюда только после завершения соответствующего change.
### 2026-09-13 — WL-P2-05: воспроизводимый SQLite e2e
Закрыты TODO 03 и 03.docs, повторно проверен SQLite scope 11. Backend
`8637ad2` с текущим diff, Node 22.21.0 / Prisma 7.9.1. Schema, migrations,
зависимости и HTTP-контракт не менялись.
- До исправления fresh migration: `RUST_LOG=warn` и `error` — exit 1 с пустым
`Schema engine error` ; переменная отсутствует или равна `info` — exit 0.
В исходном окружении было `RUST_LOG=warn` . Это воспроизведённая зависимость
запуска от окружения, а не доказательство внутреннего дефекта Rust engine.
- Prisma config исключает унаследованный `RUST_LOG` после dotenv. Общий runner
даёт каждому suite свою DB и один URL для migration/Jest, отклоняет прямой
Jest без изоляции и очищает каталог после ошибки или сигнала.
- `npm run verify` — PASS: zero-warning lint, app/test types, 35 suites /
257 unit tests, Prisma generation и build.
- Docs `npm run verify` — PASS: Markdown, ссылки/якоря и `git diff --check` .
- `npm run test:e2e` — PASS: 8 suites / 98 tests, включая runtime OpenAPI.
- `node test/sqlite-regression.cjs` — PASS: три последовательных и два
параллельных полных e2e (каждый 98 tests, всего 40 разных DB); внешний
вымышленный файл неизменён. Недоступный schema engine возвращает exit 1;
SIGINT/SIGTERM — 130/143. Все 43 созданных DB-каталога удалены.
- `npm run test:durability -- /tmp/p111-baseline` — PASS: отдельная baseline
сборка `8ec172f48eefa2237dc0c16919fbb2e726b39a65` , additive migration,
сохранение User/Session/TbankConnection, банковской истории и защиты повторов,
restart, откат приложения и backup/restore. `RUST_LOG=info` удалён из runner;
для старого baseline унаследованная переменная также исключается.
- HTTP/durability проверены вне sandbox после воспроизведения запрета локальных
портов `EPERM` . Это ограничение среды, не failing migration. Пользовательская
DB и `.env` не использовались как цель записи.
Логи этой проверки: `/tmp/wl-sqlite-verify.log` , `/tmp/wl-sqlite-e2e-1.log` ,
`/tmp/wl-sqlite-regression.log` , `/tmp/wl-sqlite-durability.log` .
Подробные regression logs сохранены в системном temp-каталоге
`wealthledger-sqlite-regression-pSyuoe` , durability —
`wealthledger-bank-durability-V0u1NA` . Эти локальные временные логи могут быть
удалены системой; воспроизводимые команды и
[матрица рисков ](../../backend/README.md#реальная-sqlite-и-сохранность-данных )
остаются в backend. Исторические evidence ниже сохранены без переписывания.
### 2026-09-13 — P1-12: backend responsibilities
Статус: `done` . Backend commit `8ba0053` .
BankCards разделён на services карт, операций и категорий, сценарий сводки и
конкретный repository. Общая transaction/retry boundary, ownership, idempotency,
optimistic concurrency и ограничения возвратов сохранены. Stock/bond services
разделены по каталогу, рынку и доходам; связные operations и T-Bank client
сохранены. Business modules отделены от integrations; сложные modules используют
слои ответственности, компактные остаются плоскими.
- `npm run verify` — passed: lint, app/test typecheck, 35 suites / 257 tests, build.
- Восемь существующих HTTP/e2e suites выполнены временным runner
`/tmp/wl-modular-http.cjs` : отдельная SQLite DB на suite, migrations с
`RUST_LOG=info` , configured HTTP, 118 tests passed. OpenAPI совпадает с frontend
snapshot. Общий e2e blocker и статус задачи 03 этим не закрываются.
- Финальный перенос 47 файлов проверен сравнением 142 исходников/tests:
различий кроме относительных путей и форматирования нет.
- Formatter, docs `npm run verify` , lint backend conventions и `git diff --check`
прошли. Новые dependencies и architecture tests не добавлены.
### 2026-09-13 — P1-11: реальная SQLite
P1-11 поставлена в backend commit `7fde3ec` . Дополнено доказательство
WL-P2-03; статус общего e2e WL-P2-05 не меняется. Команды и матрица рисков —
[backend README ](../../backend/README.md#реальная-sqlite-и-сохранность-данных ).
- `npm run test:sqlite` — два последовательных успешных запуска после фиксации
loopback-listener: 8 auth и 21 карточный HTTP/SQLite test. Каждый suite получает
собственную временную DB; Prisma не мокируется. Барьер перед CAS гарантирует,
что оба refresh прочитали прежний hash; победившая сессия переживает replay.
- Существующие карточные tests покрывают owner links, idempotency/tombstones,
версии, конкурентные refund/archive/write, rollback source lock, атомарный
перевод, точные суммы и FK/unique constraints. Новая тестовая платформа не нужна.
- `npm run test:durability -- /tmp/p111-baseline` — PASS: migration, restart,
previous-app rollback, backup/restore и чтение сохранённой финансовой истории.
Baseline экспортирован из `8ec172f48eefa2237dc0c16919fbb2e726b39a65` и собран
отдельно. Его lockfile совпадает с текущим; при этой проверке переиспользованы
установленные node_modules. README также описывает независимый `npm ci` .
Runner проверяет наличие build и неизменённый префикс migration history.
- Node 22.21.0: `npm run verify` — PASS (35 suites, 257 unit tests, zero-warning
lint, оба typecheck, Prisma generate и build).
- Первые HTTP-запуски с автоматическим открытием/закрытием сервера Supertest
дали плавающий 404. Suites теперь держат один loopback-listener до `app.close()` ;
повторные проверки прошли. Sandbox требует разрешения на локальный порт.
- Миграции выполнены с `RUST_LOG=info` . Это подтверждение выбранных DB-сценариев,
не снятие прежнего ограничения общего `test:e2e` и не выполнение задачи 03.
### 2026-09-13 — WL-P2-06: strict TypeScript
Поставка backend: commit `346a6f0` (`refactor: enforce strict backend typing` ).
По продолжению P1-10 в [общем tsconfig ](../../backend/tsconfig.json ) включён
`strict: true` без отключения отдельных strict-проверок;
`noFallthroughCasesInSwitch` сохранён отдельно. Убраны избыточные настройки,
которые теперь включает `strict` .
После замечания владельца вариант с definite-assignment `!` заменён:
в 14 файлах 315 полей DTO объявлены через `declare` . Заполнение входных DTO
принадлежит Nest/class-transformer, ответные DTO описывают возвращаемые объекты.
`declare` не генерирует поля со значением `undefined` и не подменяет проверку
входных данных. Optional/nullable-типы, декораторы и валидация сохранены.
В [TbankClient ](../../backend/src/integrations/tbank/tbank.client.ts )
`getOpenAccounts` и `getDividends` задают тип результата на `call<Response>` ,
как соседние RPC; тип параметра `.then` выводится из этого результата.
В [ESLint ](../../backend/eslint.config.mjs ) включён
`@typescript-eslint/no-non-null-assertion: error` . Он не охватывает `field!: Type` ,
поэтому `no-restricted-syntax` отдельно запрещает definite-assignment `!`
в свойствах и переменных. Устранены также 51 прежний non-null assertion и
четыре definite-assignment assertions в тестах: используются сужение типов,
локальные значения, типизированные результаты фильтрации и runtime assertions
в тестах. Транзакции, проверки доступа, cache generation и денежная точность
сохранены; отсутствующая категория в сводке приводит к явной внутренней ошибке.
Проверено на Node 22.21.0, backend `3cf883e` с указанными изменениями:
- `npm run verify` — passed: lint без warnings, strict app/test typechecks,
35 Jest suites / 257 tests, Prisma generation и production build.
- `DATABASE_URL=file:/tmp/wealthledger-declared-dto-openapi-20260913.db npm run test:openapi-contract`
— passed, 1 test; frontend snapshot не менялся.
- TypeScript Compiler API подтвердил все strict options в app/test/build/dev
configs. Каждый config отклоняет шесть примеров: неинициализированное поле,
несовместимый callback, `null` вместо строки, implicit `any` /`this` , доступ
к `unknown` в `catch` (TS2564, TS2345, TS2322, TS7006, TS2683, TS18046).
- Проверка ESLint через `lintText` подтверждает ошибки для `value!` , `field!`
и `let value!` ; декларация DTO без `!` разрешена.
- Новые тесты ValidationPipe проходят до и после замены деклараций:
обязательные credentials, нормализация email, вложенные money DTO и
обязательный version с optional-полями `PartialType` . Дополнены проверки
инструментов без UID; отдельный тест проверяет имя категории и ошибку
при нарушенной ссылке в банковской сводке.
- `NODE_ENV=development NODE_OPTIONS=--experimental-vm-modules npx jest --config test/jest-e2e.json --runInBand bank-cards.e2e-spec.ts`
с новой `DATABASE_URL=file:/tmp/bank-cards-*/test.db` — passed, 21 tests,
включая реальные миграции, валидацию HTTP, права владельца, возвраты,
транзакции и перезапуск. Runner использует `RUST_LOG=info` для миграций.
Первый прогон дал 19 passed / 2 timeout в сценариях возвратов и потребовал
остановки оставшегося Jest-процесса. Повтор на новой базе прошёл 21/21;
исходный `3cf883e` в отдельной копии с теми же dependencies также прошёл
21/21. Это не доказательство стабильности общего e2e gate.
- Полный `strict` проходит; 317 diagnostics из предыдущей оценки устранены.
Общий DB/e2e gate и ограничение WL-P2-05 остаются отдельной задачей.
### 2026-09-13 — WL-P2-06: backend TypeScript
Выполнен пункт P1-10 списка инженерных улучшений от 13.09.2026
как продолжение существующего TypeScript gate. В [общем tsconfig ](../../backend/tsconfig.json )
включены `noImplicitAny` , `strictBindCallApply` , `noFallthroughCasesInSwitch` ;
app/test typechecks, production и dev build наследуют эти настройки.
Исходный код, зависимости, unsafe-checks и публичный API не менялись.
Проверено на Node 22.21.0, backend `3cf883e` с указанным изменением tsconfig:
- `npm run verify` до и после изменения — passed: zero-warning ESLint,
оба TypeScript gate, 33 Jest suites / 253 tests, Prisma generation и build.
- Проверка через TypeScript Compiler API с виртуальным ошибочным файлом для
каждого из четырёх configs — passed: implicit-any параметр даёт TS7006,
неверные аргументы `call` /`apply` /`bind` — TS2345/TS2322, проваливание `switch`
— TS7029. Контроль с выключенными тремя flags принимает тот же файл.
- `DATABASE_URL=file:/tmp/wealthledger-p1-10-openapi-20260913.db npm run test:openapi-contract`
— passed, 1 test; runtime OpenAPI совпал с frontend snapshot.
- `npx tsc --project tsconfig.typecheck.test.json --incremental false --strict --noImplicitAny --strictBindCallApply --noFallthroughCasesInSwitch --pretty false`
— оценка полного `strict` : 317 diagnostics, из них 315 TS2564 для полей DTO
и две TS2345 в `TbankClient.getOpenAccounts` / `getDividends` из-за callback
для `Promise<unknown>` . Полный `strict` пока не включён; это отдельный этап.
- Общий DB/e2e gate не запускался; WL-P2-05 сохраняет прежний статус.
### 2026-08-26 — SDD26-01– SDD26-03, SDD26-09, SDD26-12, SDD26-17, SDD26-21, SDD26-28– SDD26-30: done
Change синхронизирован в canonical specs и архивирован в [`2026-08-26-harden-openspec-sdd-quality` ](../../specs/openspec/changes/archive/2026-08-26-harden-openspec-sdd-quality/ ).