refactor: group canonical specs by domain and archive account-top-positions (#74)
- Move canonical specs into domain folders (identity, tbank, brokerage, portfolio, instruments, banking, frontend-platform, backend-platform). - Remove process specs; keep still-valid unique rules in openspec/config.yaml. - Keep project-foundation behavior as app-shell and http-api-foundation. - Archive account-top-positions without G4 by owner decision (descoped review/QA recorded in process-record); sync portfolio-concentration and portfolio-view. - Group AI_INDEX by domain. Refs: WealthLedger/main#48
@@ -12,30 +12,40 @@ HTTP OpenAPI имеет единственный editable source в backend, а
|
|||||||
Потребитель доверяет предоставленному artifact и локально проверяет generated
|
Потребитель доверяет предоставленному artifact и локально проверяет generated
|
||||||
types. CI каждого участника использует только его собственные входы.
|
types. CI каждого участника использует только его собственные входы.
|
||||||
|
|
||||||
| Тема / trigger | Existing spec |
|
Specs сгруппированы по доменам: `openspec/specs/<domain>/<capability>/spec.md`.
|
||||||
| --- | --- |
|
Новая capability кладётся в существующий домен; новый домен — только для
|
||||||
| Auth/session/refresh/error contract | [User authentication](openspec/specs/user-authentication/spec.md) |
|
отдельного бизнес-контекста. Процессные правила сюда не входят.
|
||||||
| T-Bank connection/security/cache generation | [T-Bank connection](openspec/specs/tbank-connection/spec.md) |
|
|
||||||
| Владелец синхронизации T-Bank, scheduling/priority | [T-Bank data sync](openspec/specs/tbank-data-sync/spec.md) |
|
|
||||||
| Часовой обход, результат последней попытки | [Hourly investment sync](openspec/specs/hourly-investment-sync/spec.md) |
|
|
||||||
| Счета/сводки | [Brokerage accounts](openspec/specs/brokerage-accounts/spec.md) |
|
|
||||||
| Portfolio positions/totals/stale | [Portfolio](openspec/specs/portfolio-view/spec.md) |
|
|
||||||
| История стоимости Portfolio | [Portfolio value history](openspec/specs/portfolio-value-history/spec.md) |
|
|
||||||
| Справочные сведения/поиск инструментов (online-only) | [Online instrument information](openspec/specs/online-instrument-information/spec.md) |
|
|
||||||
| Ручные дебетовые карты | [Manual bank cards](openspec/specs/manual-bank-cards/spec.md) |
|
|
||||||
| Операции/cursor/filters | [Account ledger](openspec/specs/brokerage-account-ledger/spec.md) |
|
|
||||||
| Будущие выплаты | [Upcoming events](openspec/specs/brokerage-account-upcoming-events/spec.md) |
|
|
||||||
| Доходы и периоды | [Income analytics](openspec/specs/brokerage-account-income-analytics/spec.md) |
|
|
||||||
| Shared tokens/theme | [Design system](openspec/specs/frontend-design-system/spec.md) |
|
|
||||||
| Каталог компонентов | [UI catalog](openspec/specs/frontend-ui-catalog/spec.md) |
|
|
||||||
| Loading/skeleton | [Loading presentation](openspec/specs/frontend-loading-presentation/spec.md) |
|
|
||||||
| UI error/recovery | [UI resilience](openspec/specs/frontend-ui-resilience/spec.md) |
|
|
||||||
| Тихое чтение и редкие уведомления | [User feedback](openspec/specs/frontend-user-feedback/spec.md) |
|
|
||||||
| Query coherence/cache | [Query coherence](openspec/specs/frontend-query-coherence/spec.md), [data resilience](openspec/specs/frontend-data-resilience/spec.md) |
|
|
||||||
| OpenAPI generation | [API contract generation](openspec/specs/api-contract-generation/spec.md) |
|
|
||||||
| Logging/request context | [Structured logging](openspec/specs/backend-structured-logging/spec.md) |
|
|
||||||
| Breadcrumb/navigation | [Breadcrumbs](openspec/specs/app-breadcrumb-navigation/spec.md) |
|
|
||||||
|
|
||||||
Process specs, active changes и archives сохраняют историю прежнего SDD workflow.
|
| Домен | Тема / trigger | Existing spec |
|
||||||
Они не являются обязательной процедурой текущей задачи. Для явно запрошенной
|
| --- | --- | --- |
|
||||||
работы с OpenSpec используй [отдельный вход](AGENTS.md).
|
| identity | Auth/session/refresh/error contract | [User authentication](openspec/specs/identity/user-authentication/spec.md) |
|
||||||
|
| tbank | T-Bank connection/security/cache generation | [T-Bank connection](openspec/specs/tbank/tbank-connection/spec.md) |
|
||||||
|
| tbank | Владелец синхронизации T-Bank, scheduling/priority | [T-Bank data sync](openspec/specs/tbank/tbank-data-sync/spec.md) |
|
||||||
|
| tbank | Часовой обход, результат последней попытки | [Hourly investment sync](openspec/specs/tbank/hourly-investment-sync/spec.md) |
|
||||||
|
| brokerage | Счета/сводки | [Brokerage accounts](openspec/specs/brokerage/brokerage-accounts/spec.md) |
|
||||||
|
| brokerage | Операции/cursor/filters | [Account ledger](openspec/specs/brokerage/brokerage-account-ledger/spec.md) |
|
||||||
|
| brokerage | Будущие выплаты | [Upcoming events](openspec/specs/brokerage/brokerage-account-upcoming-events/spec.md) |
|
||||||
|
| brokerage | Доходы и периоды | [Income analytics](openspec/specs/brokerage/brokerage-account-income-analytics/spec.md) |
|
||||||
|
| portfolio | Portfolio positions/totals/stale | [Portfolio](openspec/specs/portfolio/portfolio-view/spec.md) |
|
||||||
|
| portfolio | Вкладка «Концентрация»: топ-5 акций/облигаций/секторов/эмитентов | [Portfolio concentration](openspec/specs/portfolio/portfolio-concentration/spec.md) |
|
||||||
|
| portfolio | История стоимости Portfolio | [Portfolio value history](openspec/specs/portfolio/portfolio-value-history/spec.md) |
|
||||||
|
| instruments | Справочные сведения/поиск инструментов (online-only) | [Online instrument information](openspec/specs/instruments/online-instrument-information/spec.md) |
|
||||||
|
| instruments | Календарь купонов/дивидендов инструмента | [Instrument income schedules](openspec/specs/instruments/instrument-income-schedules/spec.md) |
|
||||||
|
| instruments | Скринер акций | [Stock screener](openspec/specs/instruments/stock-screener/spec.md) |
|
||||||
|
| banking | Ручные дебетовые карты | [Manual bank cards](openspec/specs/banking/manual-bank-cards/spec.md) |
|
||||||
|
| frontend-platform | Каркас приложения, маршруты MVP | [App shell](openspec/specs/frontend-platform/app-shell/spec.md) |
|
||||||
|
| frontend-platform | Shared tokens/theme | [Design system](openspec/specs/frontend-platform/frontend-design-system/spec.md) |
|
||||||
|
| frontend-platform | Каталог компонентов | [UI catalog](openspec/specs/frontend-platform/frontend-ui-catalog/spec.md) |
|
||||||
|
| frontend-platform | Loading/skeleton | [Loading presentation](openspec/specs/frontend-platform/frontend-loading-presentation/spec.md) |
|
||||||
|
| frontend-platform | UI error/recovery | [UI resilience](openspec/specs/frontend-platform/frontend-ui-resilience/spec.md) |
|
||||||
|
| frontend-platform | Тихое чтение и редкие уведомления | [User feedback](openspec/specs/frontend-platform/frontend-user-feedback/spec.md) |
|
||||||
|
| frontend-platform | Query coherence/cache | [Query coherence](openspec/specs/frontend-platform/frontend-query-coherence/spec.md), [data resilience](openspec/specs/frontend-platform/frontend-data-resilience/spec.md) |
|
||||||
|
| frontend-platform | Breadcrumb/navigation | [Breadcrumbs](openspec/specs/frontend-platform/app-breadcrumb-navigation/spec.md) |
|
||||||
|
| frontend-platform | Structural boundaries/bundle size/coverage | [Quality guardrails](openspec/specs/frontend-platform/frontend-quality-guardrails/spec.md) |
|
||||||
|
| backend-platform | `/api/v1`, CORS, безопасные ошибки | [HTTP API foundation](openspec/specs/backend-platform/http-api-foundation/spec.md) |
|
||||||
|
| backend-platform | OpenAPI generation | [API contract generation](openspec/specs/backend-platform/api-contract-generation/spec.md) |
|
||||||
|
| backend-platform | Logging/request context | [Structured logging](openspec/specs/backend-platform/backend-structured-logging/spec.md) |
|
||||||
|
|
||||||
|
Active changes и archives сохраняют историю прежнего SDD workflow. Они не
|
||||||
|
являются обязательной процедурой текущей задачи. Для явно запрошенной работы
|
||||||
|
с OpenSpec используй [отдельный вход](AGENTS.md).
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Источник и цель
|
## Источник и цель
|
||||||
|
|
||||||
Документ не выбирает внутренний способ загрузки и хранения. Обозначения **PC**, **PVΔ** и правило нумерации строк — в [system-analysis.md](system-analysis.md). Requirements: `specs/openspec/changes/account-top-positions/specs/portfolio-concentration/spec.md` (28) и `specs/openspec/changes/account-top-positions/specs/portfolio-view/spec.md` (4). Решения владельца: [3081](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081), [3082](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082). Исходы получения (когда поле заменяется, сохраняется или становится `null`, когда отсчёт 24 часов начинается заново) определяет таблица PVΔ:156; здесь она не пересказывается.
|
Документ не выбирает внутренний способ загрузки и хранения. Обозначения **PC**, **PVΔ** и правило нумерации строк — в [system-analysis.md](system-analysis.md). Requirements: `specs/openspec/changes/account-top-positions/specs/portfolio/portfolio-concentration/spec.md` (28) и `specs/openspec/changes/account-top-positions/specs/portfolio/portfolio-view/spec.md` (4). Решения владельца: [3081](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081), [3082](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082). Исходы получения (когда поле заменяется, сохраняется или становится `null`, когда отсчёт 24 часов начинается заново) определяет таблица PVΔ:156; здесь она не пересказывается.
|
||||||
|
|
||||||
| Mapping | Источник (владелец) | Цель (владелец) | Направление | Trigger |
|
| Mapping | Источник (владелец) | Цель (владелец) | Направление | Trigger |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
- PVΔ:104 «Свежесть и fallback полного Portfolio Snapshot» — хранимое последнее известное значение и исключение «отказ token».
|
- PVΔ:104 «Свежесть и fallback полного Portfolio Snapshot» — хранимое последнее известное значение и исключение «отказ token».
|
||||||
- PVΔ:3 «Нормализованный состав Portfolio» — сектор и эмитент не влияют на количество, стоимость, агрегаты, успешность и свежесть Snapshot, кроме отказа token.
|
- PVΔ:3 «Нормализованный состав Portfolio» — сектор и эмитент не влияют на количество, стоимость, агрегаты, успешность и свежесть Snapshot, кроме отказа token.
|
||||||
|
|
||||||
Финансовый Snapshot по-прежнему требует успешных GetPortfolio и GetPositions (`docs/domains/portfolio/flows/portfolio-loading.md:10-21`; `backend/src/modules/investments/portfolio/application/portfolio.service.ts:263-283`). Обычный GET и его повтор не обращаются к T-Bank (`specs/openspec/specs/tbank-data-sync/spec.md:9-14`). Новых очередей, блокировок, таблиц и библиотек модель не вводит; их выбор — design.
|
Финансовый Snapshot по-прежнему требует успешных GetPortfolio и GetPositions (`docs/domains/portfolio/flows/portfolio-loading.md:10-21`; `backend/src/modules/investments/portfolio/application/portfolio.service.ts:263-283`). Обычный GET и его повтор не обращаются к T-Bank (`specs/openspec/specs/tbank/tbank-data-sync/spec.md:9-14`). Новых очередей, блокировок, таблиц и библиотек модель не вводит; их выбор — design.
|
||||||
|
|
||||||
## Классификация отказов по исходам PVΔ:156
|
## Классификация отказов по исходам PVΔ:156
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
| Прочее | PERMISSION_DENIED / UNAUTHENTICATED → InvalidToken; NOT_FOUND → `NotFoundException` только для `shareBy` и `getInstrumentBy`; остальное → Unavailable | `backend/src/integrations/tbank/tbank.client.ts:571-583` |
|
| Прочее | PERMISSION_DENIED / UNAUTHENTICATED → InvalidToken; NOT_FOUND → `NotFoundException` только для `shareBy` и `getInstrumentBy`; остальное → Unavailable | `backend/src/integrations/tbank/tbank.client.ts:571-583` |
|
||||||
| Очередь и скорость | Общий лимитер клиента, очередь 50, по умолчанию 5 стартов/с (локальная настройка, не квота T-Bank) | `backend/src/integrations/tbank/tbank.client.ts:50-52,147-187,259-261`; `backend/src/config/env.validation.ts:5,29-31` |
|
| Очередь и скорость | Общий лимитер клиента, очередь 50, по умолчанию 5 стартов/с (локальная настройка, не квота T-Bank) | `backend/src/integrations/tbank/tbank.client.ts:50-52,147-187,259-261`; `backend/src/config/env.validation.ts:5,29-31` |
|
||||||
| Ожидание шага обхода | 900 000 мс; истечение не отменяет операцию | `backend/src/modules/investments/tbank-sync/tbank-hourly.scheduler.ts:28-33` |
|
| Ожидание шага обхода | 900 000 мс; истечение не отменяет операцию | `backend/src/modules/investments/tbank-sync/tbank-hourly.scheduler.ts:28-33` |
|
||||||
| Часовой обход | Не ранее 60 минут от старта прошлой попытки; без очереди пропущенных и без перекрытий | `specs/openspec/specs/hourly-investment-sync/spec.md:8-21` |
|
| Часовой обход | Не ранее 60 минут от старта прошлой попытки; без очереди пропущенных и без перекрытий | `specs/openspec/specs/tbank/hourly-investment-sync/spec.md:8-21` |
|
||||||
|
|
||||||
Две сетевые попытки по 15 с с паузой дают до 31 с без ожидания лимитера. Это не общий timeout цепочки «инструмент → актив». 15 минут планировщика не являются обещанием срока получения sector/brand.
|
Две сетевые попытки по 15 с с паузой дают до 31 с без ожидания лимитера. Это не общий timeout цепочки «инструмент → актив». 15 минут планировщика не являются обещанием срока получения sector/brand.
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
- Старые потребители игнорируют новые поля; Money и состояния ресурса не меняются.
|
- Старые потребители игнорируют новые поля; Money и состояния ресурса не меняются.
|
||||||
- Старый JSON не пересоздаётся; отсутствие ключей на HTTP-границе — `null`.
|
- Старый JSON не пересоздаётся; отсутствие ключей на HTTP-границе — `null`.
|
||||||
- Если metadata нет совсем, положительные позиции образуют группы «не указан», а не пустое состояние. Пустое состояние — только при отсутствии учтённых позиций (PC:451).
|
- Если metadata нет совсем, положительные позиции образуют группы «не указан», а не пустое состояние. Пустое состояние — только при отсутствии учтённых позиций (PC:451).
|
||||||
- Client cache не обходит `404`, отсутствие подключения и известный недействительный token (`specs/openspec/specs/portfolio-view/spec.md:150-157`).
|
- Client cache не обходит `404`, отсутствие подключения и известный недействительный token (`specs/openspec/specs/portfolio/portfolio-view/spec.md:150-157`).
|
||||||
- Ошибки sector/brand не попадают в `meta` Portfolio как причина неуспеха или устаревания. Отдельный статус качества metadata потребовал бы Specs.
|
- Ошибки sector/brand не попадают в `meta` Portfolio как причина неуспеха или устаревания. Отдельный статус качества metadata потребовал бы Specs.
|
||||||
|
|
||||||
## Открытые вопросы
|
## Открытые вопросы
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
|
|
||||||
[F] **[L7]** `backend/src/modules/investments/instruments/application/public-instrument.ts` — использование instrument metadata в публичном каталоге акций/облигаций, включая `sector`, `maturityDate`, `riskLevel`.
|
[F] **[L7]** `backend/src/modules/investments/instruments/application/public-instrument.ts` — использование instrument metadata в публичном каталоге акций/облигаций, включая `sector`, `maturityDate`, `riskLevel`.
|
||||||
|
|
||||||
[F] **[L8]** `specs/openspec/specs/portfolio-view/spec.md` — Portfolio Snapshot одного счёта, отсутствие валютной конвертации и итоги по валютам.
|
[F] **[L8]** `specs/openspec/specs/portfolio/portfolio-view/spec.md` — Portfolio Snapshot одного счёта, отсутствие валютной конвертации и итоги по валютам.
|
||||||
|
|
||||||
[F] **[L9]** `backend/src/integrations/tbank/proto/contracts/instruments.proto` — `AssetFull.brand` (~:1051-1067), `Brand` (:1220-1229), `asset_uid` у Share (:776), Bond (:543), Etf (:657); `Asset` (:1075-1080) без бренда; `BrandData` (`common.proto:120`) — только данные логотипа.
|
[F] **[L9]** `backend/src/integrations/tbank/proto/contracts/instruments.proto` — `AssetFull.brand` (~:1051-1067), `Brand` (:1220-1229), `asset_uid` у Share (:776), Bond (:543), Etf (:657); `Asset` (:1075-1080) без бренда; `BrandData` (`common.proto:120`) — только данные логотипа.
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
Документ приведён в соответствие с решениями владельца [3081](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081) и [3082](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082). G2 по комплекту Specs, system-analysis, data-mapping и failure-model approved (`process-record.md`, Gate Log, последняя строка G2). Технологии, внутренние компоненты и форма хранения здесь не проектируются.
|
Документ приведён в соответствие с решениями владельца [3081](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081) и [3082](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082). G2 по комплекту Specs, system-analysis, data-mapping и failure-model approved (`process-record.md`, Gate Log, последняя строка G2). Технологии, внутренние компоненты и форма хранения здесь не проектируются.
|
||||||
|
|
||||||
Обозначения. **PC** — `specs/openspec/changes/account-top-positions/specs/portfolio-concentration/spec.md`; **PVΔ** — `specs/openspec/changes/account-top-positions/specs/portfolio-view/spec.md`. Requirement указываются по названию заголовка: `PC «Название»`, `PVΔ «Название»`. Пути с `backend/`, `frontend/`, `docs/`, `specs/` отсчитываются от workspace WealthLedger.
|
Обозначения. **PC** — `specs/openspec/changes/account-top-positions/specs/portfolio/portfolio-concentration/spec.md`; **PVΔ** — `specs/openspec/changes/account-top-positions/specs/portfolio/portfolio-view/spec.md`. Requirement указываются по названию заголовка: `PC «Название»`, `PVΔ «Название»`. Пути с `backend/`, `frontend/`, `docs/`, `specs/` отсчитываются от workspace WealthLedger.
|
||||||
|
|
||||||
## Покрытие требований (Requirement Coverage)
|
## Покрытие требований (Requirement Coverage)
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
|
|
||||||
Участники: T-Bank Invest API → backend часовой синхронизации → сохранённый Portfolio Snapshot → backend HTTP API → авторизованный frontend. T-Bank владеет исходной классификацией и брендами, WealthLedger — нормализацией и представлением. Подтверждено `docs/architecture/context.md:9-38`, `docs/architecture/containers.md:9-33`, `docs/integrations/tbank.md:3-21`.
|
Участники: T-Bank Invest API → backend часовой синхронизации → сохранённый Portfolio Snapshot → backend HTTP API → авторизованный frontend. T-Bank владеет исходной классификацией и брендами, WealthLedger — нормализацией и представлением. Подтверждено `docs/architecture/context.md:9-38`, `docs/architecture/containers.md:9-33`, `docs/integrations/tbank.md:3-21`.
|
||||||
|
|
||||||
Сектор и бренд получает сервер в часовом обходе, не браузер и не открытие вкладки. Обычный GET и его повтор не обращаются к T-Bank (`specs/openspec/specs/tbank-data-sync/spec.md:9-14`; PVΔ «Свежесть и fallback полного Portfolio Snapshot», сценарий «Сектор и бренд читаются из хранимого значения»). MOEX, НКР и CDN логотипов не являются источниками sector/issuer.
|
Сектор и бренд получает сервер в часовом обходе, не браузер и не открытие вкладки. Обычный GET и его повтор не обращаются к T-Bank (`specs/openspec/specs/tbank/tbank-data-sync/spec.md:9-14`; PVΔ «Свежесть и fallback полного Portfolio Snapshot», сценарий «Сектор и бренд читаются из хранимого значения»). MOEX, НКР и CDN логотипов не являются источниками sector/issuer.
|
||||||
|
|
||||||
**Владелец расчёта разрезов — frontend над полным ответом Portfolio.** Подтверждено: Change Profile — «вкладка считается по уже загруженному Portfolio» (`specs/openspec/changes/account-top-positions/process-record.md:16`), impact в `proposal.md:60`. Specs закрепляют клиентский расчёт: имя эмитента выбирается по позиции с наибольшим `currentValue` в выбранной валюте (PC «Название эмитента при разных названиях бренда»), а валюта и учитываемость зависят от выбора пользователя (PC «Позиции, учитываемые в разрезе», PC «Одна валюта за раз»). Серверный агрегат такой выбор не воспроизвёл бы без параметров запроса, которых контракт не вводит. Backend-агрегаты, endpoint топ-5 и обращение браузера к каталогу не требуются.
|
**Владелец расчёта разрезов — frontend над полным ответом Portfolio.** Подтверждено: Change Profile — «вкладка считается по уже загруженному Portfolio» (`specs/openspec/changes/account-top-positions/process-record.md:16`), impact в `proposal.md:60`. Specs закрепляют клиентский расчёт: имя эмитента выбирается по позиции с наибольшим `currentValue` в выбранной валюте (PC «Название эмитента при разных названиях бренда»), а валюта и учитываемость зависят от выбора пользователя (PC «Позиции, учитываемые в разрезе», PC «Одна валюта за раз»). Серверный агрегат такой выбор не воспроизвёл бы без параметров запроса, которых контракт не вводит. Backend-агрегаты, endpoint топ-5 и обращение браузера к каталогу не требуются.
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
|
|
||||||
### As-Is: фактический путь
|
### As-Is: фактический путь
|
||||||
|
|
||||||
1. Часовой планировщик независимо от экрана обновляет membership и Portfolio счетов (`backend/src/modules/investments/tbank-sync/tbank-hourly.scheduler.ts:176-209`). Интервал и отсутствие перекрытий — `specs/openspec/specs/hourly-investment-sync/spec.md:8-21`.
|
1. Часовой планировщик независимо от экрана обновляет membership и Portfolio счетов (`backend/src/modules/investments/tbank-sync/tbank-hourly.scheduler.ts:176-209`). Интервал и отсутствие перекрытий — `specs/openspec/specs/tbank/hourly-investment-sync/spec.md:8-21`.
|
||||||
2. Для счёта параллельно запрашиваются GetPortfolio и GetPositions; после нормализации полный Snapshot публикуется, и только затем запрашивается обновление metadata позиций (`backend/src/modules/investments/portfolio/application/portfolio.service.ts:263-315`). Регистрация metadata-запроса не ждёт внешнего lookup (`backend/src/integrations/tbank/instrument-metadata.service.ts:63-105`).
|
2. Для счёта параллельно запрашиваются GetPortfolio и GetPositions; после нормализации полный Snapshot публикуется, и только затем запрашивается обновление metadata позиций (`backend/src/modules/investments/portfolio/application/portfolio.service.ts:263-315`). Регистрация metadata-запроса не ждёт внешнего lookup (`backend/src/integrations/tbank/instrument-metadata.service.ts:63-105`).
|
||||||
3. Snapshot хранится одним JSON payload; публикация транзакционна и ограждена connection revision, attempt и доступностью счёта (`backend/prisma/schema.prisma:60-70`; `backend/src/modules/investments/portfolio/infrastructure/portfolio.repository.ts:116-147`).
|
3. Snapshot хранится одним JSON payload; публикация транзакционна и ограждена connection revision, attempt и доступностью счёта (`backend/prisma/schema.prisma:60-70`; `backend/src/modules/investments/portfolio/infrastructure/portfolio.repository.ts:116-147`).
|
||||||
4. Mapper считает `currentValue` из quantity × currentPrice и заполняет `logoName` из metadata (`backend/src/modules/investments/portfolio/infrastructure/tbank-portfolio.mapper.ts:22-31,63-99`). Это прецедент необязательного обогащения.
|
4. Mapper считает `currentValue` из quantity × currentPrice и заполняет `logoName` из metadata (`backend/src/modules/investments/portfolio/infrastructure/tbank-portfolio.mapper.ts:22-31,63-99`). Это прецедент необязательного обогащения.
|
||||||
@@ -159,13 +159,13 @@ PC «Предупреждение о неполных данных» требу
|
|||||||
|
|
||||||
### Публикация и получение API artifact
|
### Публикация и получение API artifact
|
||||||
|
|
||||||
Backend генерирует и проверяет OpenAPI; потребителю явно передаётся новый artifact. Frontend обновляет versioned `src/shared/api/spec/openapi.json`, локально генерирует `src/shared/api/generated/schema.d.ts` и проверяет соответствие. Generated types вручную не правятся; frontend не читает backend checkout, runtime не требует Swagger. Основания: `specs/openspec/specs/api-contract-generation/spec.md:10-35`; `docs/architecture/http-api.md:5-22`; `frontend/.ai/conventions/data.md:15-34`.
|
Backend генерирует и проверяет OpenAPI; потребителю явно передаётся новый artifact. Frontend обновляет versioned `src/shared/api/spec/openapi.json`, локально генерирует `src/shared/api/generated/schema.d.ts` и проверяет соответствие. Generated types вручную не правятся; frontend не читает backend checkout, runtime не требует Swagger. Основания: `specs/openspec/specs/backend-platform/api-contract-generation/spec.md:10-35`; `docs/architecture/http-api.md:5-22`; `frontend/.ai/conventions/data.md:15-34`.
|
||||||
|
|
||||||
## Семантика ошибок
|
## Семантика ошибок
|
||||||
|
|
||||||
Новых бизнес-ошибок HTTP из-за sector/issuer нет, кроме отказа token. Результат получения определяет PVΔ «Результат получения сектора и эмитента»; `200` с группами «не указан» не означает сбой Snapshot (PVΔ «Нормализованный состав Portfolio»; PC «Группы «Сектор не указан» и «Эмитент не указан»», PC «Состояния Portfolio на вкладке «Концентрация»»).
|
Новых бизнес-ошибок HTTP из-за sector/issuer нет, кроме отказа token. Результат получения определяет PVΔ «Результат получения сектора и эмитента»; `200` с группами «не указан» не означает сбой Snapshot (PVΔ «Нормализованный состав Portfolio»; PC «Группы «Сектор не указан» и «Эмитент не указан»», PC «Состояния Portfolio на вкладке «Концентрация»»).
|
||||||
|
|
||||||
Отказ token при получении сектора или бренда обрабатывается как отказ token в обходе Portfolio: `400 INVALID_TBANK_TOKEN` без fallback Snapshot (PVΔ «Свежесть и fallback полного Portfolio Snapshot», сценарий «Отказ token при получении бренда»; `specs/openspec/specs/portfolio-view/spec.md:113-115`). Это соответствует текущему клиенту, сводящему PERMISSION_DENIED и UNAUTHENTICATED к InvalidToken (`backend/src/integrations/tbank/tbank.client.ts:571-575`).
|
Отказ token при получении сектора или бренда обрабатывается как отказ token в обходе Portfolio: `400 INVALID_TBANK_TOKEN` без fallback Snapshot (PVΔ «Свежесть и fallback полного Portfolio Snapshot», сценарий «Отказ token при получении бренда»; `specs/openspec/specs/portfolio/portfolio-view/spec.md:113-115`). Это соответствует текущему клиенту, сводящему PERMISSION_DENIED и UNAUTHENTICATED к InvalidToken (`backend/src/integrations/tbank/tbank.client.ts:571-575`).
|
||||||
|
|
||||||
Прочие ошибки доступа: нет подключения — `409 TBANK_NOT_CONNECTED`, недоступный счёт — `404` (`docs/domains/portfolio/flows/portfolio-loading.md:24-35`).
|
Прочие ошибки доступа: нет подключения — `409 TBANK_NOT_CONNECTED`, недоступный счёт — `404` (`docs/domains/portfolio/flows/portfolio-loading.md:24-35`).
|
||||||
|
|
||||||
@@ -4,7 +4,7 @@ Design описывает, как backend и frontend реализуют утв
|
|||||||
|
|
||||||
## Inputs
|
## Inputs
|
||||||
|
|
||||||
- Specs (G2 approved): `specs/portfolio-concentration/spec.md` (28 Requirement), `specs/portfolio-view/spec.md` (PVΔ «Нормализованный состав Portfolio», PVΔ «Свежесть и fallback полного Portfolio Snapshot», PVΔ «Обновление сектора и эмитента», PVΔ «Результат получения сектора и эмитента»).
|
- Specs (G2 approved): `specs/portfolio/portfolio-concentration/spec.md` (28 Requirement), `specs/portfolio/portfolio-view/spec.md` (PVΔ «Нормализованный состав Portfolio», PVΔ «Свежесть и fallback полного Portfolio Snapshot», PVΔ «Обновление сектора и эмитента», PVΔ «Результат получения сектора и эмитента»).
|
||||||
- Analysis (G2 approved): [system-analysis.md](analysis/system-analysis.md) (контракты, семантическая delta `PortfolioPositionDto`, заметка о дублировании Alert), [data-mapping.md](analysis/data-mapping.md) (M1–M3, источники-кандидаты в T-Bank, инварианты I1–I8), [failure-model.md](analysis/failure-model.md) (классификация исходов, F01–F16).
|
- Analysis (G2 approved): [system-analysis.md](analysis/system-analysis.md) (контракты, семантическая delta `PortfolioPositionDto`, заметка о дублировании Alert), [data-mapping.md](analysis/data-mapping.md) (M1–M3, источники-кандидаты в T-Bank, инварианты I1–I8), [failure-model.md](analysis/failure-model.md) (классификация исходов, F01–F16).
|
||||||
- Design package (G3): [ux-design.md](analysis/ux-design.md), Visual Package **v2** (`visuals/*.svg`, SHA-256 — в ux-design «Materials»).
|
- Design package (G3): [ux-design.md](analysis/ux-design.md), Visual Package **v2** (`visuals/*.svg`, SHA-256 — в ux-design «Materials»).
|
||||||
- Параллельно с design: [qa-analysis.md](analysis/qa-analysis.md) и `analysis/test-cases/` (oracle для расчётов).
|
- Параллельно с design: [qa-analysis.md](analysis/qa-analysis.md) и `analysis/test-cases/` (oracle для расчётов).
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
| G2 | 2026-10-30 | specs | — | system-analysis/ux-design: эмитент у фондов, обновление metadata, имя эмитента при расхождении, поведение вкладки (сохранение выбора в пределах страницы, скрытый Select, метрика ≤5, partial) | invalidated: решения владельца ([issuecomment-3081](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081)) меняют Specs |
|
| G2 | 2026-10-30 | specs | — | system-analysis/ux-design: эмитент у фондов, обновление metadata, имя эмитента при расхождении, поведение вкладки (сохранение выбора в пределах страницы, скрытый Select, метрика ≤5, partial) | invalidated: решения владельца ([issuecomment-3081](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081)) меняют Specs |
|
||||||
| G2 | 2026-10-30 | specs, system-analysis, data-mapping, failure-model | `openspec@1.13.1 validate --strict` valid; `validate --specs` 33/33; `git diff --check` OK; readiness: plan OK; Coverage 32/32 | G2 rev2/rev3 review independent-reviewer + qa-engineer: 1 blocker (B1 — противоречие canonical «Свежесть и fallback»), 3 major, ~8 minor — закрыты решениями владельца ([3081](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081), [3082](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082)) и правками; финальный re-review: ready | approved "ок, давай дальше" |
|
| G2 | 2026-10-30 | specs, system-analysis, data-mapping, failure-model | `openspec@1.13.1 validate --strict` valid; `validate --specs` 33/33; `git diff --check` OK; readiness: plan OK; Coverage 32/32 | G2 rev2/rev3 review independent-reviewer + qa-engineer: 1 blocker (B1 — противоречие canonical «Свежесть и fallback»), 3 major, ~8 minor — закрыты решениями владельца ([3081](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081), [3082](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082)) и правками; финальный re-review: ready | approved "ок, давай дальше" |
|
||||||
| G3 | 2026-10-31 | design, ux-design, qa-analysis, test-cases, docs-impact, tasks | `openspec@1.13.1 validate --strict` valid; `git diff --check` OK; readiness: apply OK; Visual Package v2 SHA-256 сверены reviewer; Coverage 32/32 | G3 review independent-reviewer + frontend-engineer: 4 major, 4 minor, Q2 — закрыты; backend-engineer не выполнен (квота API), backend-утверждения design сверены основным агентом с кодом; повторный review: ready. Включает изменение вне Specs: подпись «Государственный сектор» на странице акции и в каталогах (3084) | approved "да, все окей, идем дальше" |
|
| G3 | 2026-10-31 | design, ux-design, qa-analysis, test-cases, docs-impact, tasks | `openspec@1.13.1 validate --strict` valid; `git diff --check` OK; readiness: apply OK; Visual Package v2 SHA-256 сверены reviewer; Coverage 32/32 | G3 review independent-reviewer + frontend-engineer: 4 major, 4 minor, Q2 — закрыты; backend-engineer не выполнен (квота API), backend-утверждения design сверены основным агентом с кодом; повторный review: ready. Включает изменение вне Specs: подпись «Государственный сектор» на странице акции и в каталогах (3084) | approved "да, все окей, идем дальше" |
|
||||||
|
| G4 | 2026-11-02 | archive | Код и docs в `develop`: backend 17432df, frontend 70a2c33, docs 37430da; `openspec@1.13.1 validate --strict` valid | Independent Review, QA и проверка отката не выполнялись | archived without verification: решение владельца в сессии specs#74 (descope 3.1–3.4, 5.1) |
|
||||||
|
|
||||||
Примечание к G2 (2026-10-30): GIVEN «сектор и бренд актива позиции ещё ни разу не получены» в Scenario «Недоступность сектора и эмитента не нарушает Snapshot» (finding N1) и замена строки design-обязательства в failure-model (N2) внесены основным агентом до записи approved G2 и входят в утверждённую версию.
|
Примечание к G2 (2026-10-30): GIVEN «сектор и бренд актива позиции ещё ни разу не получены» в Scenario «Недоступность сектора и эмитента не нарушает Snapshot» (finding N1) и замена строки design-обязательства в failure-model (N2) внесены основным агентом до записи approved G2 и входят в утверждённую версию.
|
||||||
|
|
||||||
@@ -37,6 +38,11 @@
|
|||||||
|
|
||||||
| Task | Причина | Gate |
|
| Task | Причина | Gate |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
|
| 3.1 Independent Review | Владелец решил архивировать без G4: код и docs уже в `develop` и релизах | G4 |
|
||||||
|
| 3.2 QA test-cases | Владелец решил архивировать без G4: код и docs уже в `develop` и релизах | G4 |
|
||||||
|
| 3.3 QA exploratory | Владелец решил архивировать без G4: код и docs уже в `develop` и релизах | G4 |
|
||||||
|
| 3.4 Откат backend | Владелец решил архивировать без G4: код и docs уже в `develop` и релизах | G4 |
|
||||||
|
| 5.1 Запись G4 с evidence | Владелец решил архивировать без G4: код и docs уже в `develop` и релизах | G4 |
|
||||||
|
|
||||||
## Lab Journal
|
## Lab Journal
|
||||||
|
|
||||||
@@ -48,11 +48,11 @@ Issue: WealthLedger/main#48
|
|||||||
|
|
||||||
### New Capabilities
|
### New Capabilities
|
||||||
|
|
||||||
- `specs/portfolio-concentration/spec.md`: вкладка «Концентрация» — разрезы, ранжирование топ-5, «Прочее», доли и суммарная доля топ-5, выбор валюты, правила учёта позиций, состояния.
|
- `specs/portfolio/portfolio-concentration/spec.md`: вкладка «Концентрация» — разрезы, ранжирование топ-5, «Прочее», доли и суммарная доля топ-5, выбор валюты, правила учёта позиций, состояния.
|
||||||
|
|
||||||
### Modified Capabilities
|
### Modified Capabilities
|
||||||
|
|
||||||
- `specs/portfolio-view/spec.md`: нормализованный состав Portfolio расширяется сектором и эмитентом позиции (требование «Нормализованный состав Portfolio»); добавляются требования о сроке обновления, последнем известном значении и ошибках получения сектора и эмитента. Требование «Точные значения и валютные агрегаты» не меняется; новая capability `portfolio-concentration` на него ссылается.
|
- `specs/portfolio/portfolio-view/spec.md`: нормализованный состав Portfolio расширяется сектором и эмитентом позиции (требование «Нормализованный состав Portfolio»); добавляются требования о сроке обновления, последнем известном значении и ошибках получения сектора и эмитента. Требование «Точные значения и валютные агрегаты» не меняется; новая capability `portfolio-concentration` на него ссылается.
|
||||||
|
|
||||||
## Impact
|
## Impact
|
||||||
|
|
||||||
@@ -84,8 +84,8 @@ Issue: WealthLedger/main#48
|
|||||||
|
|
||||||
- [F] Потребность: показать крупнейшие акции, облигации и секторы по денежной оценке с переключением критерия и диаграммой распределения. Источник: запрос Change Owner, WealthLedger/main#48; `analysis/research.md`, Problem Statement.
|
- [F] Потребность: показать крупнейшие акции, облигации и секторы по денежной оценке с переключением критерия и диаграммой распределения. Источник: запрос Change Owner, WealthLedger/main#48; `analysis/research.md`, Problem Statement.
|
||||||
- [F] Страница счёта уже содержит распределение по классам активов с выбором одной валюты и вкладку «Позиции» с разделением «Акции / Облигации / Прочее». Источник: `analysis/research.md`, Problem Statement.
|
- [F] Страница счёта уже содержит распределение по классам активов с выбором одной валюты и вкладку «Позиции» с разделением «Акции / Облигации / Прочее». Источник: `analysis/research.md`, Problem Statement.
|
||||||
- [F] Каноническая `portfolio-view` фиксирует отсутствие валютной конвертации и отдельные итоги по каждой валюте; позиция без вычислимой текущей стоимости остаётся в ответе, но не входит в агрегаты; в Portfolio входят только позиции с ненулевым количеством. Источник: `specs/portfolio-view/spec.md`, требования «Нормализованный состав Portfolio», «Точные значения и валютные агрегаты».
|
- [F] Каноническая `portfolio-view` фиксирует отсутствие валютной конвертации и отдельные итоги по каждой валюте; позиция без вычислимой текущей стоимости остаётся в ответе, но не входит в агрегаты; в Portfolio входят только позиции с ненулевым количеством. Источник: `specs/portfolio/portfolio-view/spec.md`, требования «Нормализованный состав Portfolio», «Точные значения и валютные агрегаты».
|
||||||
- [F] Карточки позиций показывают долю позиции среди позиций той же валюты. Источник: `specs/portfolio-view/spec.md`, требование «Представление карточек позиций на клиенте».
|
- [F] Карточки позиций показывают долю позиции среди позиций той же валюты. Источник: `specs/portfolio/portfolio-view/spec.md`, требование «Представление карточек позиций на клиенте».
|
||||||
- [F] Текущие данные позиции Portfolio не содержат сектора и эмитента. Источник: `analysis/research.md` [L4].
|
- [F] Текущие данные позиции Portfolio не содержат сектора и эмитента. Источник: `analysis/research.md` [L4].
|
||||||
- [F] Сектор есть у инструментов Share, Bond и Etf в интеграционном описании T-Bank. Источник: `backend/src/integrations/tbank/proto/contracts/instruments.proto` (Share, Bond, Etf, поле `sector`).
|
- [F] Сектор есть у инструментов Share, Bond и Etf в интеграционном описании T-Bank. Источник: `backend/src/integrations/tbank/proto/contracts/instruments.proto` (Share, Bond, Etf, поле `sector`).
|
||||||
- [F] Бренд с компанией и сектором (`Brand`, :1220-1229) доступен в полном описании актива `AssetFull.brand` (:1051-1067). Краткое описание актива `Asset` бренда не содержит, а `BrandData` внутри инструментов хранит только данные логотипа. Ссылка инструмента на актив (`asset_uid`) есть у Share (:776), Bond (:543) и Etf (:657). Источник: тот же `instruments.proto`; `analysis/research.md` [L9].
|
- [F] Бренд с компанией и сектором (`Brand`, :1220-1229) доступен в полном описании актива `AssetFull.brand` (:1051-1067). Краткое описание актива `Asset` бренда не содержит, а `BrandData` внутри инструментов хранит только данные логотипа. Ссылка инструмента на актив (`asset_uid`) есть у Share (:776), Bond (:543) и Etf (:657). Источник: тот же `instruments.proto`; `analysis/research.md` [L9].
|
||||||
@@ -110,25 +110,25 @@ Issue-координатор: [WealthLedger/main#48](https://git.personal.ksv741
|
|||||||
|
|
||||||
## 3. Review и QA до G4
|
## 3. Review и QA до G4
|
||||||
|
|
||||||
- [ ] 3.1 [specs] Independent Review: read-only review backend и frontend PR против Specs, design и analysis
|
- [x] 3.1 ~~[specs] Independent Review: read-only review backend и frontend PR против Specs, design и analysis~~ (descoped, см. process-record)
|
||||||
- **Covers:** `portfolio-view` — `Результат получения сектора и эмитента`; `portfolio-concentration` — `Расчёт долей`
|
- **Covers:** `portfolio-view` — `Результат получения сектора и эмитента`; `portfolio-concentration` — `Расчёт долей`
|
||||||
- **Source:** design.md целиком; analysis/system-analysis.md; analysis/failure-model.md
|
- **Source:** design.md целиком; analysis/system-analysis.md; analysis/failure-model.md
|
||||||
- **Verification:** отчёт review приложен к Gate Log G4 в process-record; blocker/major закрыты или возвращены в upstream-артефакт
|
- **Verification:** отчёт review приложен к Gate Log G4 в process-record; blocker/major закрыты или возвращены в upstream-артефакт
|
||||||
- **Depends on:** 1.8, 2.9
|
- **Depends on:** 1.8, 2.9
|
||||||
|
|
||||||
- [ ] 3.2 [specs] QA Verification: прогон test-cases на локальном backend + frontend
|
- [x] 3.2 ~~[specs] QA Verification: прогон test-cases на локальном backend + frontend~~ (descoped, см. process-record)
|
||||||
- **Covers:** `portfolio-view` — `Обновление сектора и эмитента`; `portfolio-view` — `Свежесть и fallback полного Portfolio Snapshot`; `portfolio-concentration` — `Состояния Portfolio на вкладке «Концентрация»`
|
- **Covers:** `portfolio-view` — `Обновление сектора и эмитента`; `portfolio-view` — `Свежесть и fallback полного Portfolio Snapshot`; `portfolio-concentration` — `Состояния Portfolio на вкладке «Концентрация»`
|
||||||
- **Source:** analysis/qa-analysis.md «Coverage Matrix», «Entry / Exit Criteria»; analysis/test-cases/conc.md, meta.md, reg.md
|
- **Source:** analysis/qa-analysis.md «Coverage Matrix», «Entry / Exit Criteria»; analysis/test-cases/conc.md, meta.md, reg.md
|
||||||
- **Verification:** результаты TC-CONC-002/005/006/007/008/015/016/020/024/027, TC-META-002/003/004/005, TC-REG-001/004 записаны pass/fail; F01–F16 покрыты; ручной блок (макеты v2, контраст, клавиатура, скринридер) зафиксирован
|
- **Verification:** результаты TC-CONC-002/005/006/007/008/015/016/020/024/027, TC-META-002/003/004/005, TC-REG-001/004 записаны pass/fail; F01–F16 покрыты; ручной блок (макеты v2, контраст, клавиатура, скринридер) зафиксирован
|
||||||
- **Depends on:** 1.8, 2.9
|
- **Depends on:** 1.8, 2.9
|
||||||
|
|
||||||
- [ ] 3.3 [specs] QA Verification: exploratory Q-D1/Q-D2/Q-F3 на реальном токене владельца
|
- [x] 3.3 ~~[specs] QA Verification: exploratory Q-D1/Q-D2/Q-F3 на реальном токене владельца~~ (descoped, см. process-record)
|
||||||
- **Covers:** `portfolio-view` — `Обновление сектора и эмитента`; `portfolio-concentration` — `Группы «Сектор не указан» и «Эмитент не указан»`
|
- **Covers:** `portfolio-view` — `Обновление сектора и эмитента`; `portfolio-concentration` — `Группы «Сектор не указан» и «Эмитент не указан»`
|
||||||
- **Source:** analysis/qa-analysis.md «Gaps / Blockers», «Test Data and Environment Needs»; решение владельца [3084](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3084)
|
- **Source:** analysis/qa-analysis.md «Gaps / Blockers», «Test Data and Environment Needs»; решение владельца [3084](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3084)
|
||||||
- **Verification:** записаны полнота сектора и бренда у позиций владельца (доля стоимости без значения, наличие `government` и фондов без сектора), число RPC и длительность первого обхода, отсутствие RESOURCE_EXHAUSTED / queue full; шаг Portfolio укладывается в `WORK_WAIT_BOUND_MS`
|
- **Verification:** записаны полнота сектора и бренда у позиций владельца (доля стоимости без значения, наличие `government` и фондов без сектора), число RPC и длительность первого обхода, отсутствие RESOURCE_EXHAUSTED / queue full; шаг Portfolio укладывается в `WORK_WAIT_BOUND_MS`
|
||||||
- **Depends on:** 3.2
|
- **Depends on:** 3.2
|
||||||
|
|
||||||
- [ ] 3.4 [backend] Verification: откат backend-bundle на копии данных до G4
|
- [x] 3.4 ~~[backend] Verification: откат backend-bundle на копии данных до G4~~ (descoped, см. process-record)
|
||||||
- **Covers:** N/A — проверка отката (design.md «Migration / Rollout / Rollback»)
|
- **Covers:** N/A — проверка отката (design.md «Migration / Rollout / Rollback»)
|
||||||
- **Source:** design.md «Migration / Rollout / Rollback» (Backend); `deploy/README.md` «Ручной откат и восстановление»; `docs/architecture/deployment.md` «Откат image»
|
- **Source:** design.md «Migration / Rollout / Rollback» (Backend); `deploy/README.md` «Ручной откат и восстановление»; `docs/architecture/deployment.md` «Откат image»
|
||||||
- **Verification:** на disposable копии БД с применённой миграцией `TbankInstrumentClassification`: (1) предыдущий backend-image, запущенный как при ручном откате (`up --no-deps backend`, без сервиса `migration`), проходит healthcheck, GET Portfolio отвечает `200` на Snapshot с полями `sector`/`issuer`; (2) из предыдущего image `node node_modules/prisma/build/index.js migrate status` и `migrate deploy` — записаны exit code и вывод (ожидание: status сообщает о миграции, отсутствующей локально; deploy не падает). Результат записан в Gate Log G4; при падении deploy — finding в design
|
- **Verification:** на disposable копии БД с применённой миграцией `TbankInstrumentClassification`: (1) предыдущий backend-image, запущенный как при ручном откате (`up --no-deps backend`, без сервиса `migration`), проходит healthcheck, GET Portfolio отвечает `200` на Snapshot с полями `sector`/`issuer`; (2) из предыдущего image `node node_modules/prisma/build/index.js migrate status` и `migrate deploy` — записаны exit code и вывод (ожидание: status сообщает о миграции, отсутствующей локально; deploy не падает). Результат записан в Gate Log G4; при падении deploy — finding в design
|
||||||
@@ -174,13 +174,13 @@ Issue-координатор: [WealthLedger/main#48](https://git.personal.ksv741
|
|||||||
|
|
||||||
## 5. Specs: G4 и завершение change
|
## 5. Specs: G4 и завершение change
|
||||||
|
|
||||||
- [ ] 5.1 [specs] Verification: запись G4 в process-record с evidence задач 1–4
|
- [x] 5.1 ~~[specs] Verification: запись G4 в process-record с evidence задач 1–4~~ (descoped, см. process-record)
|
||||||
- **Covers:** N/A — gate протокол
|
- **Covers:** N/A — gate протокол
|
||||||
- **Source:** instruction `process-record` (Readiness Checklist, Gate Log)
|
- **Source:** instruction `process-record` (Readiness Checklist, Gate Log)
|
||||||
- **Verification:** `npx -y @fission-ai/openspec@1.13.1 validate account-top-positions --store wealth-ledger-specs --strict` valid; `git diff --check` чист; строка G4 содержит ссылки на PR, отчёты 3.1–3.3 и решение владельца
|
- **Verification:** `npx -y @fission-ai/openspec@1.13.1 validate account-top-positions --store wealth-ledger-specs --strict` valid; `git diff --check` чист; строка G4 содержит ссылки на PR, отчёты 3.1–3.3 и решение владельца
|
||||||
- **Depends on:** 3.1, 3.2, 3.3, 3.4, 4.6
|
- **Depends on:** 3.1, 3.2, 3.3, 3.4, 4.6
|
||||||
|
|
||||||
- [ ] 5.2 [specs] Verification: native archive change после G4 и PR в `develop` со ссылкой на WealthLedger/main#48
|
- [x] 5.2 [specs] Verification: native archive change после G4 и PR в `develop` со ссылкой на WealthLedger/main#48
|
||||||
- **Covers:** N/A — native sync/archive выполняет CLI, canonical specs вручную не правятся
|
- **Covers:** N/A — native sync/archive выполняет CLI, canonical specs вручную не правятся
|
||||||
- **Source:** schema `wealth-ledger-sdd-lab` apply/archive instruction; `.ai/conventions/engineering-workflow.md` «Merge → Issue Closed»
|
- **Source:** schema `wealth-ledger-sdd-lab` apply/archive instruction; `.ai/conventions/engineering-workflow.md` «Merge → Issue Closed»
|
||||||
- **Verification:** `npx -y @fission-ai/openspec@1.13.1 archive account-top-positions --store wealth-ledger-specs` завершён; `openspec validate --all --strict` valid; PR specs открыт; Issue main#48 закрывается после merge всех PR
|
- **Verification:** `npx -y @fission-ai/openspec@1.13.1 archive account-top-positions --store wealth-ledger-specs` завершён; `openspec validate --all --strict` valid; PR specs открыт; Issue main#48 закрывается после merge всех PR
|
||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@@ -12,7 +12,15 @@ context: |
|
|||||||
`wealth-ledger-sdd` keep their original proposal → specs → design → tasks → apply
|
`wealth-ledger-sdd` keep their original proposal → specs → design → tasks → apply
|
||||||
lifecycle and existing approvals until completion. Never infer approval from
|
lifecycle and existing approvals until completion. Never infer approval from
|
||||||
the existence of an artifact. Schema selection comes from each change's
|
the existence of an artifact. Schema selection comes from each change's
|
||||||
`.openspec.yaml`, not from the current default.
|
`.openspec.yaml`, not from the current default. The Change Owner is the Product
|
||||||
|
Owner for product behavior and the Engineering Owner for technical/process changes.
|
||||||
|
A session handoff never stores requirements, design or tasks and never proves an
|
||||||
|
approval; a new session without an explicitly confirmed approval does not start
|
||||||
|
downstream work. Versioned planning, spec, task and design artifacts live only in
|
||||||
|
`specs/openspec`, never in framework-specific folders elsewhere.
|
||||||
|
Canonical specs are grouped by domain as `specs/<domain>/<capability>/spec.md`;
|
||||||
|
a delta uses the same path. Process rules belong to workspace conventions, this
|
||||||
|
config and schemas, not to canonical specs.
|
||||||
|
|
||||||
Repository responsibilities and sources of truth:
|
Repository responsibilities and sources of truth:
|
||||||
- `main` (`./`): workspace instructions, shared configuration, development Compose
|
- `main` (`./`): workspace instructions, shared configuration, development Compose
|
||||||
@@ -67,3 +75,6 @@ operations:
|
|||||||
- Keep the change's selected schema and explicit approvals; do not impose v2-only artifacts on legacy changes.
|
- Keep the change's selected schema and explicit approvals; do not impose v2-only artifacts on legacy changes.
|
||||||
- Complete implementation, developer checks, independent verification and canonical documentation before archive. For v2 changes, also check applicable QA Analysis, docs-impact and target contract compatibility with backend-generated OpenAPI.
|
- Complete implementation, developer checks, independent verification and canonical documentation before archive. For v2 changes, also check applicable QA Analysis, docs-impact and target contract compatibility with backend-generated OpenAPI.
|
||||||
- Native OpenSpec sync/archive updates canonical behavior specs, not implementation documentation.
|
- Native OpenSpec sync/archive updates canonical behavior specs, not implementation documentation.
|
||||||
|
- Independent verification is read-only (no edits to code, specs or tasks) and returns PASS, FAIL or SPEC_ISSUE routed to the earliest affected artifact. For UI changes it compares implemented screens, states, interactions and responsive behavior with the approved visual package.
|
||||||
|
- Archive only after the latest PASS with no Critical or Important findings and no relevant input changes since; archive routes blockers instead of fixing them.
|
||||||
|
- Completion evidence is written after the work and records, per affected repo, the commit, exact commands with observed results, N/A reasons and the review outcome. Never create empty commits to mark an unaffected repo.
|
||||||
|
|||||||
@@ -1,306 +0,0 @@
|
|||||||
# agent-sdd-session-workflow Specification
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
Определяет воспроизводимый session-oriented workflow для AI-assisted SDD,
|
|
||||||
сохраняющий OpenSpec единственным источником спецификации и границы независимых
|
|
||||||
инженерных ролей.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
### Requirement: Каждая agent-сессия имеет одну SDD-роль
|
|
||||||
|
|
||||||
Session-oriented SDD workflow SHALL направлять каждую agent-сессию ровно в одну
|
|
||||||
роль: Discovery, Specification, Implementation, Validation или Finalization.
|
|
||||||
Сессия MUST NOT самостоятельно выполнять следующую роль, но создание immutable
|
|
||||||
phase record или ожидание решения MUST NOT само по себе принуждать к новой
|
|
||||||
сессии той же роли. Specification MUST поддерживать bounded progression
|
|
||||||
`Proposal + Delta Specs` и `Design + Tasks`, сохраняя отдельную explicit
|
|
||||||
approval boundary перед каждым downstream artifact. Для `wealth-ledger-sdd-v2`
|
|
||||||
Specification SHALL также поддерживать System Analysis после Delta Specs,
|
|
||||||
параллельные Design и QA Analysis после System Analysis, Docs Impact после
|
|
||||||
обоих и Tasks после Docs Impact. Для active `wealth-ledger-sdd` сохраняются
|
|
||||||
прежние пары и approvals без автоматической миграции.
|
|
||||||
|
|
||||||
#### Scenario: Начинается новый change
|
|
||||||
|
|
||||||
- **WHEN** пользователь начинает SDD-workflow для нового change
|
|
||||||
- **THEN** workflow направляет сессию только в Discovery и не начинает
|
|
||||||
Specification, Implementation, Validation или Finalization в той же сессии
|
|
||||||
|
|
||||||
#### Scenario: Specification подготавливает planning artifact
|
|
||||||
|
|
||||||
- **WHEN** Specification подготовила structurally valid Proposal
|
|
||||||
- **THEN** workflow запрашивает явный approval Change Owner и не создаёт Delta
|
|
||||||
Specs до получения решения
|
|
||||||
|
|
||||||
#### Scenario: Proposal явно одобрен
|
|
||||||
|
|
||||||
- **WHEN** Change Owner явно одобряет неизменившийся Proposal в bounded
|
|
||||||
`Proposal + Delta Specs` progression
|
|
||||||
- **THEN** Specification MAY продолжить в той же роли и создать Delta Specs без
|
|
||||||
перехода к Design или другой SDD-роли
|
|
||||||
|
|
||||||
#### Scenario: Delta Specs явно одобрены
|
|
||||||
|
|
||||||
- **WHEN** Change Owner явно одобряет неизменившиеся Delta Specs
|
|
||||||
- **THEN** workflow завершает bounded `Proposal + Delta Specs` progression и
|
|
||||||
направляет следующий Specification outcome к Design для legacy либо к System Analysis для v2
|
|
||||||
|
|
||||||
#### Scenario: Design явно одобрен
|
|
||||||
|
|
||||||
- **WHEN** Change Owner явно одобряет неизменившийся Design в bounded
|
|
||||||
`Design + Tasks` progression
|
|
||||||
- **THEN** для legacy Specification MAY продолжить в той же роли и создать Tasks;
|
|
||||||
для v2 Tasks ожидает также QA Analysis и Docs Impact; Implementation ждёт отдельного approval Tasks
|
|
||||||
|
|
||||||
#### Scenario: Завершилась реализация
|
|
||||||
|
|
||||||
- **WHEN** Implementation завершает все утверждённые implementation-owned Tasks
|
|
||||||
- **THEN** workflow фиксирует результат Implementation как вход для следующей
|
|
||||||
Validation-сессии и не выполняет Validation в завершившейся
|
|
||||||
Implementation-сессии
|
|
||||||
|
|
||||||
### Requirement: Продолжение workflow восстанавливает только нужный контекст
|
|
||||||
|
|
||||||
Workflow SHALL однозначно определять текущую роль и разрешённый outcome из
|
|
||||||
сохранённого состояния change и одного актуального self-contained handoff. Он
|
|
||||||
MUST загружать только phase-specific canonical authority и изменившийся
|
|
||||||
relevant evidence, а не полную историю, прежние handoff-данные или уже
|
|
||||||
прочитанные неизменившиеся inputs. После появления OpenSpec change его approved
|
|
||||||
artifacts MUST быть источником intent, requirements, design и tasks.
|
|
||||||
|
|
||||||
Specification при подготовке Design SHALL определять применимый визуальный
|
|
||||||
пакет в canonical Design. При продолжении после его approval Implementation и
|
|
||||||
Validation SHALL получать применимые визуальные материалы именно согласованной
|
|
||||||
версии из canonical Design, сохраняя одну роль сессии и не создавая копию Design
|
|
||||||
в handoff. Недоступность или неоднозначность согласованного пакета MUST быть
|
|
||||||
сообщена как блокер зависимой работы и MUST NOT компенсироваться догадкой по
|
|
||||||
истории обсуждения или текущему внешнему макету.
|
|
||||||
|
|
||||||
#### Scenario: Пользователь продолжает change после другой сессии
|
|
||||||
|
|
||||||
- **WHEN** пользователь запрашивает продолжение известного change
|
|
||||||
- **THEN** workflow определяет ровно одну текущую роль, читает только актуальный
|
|
||||||
handoff и применимую canonical authority этой роли
|
|
||||||
|
|
||||||
#### Scenario: Есть история нескольких попыток
|
|
||||||
|
|
||||||
- **WHEN** change содержит более старые records или результаты прежних попыток
|
|
||||||
- **THEN** workflow не загружает их по умолчанию и обращается к ним только для
|
|
||||||
расследования конкретной проблемы текущей роли
|
|
||||||
|
|
||||||
#### Scenario: Независимые evidence доступны одновременно
|
|
||||||
|
|
||||||
- **WHEN** до следующего смыслового решения нужны несколько независимых
|
|
||||||
read-only inputs
|
|
||||||
- **THEN** workflow получает их одним bounded batch и сохраняет полный relevant
|
|
||||||
scope для failure или review findings
|
|
||||||
|
|
||||||
#### Scenario: Успешный gate уже выполнен на неизменившихся inputs
|
|
||||||
|
|
||||||
- **WHEN** успешный gate был выполнен и его relevant inputs после этого не
|
|
||||||
изменялись
|
|
||||||
- **THEN** workflow использует сохранённый observed outcome и не повторяет gate
|
|
||||||
без причины
|
|
||||||
|
|
||||||
#### Scenario: Specification готовит Design с визуальными материалами
|
|
||||||
|
|
||||||
- **WHEN** Specification получила разрешение подготовить Design с применимым
|
|
||||||
UI/UX scope
|
|
||||||
- **THEN** она представляет визуальные материалы как часть одного canonical
|
|
||||||
Design и останавливается до его единого approval, не начиная другую роль
|
|
||||||
|
|
||||||
#### Scenario: Implementation получает утверждённый визуальный Design
|
|
||||||
|
|
||||||
- **WHEN** Implementation начинает разрешённую реализацию UI change
|
|
||||||
- **THEN** она использует применимый пакет согласованной версии из canonical
|
|
||||||
Design, а навигационный handoff не заменяет его содержимое или owner approval
|
|
||||||
|
|
||||||
#### Scenario: Пакет невозможно однозначно восстановить
|
|
||||||
|
|
||||||
- **WHEN** следующая роль не может получить применимые материалы или установить
|
|
||||||
согласованную версию
|
|
||||||
- **THEN** зависимая работа останавливается с конкретным блокером до
|
|
||||||
восстановления пакета либо разрешения вопроса на соответствующей planning boundary
|
|
||||||
|
|
||||||
### Requirement: Handoff не заменяет canonical OpenSpec authority
|
|
||||||
|
|
||||||
Workflow handoff SHALL сохранять только состояние перехода, краткий observed
|
|
||||||
result, известные блокеры и один следующий допустимый outcome. Navigation state
|
|
||||||
MAY сохранять approval status текущих planning artifacts для продолжения
|
|
||||||
workflow, но handoff и state MUST NOT становиться альтернативным хранилищем
|
|
||||||
Requirements, Delta Specs, Design, Tasks или acceptance scenarios и MUST NOT
|
|
||||||
считаться самостоятельным доказательством решения Change Owner.
|
|
||||||
|
|
||||||
#### Scenario: Specification уже завершена
|
|
||||||
|
|
||||||
- **WHEN** следующая роль получает handoff после Specification
|
|
||||||
- **THEN** она использует approved OpenSpec artifacts для требований и решений,
|
|
||||||
а handoff — только для маршрутизации, observed results и известных
|
|
||||||
ограничений
|
|
||||||
|
|
||||||
#### Scenario: Approval подтверждён для неизменившегося artifact
|
|
||||||
|
|
||||||
- **WHEN** новый Specification context содержит сохранённый approved status и
|
|
||||||
workflow не изменял соответствующий planning artifact
|
|
||||||
- **THEN** workflow продолжает к разрешённому downstream artifact без
|
|
||||||
повторного запроса того же approval
|
|
||||||
|
|
||||||
#### Scenario: Workflow изменяет planning artifact
|
|
||||||
|
|
||||||
- **WHEN** workflow семантически изменяет planning artifact
|
|
||||||
- **THEN** approval этого artifact и всех зависимых downstream artifacts
|
|
||||||
сбрасывается до нового явного решения Change Owner
|
|
||||||
|
|
||||||
#### Scenario: Требование нужно изменить во время реализации
|
|
||||||
|
|
||||||
- **WHEN** Implementation обнаруживает, что requirement или архитектурное
|
|
||||||
решение неполно либо противоречиво
|
|
||||||
- **THEN** workflow возвращает работу к самой ранней затронутой canonical
|
|
||||||
planning boundary и не изменяет требование только в handoff или реализации
|
|
||||||
|
|
||||||
### Requirement: Validation остаётся независимой и без побочных исправлений
|
|
||||||
|
|
||||||
Validation SHALL независимо выполнять affected canonical gates, semantic и
|
|
||||||
acceptance verification, проверку применимых edge cases и independent read-only
|
|
||||||
review относительно approved OpenSpec artifacts. Она MUST NOT изменять
|
|
||||||
production implementation, specification или Tasks и MUST возвращать только
|
|
||||||
PASS, FAIL либо SPEC_ISSUE с маршрутизацией к Finalization, Implementation либо
|
|
||||||
самой ранней затронутой planning boundary. Validation-owned verification и
|
|
||||||
review MUST NOT оставаться unchecked implementation Tasks.
|
|
||||||
|
|
||||||
Для применимого UI/UX scope независимое сопоставление SHALL включать визуальные
|
|
||||||
материалы согласованной версии canonical Design и соответствующие экраны,
|
|
||||||
состояния, взаимодействия и адаптивное поведение реализации. Read-only boundary
|
|
||||||
Validation SHALL распространяться на весь визуальный пакет Design.
|
|
||||||
|
|
||||||
#### Scenario: Реализация соответствует утверждённому change
|
|
||||||
|
|
||||||
- **WHEN** Validation подтверждает approved requirements, affected gates,
|
|
||||||
acceptance behavior и отсутствие blocking review findings
|
|
||||||
- **THEN** она возвращает PASS и разрешает следующую сессию Finalization
|
|
||||||
|
|
||||||
#### Scenario: Найдена проблема реализации
|
|
||||||
|
|
||||||
- **WHEN** Validation находит несоответствие реализации утверждённому OpenSpec
|
|
||||||
- **THEN** она возвращает FAIL с точным observed finding и направляет следующую
|
|
||||||
сессию к Implementation без самостоятельного исправления
|
|
||||||
|
|
||||||
#### Scenario: Найдена проблема спецификации
|
|
||||||
|
|
||||||
- **WHEN** Validation находит противоречие или пробел в approved planning
|
|
||||||
artifacts
|
|
||||||
- **THEN** она возвращает SPEC_ISSUE и направляет работу к самой ранней
|
|
||||||
затронутой planning boundary без переписывания specification под реализацию
|
|
||||||
|
|
||||||
#### Scenario: Tasks планируют независимую проверку
|
|
||||||
|
|
||||||
- **WHEN** Tasks описывают ожидаемую semantic verification или independent
|
|
||||||
review после реализации
|
|
||||||
- **THEN** завершение Implementation не зависит от checkbox, который может
|
|
||||||
закрыть только Validation
|
|
||||||
|
|
||||||
#### Scenario: Найдено визуальное несоответствие
|
|
||||||
|
|
||||||
- **WHEN** наблюдаемая реализация расходится с однозначным применимым решением
|
|
||||||
согласованного визуального пакета
|
|
||||||
- **THEN** Validation возвращает FAIL с конкретным несоответствием и не
|
|
||||||
исправляет интерфейс или визуальный пакет в этой сессии
|
|
||||||
|
|
||||||
#### Scenario: Визуальный пакет противоречит другим planning artifacts
|
|
||||||
|
|
||||||
- **WHEN** Validation обнаруживает противоречие согласованного визуального
|
|
||||||
результата требованиям либо неоднозначность самого Design
|
|
||||||
- **THEN** она возвращает SPEC_ISSUE с основанием возврата к самой ранней
|
|
||||||
затронутой planning boundary, не выбирая новую трактовку самостоятельно
|
|
||||||
|
|
||||||
### Requirement: Finalization требует успешной независимой Validation
|
|
||||||
|
|
||||||
Workflow SHALL разрешать Finalization только после последней независимой
|
|
||||||
Validation с PASS, если после неё не было relevant изменений planning или
|
|
||||||
delivery inputs. Finalization MUST выполнять только archive и completion
|
|
||||||
mechanics, MUST NOT повторять актуальную Validation и MUST направлять каждый
|
|
||||||
blocker к точной ответственной роли без исправления production implementation
|
|
||||||
или planning artifacts.
|
|
||||||
|
|
||||||
#### Scenario: Последняя Validation прошла
|
|
||||||
|
|
||||||
- **WHEN** Finalization получает change после PASS и relevant inputs с момента
|
|
||||||
этой Validation не изменялись
|
|
||||||
- **THEN** она использует observed PASS и выполняет completion mechanics без
|
|
||||||
повторной independent Validation
|
|
||||||
|
|
||||||
#### Scenario: Implementation-owned Task не завершена
|
|
||||||
|
|
||||||
- **WHEN** Finalization обнаруживает незавершённую implementation-owned Task
|
|
||||||
- **THEN** она возвращает blocker в Implementation и не архивирует change
|
|
||||||
|
|
||||||
#### Scenario: PASS отсутствует или устарел
|
|
||||||
|
|
||||||
- **WHEN** последняя Validation не завершилась PASS либо после PASS изменились
|
|
||||||
relevant planning или delivery inputs
|
|
||||||
- **THEN** Finalization возвращает blocker в Validation и не считает прежний
|
|
||||||
outcome актуальным
|
|
||||||
|
|
||||||
#### Scenario: Обнаружена planning issue
|
|
||||||
|
|
||||||
- **WHEN** Finalization обнаруживает противоречие или пробел в approved planning
|
|
||||||
artifacts
|
|
||||||
- **THEN** она возвращает blocker к самой ранней затронутой Specification
|
|
||||||
boundary без самостоятельного исправления
|
|
||||||
|
|
||||||
#### Scenario: Completion mechanics временно недоступны
|
|
||||||
|
|
||||||
- **WHEN** production и planning inputs корректны, но собственное retryable
|
|
||||||
действие завершения не выполнено из-за environment или completion failure
|
|
||||||
- **THEN** workflow остаётся в Finalization с observed blocker и не повторяет
|
|
||||||
Implementation или Validation без изменения их inputs
|
|
||||||
|
|
||||||
#### Scenario: В Finalization обнаружена проблема
|
|
||||||
|
|
||||||
- **WHEN** Finalization обнаруживает любой blocker завершения
|
|
||||||
- **THEN** она не закрывает lifecycle change, сохраняет observed cause и
|
|
||||||
направляет продолжение к точной ответственной роли
|
|
||||||
|
|
||||||
### Requirement: Implementation сохраняет ограниченные checkpoints
|
|
||||||
|
|
||||||
Implementation SHALL выбирать связный ограниченный batch из оставшихся
|
|
||||||
утверждённых Tasks и MAY завершить сессию, оставаясь в роли Implementation,
|
|
||||||
если весь change ещё не реализован. Такой checkpoint MUST фиксировать
|
|
||||||
завершённые canonical Tasks, оставшуюся работу и достаточный результат
|
|
||||||
релевантных проверок, не выдавая неполный change за готовый к Validation.
|
|
||||||
|
|
||||||
#### Scenario: Завершён один связный batch
|
|
||||||
|
|
||||||
- **WHEN** Implementation завершила и проверила ограниченный batch, но в
|
|
||||||
canonical Tasks осталась implementation-owned работа
|
|
||||||
- **THEN** workflow сохраняет завершённые и оставшиеся Tasks, направляет
|
|
||||||
продолжение в новую Implementation-сессию и не сообщает blocker или
|
|
||||||
готовность к Validation
|
|
||||||
|
|
||||||
#### Scenario: Завершена вся implementation-owned работа
|
|
||||||
|
|
||||||
- **WHEN** все утверждённые implementation-owned Tasks выполнены и релевантные
|
|
||||||
проверки Implementation успешны
|
|
||||||
- **THEN** workflow фиксирует готовность change к независимой Validation
|
|
||||||
|
|
||||||
### Requirement: Активные инструкции согласованы и независимы от agent runtime
|
|
||||||
|
|
||||||
Активные SDD и repository instructions SHALL направлять участника к одной
|
|
||||||
authority для общей lifecycle policy и одной authority для операционной context
|
|
||||||
discipline. Они MUST сохранять одинаковые approval и completion safeguards и
|
|
||||||
MUST NOT требовать конкретный AI-agent runtime или его необязательные
|
|
||||||
framework-specific entrypoints для выполнения canonical workflow.
|
|
||||||
|
|
||||||
#### Scenario: Участник начинает работу из любого active entrypoint
|
|
||||||
|
|
||||||
- **WHEN** участник открывает root или repository-local active instructions
|
|
||||||
- **THEN** он получает согласованный canonical lifecycle, применимые локальные
|
|
||||||
boundaries и ссылки на общую authority без противоречащей копии shared policy
|
|
||||||
|
|
||||||
#### Scenario: Необязательный agent runtime отсутствует
|
|
||||||
|
|
||||||
- **WHEN** участник выполняет workflow без vendor-specific commands, skills или
|
|
||||||
instruction tree
|
|
||||||
- **THEN** все canonical planning, implementation, validation и finalization
|
|
||||||
outcomes остаются достижимыми без ослабления safeguards
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
# audit-remediation-workflow Specification
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
Определяет устойчивый способ продолжать и подтверждать устранение findings технического аудита WealthLedger между сессиями и независимыми репозиториями.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
### Requirement: Реестр remediation отделён от снимка аудита
|
|
||||||
|
|
||||||
Система SHALL создавать отдельный неизменяемый versioned audit snapshot в `docs/audits` для каждого завершённого аудита и SHALL поддерживать один актуальный durable remediation registry в `docs/development`, охватывающий findings всех audit snapshots. Для завершённого multi-source audit система SHALL сохранять каждый source file byte-for-byte и объединять их одним snapshot index. Каждый snapshot SHALL оставаться source of claims своего аудита и MUST NOT редактироваться для отражения последующей remediation. Внешняя модельная оценка MUST быть обозначена как неавторитетный источник claims и MUST NOT подменять requirements, governance или проверенное состояние проекта. Registry SHALL хранить текущее состояние, связанный canonical change, следующее действие и completion evidence каждой записи, MUST ссылаться на однозначный Audit ID и каждый относящийся source snapshot и MUST NOT дублировать полный текст finding, если он уже содержится в snapshot.
|
|
||||||
|
|
||||||
#### Scenario: Агент открывает работу по аудиту в новой сессии
|
|
||||||
|
|
||||||
- **WHEN** агент получает задачу устранить или продолжить finding из любого завершённого аудита
|
|
||||||
- **THEN** он находит в едином registry исходный snapshot и Audit ID, текущий статус, связанный OpenSpec change, evidence и следующее действие без повторной интерпретации всех аудитов
|
|
||||||
|
|
||||||
#### Scenario: Проводится повторный аудит
|
|
||||||
|
|
||||||
- **WHEN** новый аудит завершён после предыдущего audit snapshot
|
|
||||||
- **THEN** система добавляет новый immutable snapshot и обновляет тот же live registry, не переписывая предыдущий snapshot и не создавая конкурирующий registry
|
|
||||||
|
|
||||||
#### Scenario: Обновляется прогресс remediation
|
|
||||||
|
|
||||||
- **WHEN** работа по finding меняет статус
|
|
||||||
- **THEN** versioned audit snapshots не редактируются, а изменение фиксируется только в live registry с датой и необходимым evidence
|
|
||||||
|
|
||||||
#### Scenario: Один аудит содержит несколько внешних оценок
|
|
||||||
|
|
||||||
- **WHEN** завершённая assessment использовала несколько независимых source reports
|
|
||||||
- **THEN** snapshot index связывает byte-for-byte сохранённые reports в один audit и явно отделяет их claims от project authority
|
|
||||||
|
|
||||||
### Requirement: Registry задаёт однозначный статус и следующий change
|
|
||||||
Каждая audit-derived запись SHALL иметь ровно один статус из `planned`, `active`, `done`, `deferred` или `accepted`. `planned` MUST означать согласованную работу, которую можно начать без внешнего review trigger; запись, ожидающая версии зависимости, внешнего события или отдельного решения владельца, MUST иметь статус `deferred` с условием пересмотра. Registry MUST содержать не более одного `active` remediation change и ровно одну следующую рекомендуемую задачу, пока существуют findings со статусом `planned`.
|
|
||||||
|
|
||||||
#### Scenario: В рабочей области нет активного remediation change
|
|
||||||
- **WHEN** агент открывает registry и все незакрытые немедленно исполнимые findings имеют статус `planned`
|
|
||||||
- **THEN** он может выбрать ровно одну строку, отмеченную как следующая рекомендуемая задача, и создать связанный canonical OpenSpec change
|
|
||||||
|
|
||||||
#### Scenario: В рабочей области уже есть активный remediation change
|
|
||||||
- **WHEN** registry содержит запись со статусом `active`
|
|
||||||
- **THEN** агент продолжает связанный change и не создаёт второй remediation change без явного решения владельца
|
|
||||||
|
|
||||||
#### Scenario: Finding зависит от будущего trigger
|
|
||||||
- **WHEN** remediation нельзя обоснованно начать до указанной версии зависимости, внешнего события или решения владельца
|
|
||||||
- **THEN** registry хранит статус `deferred`, rationale и проверяемое условие пересмотра вместо представления finding как готового `planned` work
|
|
||||||
|
|
||||||
### 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 сохраняет причину решения и условия, при которых оно должно быть пересмотрено
|
|
||||||
|
|
||||||
### Requirement: Каждое audit claim получает доказательный disposition
|
|
||||||
|
|
||||||
Каждое уникальное claim завершённого multi-source audit MUST входить ровно в один нормализованный Audit ID и иметь triage disposition `confirmed`, `already-covered`, `rejected` или `deferred`. Нормализованная запись MUST ссылаться на каждый source report, содержащий claim. `confirmed` MUST связываться с remediation status и change либо terminal evidence; `already-covered` MUST приводить проверяемое существующее evidence; `rejected` MUST содержать конкретное rationale; `deferred` MUST содержать review trigger. Triage disposition MUST оставаться отдельным от remediation status `planned`, `active`, `done`, `deferred` или `accepted`, чтобы внешняя рекомендация не становилась принятой policy без проверки.
|
|
||||||
|
|
||||||
#### Scenario: Несколько моделей повторяют одно замечание
|
|
||||||
|
|
||||||
- **WHEN** два или более source reports описывают один и тот же underlying gap
|
|
||||||
- **THEN** registry содержит один нормализованный Audit ID со ссылками на все источники и одним доказательным disposition
|
|
||||||
|
|
||||||
#### Scenario: Рекомендация уже реализована
|
|
||||||
|
|
||||||
- **WHEN** проверяемое состояние проекта полностью покрывает external claim
|
|
||||||
- **THEN** disposition `already-covered` ссылается на существующий requirement, guardrail или completion evidence без создания фиктивной remediation work
|
|
||||||
|
|
||||||
#### Scenario: Внешняя рекомендация противоречит authority
|
|
||||||
|
|
||||||
- **WHEN** source report предлагает неподдерживаемый либо ухудшающий действующий invariant подход
|
|
||||||
- **THEN** disposition `rejected` фиксирует конкретное противоречие и не превращает recommendation в requirement
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# http-api-foundation Specification
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Определяет общий безопасный фундамент backend HTTP API, на котором строятся доменные endpoints.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Backend предоставляет безопасный API-фундамент
|
||||||
|
Backend SHALL публиковать HTTP API с префиксом `/api/v1`, принимать разрешенные frontend origins только из конфигурации и возвращать клиенту безопасные ошибки без секретов или внутренних деталей.
|
||||||
|
|
||||||
|
#### Scenario: Запрос приходит с неразрешенного origin
|
||||||
|
- **WHEN** браузер отправляет cross-origin запрос не с настроенного frontend origin
|
||||||
|
- **THEN** backend не разрешает браузеру доступ к ответу через CORS
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
# engineering-change-governance Specification
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
Определяет соразмерные и проверяемые правила инженерных решений AI-агентов, чтобы WealthLedger переиспользовал зрелые решения, тестировал существенные риски и локально отклонял код, нарушающий инварианты проекта.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
### Requirement: Готовые решения оцениваются до собственной реализации
|
|
||||||
|
|
||||||
Изменение, которое вводит или существенно заменяет механизм авторизации, безопасности, хранения данных, внешней интеграции, наблюдаемости, кэширования, конкурентного доступа либо общей инфраструктуры и tooling, MUST до утверждения архитектурного решения оценить существующие поддерживаемые решения. Оценка MUST сравнивать применимые варианты по соответствию требованиям, зрелости, безопасности, эксплуатационной стоимости, ограничениям и стоимости миграции. Собственная реализация SHALL допускаться только когда подходящего готового решения нет либо его существенная несовместимость явно зафиксирована вместе с рисками такого выбора. Для изменений вне перечисленных областей отдельная оценка MUST NOT быть обязательной без конкретного риска или дорогостоящего необратимого решения.
|
|
||||||
|
|
||||||
#### Scenario: Существует совместимое зрелое решение
|
|
||||||
|
|
||||||
- **WHEN** change затрагивает одну из обязательных для оценки областей и найдено поддерживаемое решение, удовлетворяющее требованиям без неприемлемых ограничений
|
|
||||||
- **THEN** архитектурное решение использует это решение либо явно объясняет, почему его совокупная стоимость или риск выше выбранной альтернативы
|
|
||||||
|
|
||||||
#### Scenario: Подходящего решения нет
|
|
||||||
|
|
||||||
- **WHEN** рассмотренные зрелые решения не выполняют существенные требования или создают неприемлемый риск
|
|
||||||
- **THEN** собственная реализация допускается только после фиксации проверенных вариантов, конкретных разрывов, принятых рисков и условия повторного пересмотра
|
|
||||||
|
|
||||||
#### Scenario: Изменение не требует solution assessment
|
|
||||||
|
|
||||||
- **WHEN** change не относится к обязательным областям и не содержит отдельного дорогостоящего или необратимого решения
|
|
||||||
- **THEN** отсутствие формальной оценки готовых решений не блокирует SDD lifecycle и не создаёт дополнительный артефакт ради процесса
|
|
||||||
|
|
||||||
### Requirement: Тестирование определяется риском поведения
|
|
||||||
|
|
||||||
План изменения MUST требовать автоматизированные тесты для security- и privacy-sensitive поведения, денежных расчётов, целостности и миграции данных, конкурентного доступа, публичных контрактов, критических пользовательских сценариев и подтверждённых регрессий. Изменение MUST NOT требовать новый тест только из-за появления или изменения файла. Простые декларативные структуры, DTO без собственной логики, тонкие адаптеры, прямолинейная оркестрация, hygiene scripts и поведение сторонней библиотеки SHALL проверяться существующим контрактным или интеграционным gate без отдельного unit test, если они не содержат самостоятельного ветвления, преобразования, инварианта либо ранее найденной регрессии. Существующий frontend coverage gate SHALL использоваться только как anti-regression constraint, а не как основание создавать малоценные тесты. Backend MUST NOT получать общий числовой coverage threshold только ради симметрии или процессного соответствия; такой gate требует отдельного утверждённого обоснования защищаемого риска.
|
|
||||||
|
|
||||||
#### Scenario: Изменяется критический инвариант
|
|
||||||
|
|
||||||
- **WHEN** change меняет безопасность, денежный результат, целостность данных, конкурентное поведение, публичный контракт, критический journey или исправляет регрессию
|
|
||||||
- **THEN** checklist содержит тест соответствующего уровня, который наблюдаемо подтверждает новый или исправленный результат
|
|
||||||
|
|
||||||
#### Scenario: Добавлен простой служебный скрипт
|
|
||||||
|
|
||||||
- **WHEN** скрипт только последовательно запускает существующие проверяемые команды, не содержит самостоятельной бизнес-логики, ветвления или преобразования данных
|
|
||||||
- **THEN** отдельный unit test для скрипта не является обязательным, а корректность результата подтверждается выполнением самого локального gate
|
|
||||||
|
|
||||||
#### Scenario: Coverage можно повысить только малоценным тестом
|
|
||||||
|
|
||||||
- **WHEN** новый тест повторял бы декларативную структуру или внутреннее поведение зависимости и не защищал бы самостоятельный риск проекта
|
|
||||||
- **THEN** агент не создаёт такой тест только ради процента coverage и сохраняет существующий anti-regression threshold
|
|
||||||
|
|
||||||
#### Scenario: Backend не имеет числового coverage threshold
|
|
||||||
|
|
||||||
- **WHEN** обязательные risk-based тесты backend проходят, а отдельный измеримый риск для общего coverage threshold не утверждён
|
|
||||||
- **THEN** отсутствие глобального числового threshold не считается пробелом и не блокирует change
|
|
||||||
|
|
||||||
### Requirement: Enforceable Engineering Invariant имеет локальную проверку
|
|
||||||
|
|
||||||
Каждое правило, обозначенное как обязательный Enforceable Engineering Invariant, MUST иметь детерминированную non-mutating локальную проверку и MUST блокировать завершение работы при нарушении. Такие инварианты SHALL охватывать применимые правила стиля проекта, статическую корректность, архитектурные границы, публичные контракты, безопасность и критические доменные ограничения. Рекомендация, которую невозможно надёжно проверить локально, MUST быть обозначена как guidance и MUST NOT выдаваться за hard guardrail. Проверка самого hard guardrail MUST иметь evidence, что она отклоняет хотя бы одно контролируемое репрезентативное нарушение; это evidence MUST NOT превращаться в требование unit-тестировать каждый вспомогательный скрипт.
|
|
||||||
|
|
||||||
#### Scenario: Агент пишет код не в стиле проекта
|
|
||||||
|
|
||||||
- **WHEN** изменение нарушает проверяемое правило форматирования, lint, типов, импортных границ или публичного контракта проекта
|
|
||||||
- **THEN** обязательный локальный gate завершается с ошибкой и работа не считается завершённой
|
|
||||||
|
|
||||||
#### Scenario: Правило является только рекомендацией
|
|
||||||
|
|
||||||
- **WHEN** команда не может определить детерминированную локальную проверку сформулированного предпочтения
|
|
||||||
- **THEN** правило документируется как guidance, а агент не использует его как самостоятельную причину объявить корректную реализацию невалидной
|
|
||||||
|
|
||||||
#### Scenario: Добавляется новый hard guardrail
|
|
||||||
|
|
||||||
- **WHEN** change объявляет новое правило блокирующим
|
|
||||||
- **THEN** completion evidence подтверждает как успешный compliant case, так и обнаружение контролируемого representative violation
|
|
||||||
|
|
||||||
### Requirement: Труднообратимое изменение имеет rollback contract
|
|
||||||
|
|
||||||
Design MUST определять rollback trigger, rollback actions, data safety и rollback verification, когда change затрагивает auth или security behavior, data integrity или migration, public contract либо другое существенно труднообратимое решение. Rollback contract MUST учитывать данные и совместимость, созданные после поставки change, и MUST быть выполним без нового неутверждённого архитектурного решения. Когда указанные риски неприменимы, Design SHALL фиксировать конкретную проверяемую причину `N/A` и MUST NOT создавать отдельный artifact или формальный rollback plan ради процесса.
|
|
||||||
|
|
||||||
#### Scenario: Change мигрирует данные
|
|
||||||
|
|
||||||
- **WHEN** Design изменяет хранимые данные способом, который может потребовать возврата
|
|
||||||
- **THEN** он определяет trigger, безопасные действия отката, судьбу новых данных и проверку восстановленного состояния до утверждения Tasks
|
|
||||||
|
|
||||||
#### Scenario: Change меняет публичный контракт
|
|
||||||
|
|
||||||
- **WHEN** Design вводит несовместимое изменение публичного контракта
|
|
||||||
- **THEN** rollback contract объясняет восстановление совместимости и проверяемое условие успешного отката
|
|
||||||
|
|
||||||
#### Scenario: Rollback risk отсутствует
|
|
||||||
|
|
||||||
- **WHEN** change не затрагивает auth, security, данные, публичный контракт или другое труднообратимое решение
|
|
||||||
- **THEN** Design указывает конкретную причину `N/A` без создания дополнительного rollback artifact
|
|
||||||
|
|
||||||
### Requirement: Token-efficient execution сохраняет delivery evidence
|
|
||||||
|
|
||||||
Project-owned agent guidance SHALL направлять AI-агента к совместному получению
|
|
||||||
независимых read-only evidence, targeted чтению найденных диапазонов, сужению
|
|
||||||
diff по затронутым paths и компактному представлению успешных command results.
|
|
||||||
Такая оптимизация MUST сохранять exit status, существенный observed outcome и
|
|
||||||
всё evidence, необходимое для текущего решения, canonical gate, semantic
|
|
||||||
verification или independent review. При failure, неоднозначности или
|
|
||||||
существенном расхождении workflow SHALL расширить diagnostics соразмерно
|
|
||||||
наблюдаемой проблеме. Предпочтения по batching и размеру output SHALL оставаться
|
|
||||||
guidance и MUST NOT блокировать корректную delivery без отдельного
|
|
||||||
детерминированного hard guardrail.
|
|
||||||
|
|
||||||
#### Scenario: Требуются несколько независимых read-only результатов
|
|
||||||
|
|
||||||
- **WHEN** агент до следующего смыслового решения заранее знает несколько независимых source, status или diff запросов
|
|
||||||
- **THEN** workflow направляет получить их одним evidence batch и вернуть только релевантные результаты без промежуточного model round-trip после каждого запроса
|
|
||||||
|
|
||||||
#### Scenario: Canonical gate проходит успешно
|
|
||||||
|
|
||||||
- **WHEN** обязательная verification command завершается успешно и её полный output не нужен для последующего смыслового решения
|
|
||||||
- **THEN** agent context сохраняет точную command identity, exit status и существенную итоговую summary без обязательного переноса полного verbose log
|
|
||||||
|
|
||||||
#### Scenario: Verification завершается ошибкой
|
|
||||||
|
|
||||||
- **WHEN** compact command result сообщает failure или не позволяет определить причину
|
|
||||||
- **THEN** workflow получает достаточные diagnostics для локализации ошибки и не скрывает необходимые failure details ради соблюдения output budget
|
|
||||||
|
|
||||||
#### Scenario: Independent review требует полный relevant diff
|
|
||||||
|
|
||||||
- **WHEN** reviewer должен проверить весь фактический scope реализации против утверждённых artifacts
|
|
||||||
- **THEN** token-efficient guidance не исключает relevant diff или evidence, необходимые для semantic conclusion
|
|
||||||
|
|
||||||
### Requirement: Token-efficiency оценивается на завершённых фазах вместе с качеством
|
|
||||||
|
|
||||||
Token-efficiency pilot SHALL сравнивать resource usage на успешно завершённую
|
|
||||||
SDD-фазу, включая cumulative input, количество model calls, глубину контекста и
|
|
||||||
объём tool outputs, вместе с outcome indicators: результатами обязательных
|
|
||||||
gates, количеством циклов исправления и findings independent review. Снижение
|
|
||||||
resource usage MUST NOT считаться улучшением, если сопоставимая работа чаще не
|
|
||||||
завершается, требует больше исправлений либо ухудшает verification или review
|
|
||||||
outcomes. До накопления репрезентативных сопоставимых наблюдений числовые budgets
|
|
||||||
SHALL оставаться guidance и MUST NOT становиться самостоятельным completion
|
|
||||||
blocker.
|
|
||||||
|
|
||||||
#### Scenario: Resource usage снизился без ухудшения результата
|
|
||||||
|
|
||||||
- **WHEN** pilot показывает меньше cumulative input или model calls на сопоставимую завершённую фазу, а canonical gates, fix cycles и review findings не ухудшились
|
|
||||||
- **THEN** изменение может быть представлено Engineering Owner как наблюдаемое улучшение с указанным measurement scope и ограничениями
|
|
||||||
|
|
||||||
#### Scenario: Дешёвая фаза создаёт больше rework
|
|
||||||
|
|
||||||
- **WHEN** вариант workflow использует меньше токенов, но чаще получает failed gates, дополнительные fix cycles или более серьёзные review findings
|
|
||||||
- **THEN** pilot не представляет этот вариант как token-efficiency improvement
|
|
||||||
|
|
||||||
#### Scenario: Наблюдений недостаточно для обязательного порога
|
|
||||||
|
|
||||||
- **WHEN** pilot ещё не содержит репрезентативных сопоставимых завершённых фаз или надёжной локальной проверки
|
|
||||||
- **THEN** model-call, context-depth и tool-output budgets остаются guidance и не блокируют delivery
|
|
||||||
|
|
||||||
#### Scenario: Числовой budget предлагается как hard guardrail
|
|
||||||
|
|
||||||
- **WHEN** последующий change предлагает сделать token budget обязательным completion condition
|
|
||||||
- **THEN** он должен определить защищаемый риск, детерминированную non-mutating проверку и controlled compliant/violation evidence по общему contract Enforceable Engineering Invariant
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# app-shell Specification
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Определяет общий каркас frontend-приложения, в который встраиваются доменные экраны.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Frontend предоставляет минимальный каркас приложения
|
||||||
|
Frontend SHALL предоставлять русскоязычный адаптивный каркас приложения с маршрутами `/login`, `/register`, `/accounts`, `/accounts/:accountId` и `/settings`, светлой финансовой темой и навигацией для счетов и настроек. Каркас MUST содержать состояния загрузки, ошибки и пустых данных без реализации доменных сценариев.
|
||||||
|
|
||||||
|
#### Scenario: Пользователь открывает маршрут MVP
|
||||||
|
- **WHEN** пользователь переходит на любой маршрут MVP
|
||||||
|
- **THEN** frontend отображает соответствующий каркас страницы и не показывает шаблонный Todo-интерфейс
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
# multi-repository-delivery Specification
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
Определяет полную поставку одного SDD-изменения через независимые frontend, backend, specs и docs репозитории без потерянных областей, фиктивных коммитов и преждевременного статуса done.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
### Requirement: Каждый change содержит полный Delivery Map
|
|
||||||
|
|
||||||
Каждый legacy `wealth-ledger-sdd` change MUST оценивать delivery areas `frontend`, `backend`, `specs` и `docs` в Design Delivery Map и для каждой области указывать `affected` либо `N/A` с конкретной причиной. Для `wealth-ledger-sdd-v2` Design оценивает implementation impact `main`, `frontend`, `backend` (и `qa`, только если существует repo), а Docs Impact отдельно оценивает `docs`; `specs` владеет SDD artifacts и native sync/archive без фиктивной implementation task. Для обоих workflows `docs` SHALL быть affected для каждой поставленной пользовательской фичи; для технического или процессного change она MAY быть `N/A` только когда фактическая устойчивая документация не изменяется. `frontend` и `backend` SHALL быть affected только когда меняется их поведение, контракт, реализация или обязательный локальный gate. Пустой коммит MUST NOT использоваться для имитации участия незатронутого репозитория.
|
|
||||||
|
|
||||||
#### Scenario: Фича затрагивает клиент и API
|
|
||||||
|
|
||||||
- **WHEN** change меняет пользовательский поток и соответствующее API-поведение
|
|
||||||
- **THEN** legacy Delivery Map отмечает frontend, backend, specs и docs как affected; v2 Design отмечает frontend/backend, а Docs Impact — docs и отдельный specs artifact не превращается в пустую task
|
|
||||||
|
|
||||||
#### Scenario: Область не затронута
|
|
||||||
|
|
||||||
- **WHEN** поведение, контракт, реализация, guardrails и фактическая документация области не меняются
|
|
||||||
- **THEN** соответствующий impact artifact содержит проверяемую причину `N/A`, а delivery не требует пустого коммита этого репозитория
|
|
||||||
|
|
||||||
### Requirement: Частичная multi-repository delivery не считается завершённой
|
|
||||||
|
|
||||||
Change MUST оставаться active, пока каждая affected область не реализована и не прошла свои обязательные локальные gates. Успех одной области MUST NOT позволять архивировать change, если другая affected область отсутствует, не проверена либо не соответствует согласованному поведению. После archive change MUST NOT получить terminal status `done`, пока фактические результаты всех применимых delivery areas выбранной schema не представлены в Completion Evidence.
|
|
||||||
|
|
||||||
#### Scenario: Backend готов, а frontend ещё не реализован
|
|
||||||
|
|
||||||
- **WHEN** Delivery Map помечает frontend и backend как affected, но завершён и проверен только backend
|
|
||||||
- **THEN** change остаётся active и не может быть архивирован
|
|
||||||
|
|
||||||
#### Scenario: Все affected области готовы
|
|
||||||
|
|
||||||
- **WHEN** каждая affected область реализована, согласована по общим контрактам и прошла требуемые локальные gates
|
|
||||||
- **THEN** change может перейти к семантической верификации и archive, после которого формируется Completion Evidence для terminal status
|
|
||||||
|
|
||||||
### Requirement: Completion Evidence содержит только наблюдённые результаты
|
|
||||||
|
|
||||||
Completion Evidence MUST создаваться после выполнения работы и MUST связывать canonical change с commit identifier каждого изменённого Git-репозитория, точными выполненными non-mutating verification commands и их наблюдёнными результатами. Для каждой оценённой области с `N/A` evidence SHALL сохранять согласованную причину отсутствия изменения. Planned commands, ожидаемые результаты, незавершённые checklist items и предполагаемые commit identifiers MUST NOT представляться как completion evidence.
|
|
||||||
|
|
||||||
#### Scenario: Change готовится к terminal status
|
|
||||||
|
|
||||||
- **WHEN** implementer заявляет, что multi-repository change завершён
|
|
||||||
- **THEN** reviewer может сопоставить impact artifacts выбранной schema с фактическими commits, результатами gates и причинами `N/A` для всех оценённых областей
|
|
||||||
|
|
||||||
#### Scenario: Команда ещё не была выполнена
|
|
||||||
|
|
||||||
- **WHEN** verification command только запланирована или её результат не сохранён
|
|
||||||
- **THEN** она остаётся implementation checklist item и не засчитывается как Completion Evidence
|
|
||||||
|
|
||||||
### Requirement: Общий локальный verifier сохраняет gates репозиториев
|
|
||||||
|
|
||||||
Workspace SHALL предоставлять один non-mutating локальный verification entrypoint для multi-repository delivery. Он MUST проверять совместимость runtime до application gates, запускать канонический gate каждой selected affected области и сохранять их ошибки как blocking result. Общий verifier MUST NOT заменять или ослаблять локальные gates независимых репозиториев.
|
|
||||||
|
|
||||||
#### Scenario: Запущен неподдерживаемый runtime
|
|
||||||
|
|
||||||
- **WHEN** multi-repository verifier запускается с runtime, не соответствующим объявленному проектом контракту
|
|
||||||
- **THEN** проверка завершается ошибкой до получения вводящего в заблуждение результата application tests
|
|
||||||
|
|
||||||
#### Scenario: Один repository gate завершается ошибкой
|
|
||||||
|
|
||||||
- **WHEN** общий verifier проверяет несколько affected областей и канонический gate одной из них не проходит
|
|
||||||
- **THEN** общий результат является неуспешным и явно указывает failing area без обхода её локального gate
|
|
||||||
|
|
||||||
### Requirement: Каждая задача объявляет единственную delivery area
|
|
||||||
|
|
||||||
Каждый checkbox legacy Tasks MUST объявлять ровно одного owner из `frontend`, `backend`, `specs`, `docs` или `workspace`; `workspace` SHALL использоваться только для cross-area orchestration или verification без владения repository implementation. Каждый checkbox v2 Tasks MUST объявлять ровно одного repository owner из `main`, `frontend`, `backend`, `docs`, `specs` или существующего `qa`; `main` владеет только workspace/Compose/release/configuration, `specs` — genuine repository maintenance, `docs` — approved Docs Impact, `qa` — только реальная automation delivery, но не manual acceptance checkbox. Implementation work, изменяющая несколько Git-репозиториев, MUST быть разделена на repository-owned tasks. Для каждой `affected` implementation area Tasks MUST содержать её implementation work и canonical local gate, а task ownership MUST соответствовать утверждённым impact artifacts выбранной schema.
|
|
||||||
|
|
||||||
#### Scenario: Change затрагивает frontend и backend
|
|
||||||
|
|
||||||
- **WHEN** одна delivery intent требует изменения клиента и API
|
|
||||||
- **THEN** Tasks содержит отдельные frontend-owned и backend-owned checkbox items вместо одной общей implementation task
|
|
||||||
|
|
||||||
#### Scenario: Выполняется общий verification gate
|
|
||||||
|
|
||||||
- **WHEN** задача только оркестрирует проверку нескольких affected areas и не изменяет их implementation
|
|
||||||
- **THEN** legacy task MAY использовать `workspace`; v2 использует `main` только при реальном workspace-owned outcome, не маскируя независимую Validation под implementation checkbox
|
|
||||||
|
|
||||||
#### Scenario: Task ссылается на N/A area
|
|
||||||
|
|
||||||
- **WHEN** checkbox объявляет owner области, которая имеет статус `N/A` в Delivery Map
|
|
||||||
- **THEN** planning validation завершается ошибкой и указывает несогласованную delivery area выбранной schema
|
|
||||||
|
|
||||||
### Requirement: Tasks трассируются к утверждённым требованиям
|
|
||||||
|
|
||||||
Каждый checkbox Tasks MUST содержать coverage reference: одну или несколько пар из точного capability path и точного Requirement heading либо `N/A` с конкретной причиной для работы, которая не реализует spec-level behavior. Причина `N/A` MUST объяснять отсутствие самостоятельного observable behavior, техническую необходимость задачи и её связь с утверждённым Design или delivery; для v2 также допустима связь с System Analysis или Docs Impact. Однословная категория или неразрешённый placeholder не являются достаточной причиной. Каждый Requirement из Delta Specs MUST быть покрыт хотя бы одной task; для v2 допустимо явное объяснение отсутствия implementation work. Planning validation MUST отклонять отсутствующее покрытие, ссылку на несуществующий capability или Requirement, пустую причину `N/A` и неразрешённый placeholder. Содержательная достаточность непустой причины SHALL оцениваться semantic approval и independent review и MUST NOT выдаваться за детерминированный hard guardrail. Traceability SHALL использовать нативную идентичность requirement и MUST NOT вводить параллельный namespace собственных requirement IDs.
|
|
||||||
|
|
||||||
#### Scenario: Delta requirement покрыт реализацией
|
|
||||||
|
|
||||||
- **WHEN** Tasks планирует поставку изменённого requirement
|
|
||||||
- **THEN** хотя бы один checkbox ссылается на точный capability path и Requirement heading этого delta
|
|
||||||
|
|
||||||
#### Scenario: Задача не меняет spec-level behavior
|
|
||||||
|
|
||||||
- **WHEN** task обновляет infrastructure, documentation или verification без самостоятельного requirement
|
|
||||||
- **THEN** coverage reference содержит `N/A` и конкретно объясняет техническую необходимость задачи и её связь с утверждённым Design или delivery
|
|
||||||
|
|
||||||
#### Scenario: N/A содержит placeholder
|
|
||||||
|
|
||||||
- **WHEN** coverage reference оставляет template placeholder вместо фактической причины
|
|
||||||
- **THEN** planning validation блокирует approval Tasks и указывает незавершённую metadata
|
|
||||||
|
|
||||||
#### Scenario: N/A содержит непустую слабую причину
|
|
||||||
|
|
||||||
- **WHEN** coverage reference формально заполнена, но не объясняет необходимость задачи или её связь с утверждённым change
|
|
||||||
- **THEN** semantic review запрашивает уточнение без представления эвристической текстовой оценки как hard guardrail
|
|
||||||
|
|
||||||
#### Scenario: Requirement остался без задачи
|
|
||||||
|
|
||||||
- **WHEN** хотя бы один Requirement из Delta Specs не указан ни в одной coverage reference
|
|
||||||
- **THEN** planning validation блокирует approval Tasks и перечисляет uncovered Requirement
|
|
||||||
@@ -1,427 +0,0 @@
|
|||||||
# openspec-authority-and-lifecycle Specification
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
Определяет единственный источник полномочий для OpenSpec и проверяемый жизненный цикл SDD-изменений независимо от текущей директории, глобальной конфигурации или agent framework.
|
|
||||||
Применяется только к работе, которую Change Owner явно начал как OpenSpec/SDD; обычная разработка идёт по задаче без planning artifacts.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
### Requirement: SDD-артефакты имеют непересекающиеся полномочия
|
|
||||||
|
|
||||||
Proposal SHALL выражать причину, намерение, границы и ожидаемый эффект change языком владельца и MUST NOT содержать решения по технологиям, структуре кода, файлам, API или зависимостям. Delta Specs SHALL определять только добавленное, изменённое или удалённое наблюдаемое поведение и инварианты системы без описания изменений кода. В `wealth-ledger-sdd-v2` System Analysis SHALL определять межсистемные потоки, contracts и semantics до Design; Design SHALL объяснять внутреннюю реализацию approved behavior/contracts, риски и альтернативы, не становясь построчной инструкцией. QA Analysis SHALL определять независимую system verification, не предписывая разработчикам internal tests. Docs Impact SHALL планировать только durable AS-IS knowledge для `docs/`. Применимые UI/UX-решения и визуальные материалы SHALL входить в единый canonical Design и MUST NOT образовывать отдельный planning authority или отдельный UI/UX approval. Tasks SHALL быть implementation checklist из утверждённых upstream artifacts и MUST NOT содержать ещё не наблюдённые completion results, commit identifiers или post-archive bookkeeping. Completion Evidence SHALL фиксироваться только после фактической реализации и верификации и MUST NOT подменять planning artifact. Концептуальные материалы и Discovery SHALL оставаться входным контекстом и MUST NOT считаться утверждёнными OpenSpec artifacts.
|
|
||||||
|
|
||||||
#### Scenario: Product Owner формулирует Proposal
|
|
||||||
|
|
||||||
- **WHEN** владелец описывает требуемое изменение, не зная структуры кода и файлов
|
|
||||||
- **THEN** Proposal остаётся полноценным утверждаемым намерением без необходимости принимать архитектурные решения
|
|
||||||
|
|
||||||
#### Scenario: Агент подготавливает Tasks
|
|
||||||
|
|
||||||
- **WHEN** upstream artifacts выбранной schema утверждены
|
|
||||||
- **THEN** Tasks перечисляет конкретные действия реализации и проверки, но не заявляет будущие результаты уже выполненными
|
|
||||||
|
|
||||||
#### Scenario: Владелец согласует визуальный результат
|
|
||||||
|
|
||||||
- **WHEN** Change Owner явно утверждает Design с применимыми визуальными материалами
|
|
||||||
- **THEN** решение распространяется на обозначенную версию всего пакета Design
|
|
||||||
в существующем approval gate без новой SDD-роли или отдельного UI/UX approval
|
|
||||||
|
|
||||||
#### Scenario: Концепт доступен до Design
|
|
||||||
|
|
||||||
- **WHEN** обсуждение или Discovery содержит визуальный концепт
|
|
||||||
- **THEN** его наличие не разрешает downstream planning или реализацию и не
|
|
||||||
заменяет явное утверждение соответствующего OpenSpec artifact
|
|
||||||
|
|
||||||
### Requirement: Artifact graph применяет последовательные approval gates
|
|
||||||
|
|
||||||
Каждый change SHALL следовать schema из своего `.openspec.yaml`: существующие active `wealth-ledger-sdd` сохраняют `Proposal → Delta Specs → Design → Tasks → Apply`, а новые `wealth-ledger-sdd-v2` используют `Proposal → Delta Specs → System Analysis → (Design + QA Analysis) → Docs Impact → Tasks → Apply`. В v2 Design и QA Analysis MAY подготавливаться параллельно после approval System Analysis; Docs Impact требует approvals обоих. `skip_specs: true` явно обозначает отсутствие behavior delta, а не фиктивный spec. AI-агент MAY подготовить черновик текущего разрешённого артефакта, но MUST NOT считать его утверждённым самостоятельно или создавать downstream artifact до явного решения Change Owner. Для change, определяющего продуктовое поведение, Change Owner SHALL быть Product Owner; для технического или процессного change — Engineering Owner. Каждый применимый planning artifact выбранной schema MUST существовать и быть явно утверждён до Apply; существующие approvals legacy changes MUST NOT инвалидироваться только из-за смены default schema.
|
|
||||||
|
|
||||||
#### Scenario: Proposal ещё не утверждён
|
|
||||||
|
|
||||||
- **WHEN** AI-агент завершил черновик Proposal, но Change Owner не дал явного согласия
|
|
||||||
- **THEN** downstream artifacts выбранной schema остаются недоступны для создания
|
|
||||||
|
|
||||||
#### Scenario: Delta Specs утверждены
|
|
||||||
|
|
||||||
- **WHEN** Change Owner явно подтверждает Delta Specs после утверждённого Proposal
|
|
||||||
- **THEN** для legacy разрешён Design, для v2 — System Analysis; Tasks и Apply остаются заблокированы
|
|
||||||
|
|
||||||
#### Scenario: Active change переживает смену default schema
|
|
||||||
|
|
||||||
- **WHEN** active change закреплён за `wealth-ledger-sdd` и default меняется на `wealth-ledger-sdd-v2`
|
|
||||||
- **THEN** он сохраняет прежний artifact graph и approvals без создания фиктивных v2 artifacts
|
|
||||||
|
|
||||||
### Requirement: Изменение upstream artifact требует каскадной проверки
|
|
||||||
|
|
||||||
Семантическое изменение утверждённого artifact MUST возвращаться к самой ранней затронутой planning boundary и инициировать повторную проверку и approval только её зависимых downstream artifacts согласно выбранной schema. Для legacy Proposal → Delta Specs → Design → Tasks; для v2 intent/scope → Proposal, observable behavior → Specs, systems/sequences/contracts/mappings/inter-system errors/semantic observability → System Analysis, internal implementation/storage/technical observability/developer tests → Design, system verification/test data/automation → QA Analysis, durable AS-IS/ADR → Docs Impact, decomposition/ownership/dependencies → Tasks. Изменение Tasks MUST NOT неявно менять upstream semantics. Если несоответствие обнаружено во время Design или Apply, downstream-работа MUST остановиться, а Change Owner MUST получить наблюдаемое основание возврата. Механическое исправление синтаксиса или формата без изменения смысла MUST пройти повторную structural validation и MUST NOT само по себе инвалидировать approvals. Исправление Markdown heading, опечатки без изменения нормативного смысла или выравнивания таблицы MAY считаться механическим; изменение Requirement/Scenario, contract, sequence, архитектурного решения, QA expected result, docs target либо planned Verification задачи MUST NOT считаться механическим.
|
|
||||||
|
|
||||||
#### Scenario: После Design изменилось намерение
|
|
||||||
|
|
||||||
- **WHEN** владелец меняет scope или ожидаемый эффект Proposal
|
|
||||||
- **THEN** зависимые artifacts выбранной schema теряют прежнее подтверждение до повторной согласованной проверки
|
|
||||||
|
|
||||||
#### Scenario: Task вводит новое поведение
|
|
||||||
|
|
||||||
- **WHEN** implementation checklist требует поведение, которого нет в утверждённых Delta Specs
|
|
||||||
- **THEN** агент не расширяет scope через Tasks и возвращает change к Delta Specs
|
|
||||||
|
|
||||||
#### Scenario: Apply выявляет архитектурное расхождение
|
|
||||||
|
|
||||||
- **WHEN** во время реализации обнаружено, что утверждённый Design не позволяет выполнить Specs без другого архитектурного решения
|
|
||||||
- **THEN** Apply останавливается, затронутые downstream approvals теряют силу, а change возвращается к Design с наблюдаемым основанием и вариантами решения
|
|
||||||
|
|
||||||
#### Scenario: Исправляется только структурный формат
|
|
||||||
|
|
||||||
- **WHEN** утверждённый artifact содержит исправимую синтаксическую или formatting-ошибку без изменения его смысла
|
|
||||||
- **THEN** workflow исправляет ошибку, повторяет structural validation и сохраняет действующие approvals
|
|
||||||
|
|
||||||
#### Scenario: Меняется planned Verification
|
|
||||||
|
|
||||||
- **WHEN** исправление Tasks меняет способ, которым должна подтверждаться поставка
|
|
||||||
- **THEN** workflow рассматривает изменение как semantic task-scope change и повторно запрашивает approval Tasks
|
|
||||||
|
|
||||||
### 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: OpenSpec tooling проверяется по совместимости
|
|
||||||
|
|
||||||
SDD workflow MUST проверять доступный OpenSpec CLI на совместимость с выбранной schema и canonical store без закрепления одной версии CLI. Перед изменением workflow или обновлением CLI SHALL выполняться native validation обеих project-local schemas, затронутых changes и canonical specs; artifact graph, agent workflow, store selection и blocking gates MUST сохранять согласованную семантику. Несовместимый CLI MUST давать actionable blocking result и MUST NOT приводить к молчаливому изменению artifacts или project-owned entrypoints. Фактически использованная версия CLI SHALL сохраняться в observed verification evidence, а не в отдельном version contract.
|
|
||||||
|
|
||||||
#### Scenario: Доступный CLI совместим
|
|
||||||
|
|
||||||
- **WHEN** проверки выбранной schema и canonical store проходят на установленном OpenSpec CLI
|
|
||||||
- **THEN** workflow продолжает работу без требования совпадения с закреплённым номером версии
|
|
||||||
|
|
||||||
#### Scenario: CLI нарушает совместимость
|
|
||||||
|
|
||||||
- **WHEN** после обновления CLI schema validation, разрешение store или blocking gates перестают работать
|
|
||||||
- **THEN** зависимая SDD-операция останавливается с диагностикой нарушения до исправления несовместимости
|
|
||||||
|
|
||||||
#### Scenario: CLI обновлён
|
|
||||||
|
|
||||||
- **WHEN** Engineering Owner обновляет OpenSpec CLI
|
|
||||||
- **THEN** проверяются обе project-local schemas, затронутые changes, canonical specs и workflow, а фактическая версия и результаты сохраняются в verification evidence
|
|
||||||
|
|
||||||
### Requirement: Structural и semantic verification являются разными gates
|
|
||||||
|
|
||||||
OpenSpec structural validation SHALL проверять schema, artifact graph и формальную корректность specs, но MUST NOT считаться доказательством соответствия реализации или approval. До terminal status change MUST пройти semantic verification реализации против применимых approved artifacts выбранной schema, включая v2 System Analysis, QA Analysis и Docs Impact, а затем независимый read-only review. Если основной agent entrypoint semantic verification недоступен, workflow SHALL использовать versioned эквивалентную процедуру с теми же входными артефактами, категориями проверки и наблюдаемым evidence.
|
|
||||||
|
|
||||||
#### Scenario: Structural validation прошла без ошибок
|
|
||||||
|
|
||||||
- **WHEN** все planning artifacts формально валидны, но реализация ещё не сопоставлена с ними
|
|
||||||
- **THEN** change не получает terminal status только на основании structural validation
|
|
||||||
|
|
||||||
#### Scenario: Slash workflow недоступен агенту
|
|
||||||
|
|
||||||
- **WHEN** среда не предоставляет установленный semantic verification entrypoint
|
|
||||||
- **THEN** агент выполняет документированную эквивалентную read-only проверку и сохраняет её результат вместо пропуска gate
|
|
||||||
|
|
||||||
### Requirement: Archive блокируется незавершёнными tasks
|
|
||||||
Project-owned archive workflow MUST отклонять archive, если отсутствует требуемый выбранной schema planning artifact, любой обязательный artifact не утверждён, `tasks.md` отсутствует или содержит unchecked task, semantic verification либо независимый read-only review не завершены успешно, или любая affected delivery area не реализована и не прошла обязательные pre-archive gates. Для v2 также MUST быть подтверждены developer checks, независимая QA/system verification, semantic compatibility backend-generated OpenAPI/runtime interface с approved target contract при изменении API и применение Docs Impact так, чтобы canonical `docs/` отражали resulting AS-IS. Native OpenSpec sync/archive SHALL обновлять canonical behavior specs, не переписывая их implementation details; System Analysis и target contracts остаются в архивном change, а не становятся второй вечной копией current OpenAPI. Workflow MUST NOT предлагать confirmation override для этих blocking conditions. Post-archive bookkeeping MUST NOT появляться как unchecked task; он SHALL фиксироваться через детерминированное Completion Evidence после успешного archive, после чего связанная delivery может получить terminal status.
|
|
||||||
|
|
||||||
#### Scenario: Change имеет unchecked task
|
|
||||||
- **WHEN** implementer запрашивает archive и остаётся хотя бы один unchecked task
|
|
||||||
- **THEN** workflow не архивирует change и сообщает incomplete tasks как blocking condition без возможности confirmation override
|
|
||||||
|
|
||||||
#### Scenario: Change не прошёл required verification
|
|
||||||
- **WHEN** planning artifacts и tasks завершены, но semantic verification, independent review, implementation или pre-archive gate affected area отсутствуют либо неуспешны
|
|
||||||
- **THEN** workflow не архивирует change и перечисляет недостающие blocking conditions
|
|
||||||
|
|
||||||
#### Scenario: Change завершил все tasks
|
|
||||||
- **WHEN** каждый planning artifact утверждён, каждый task отмечен, required verification, implementation и pre-archive gates всех affected areas успешно завершены
|
|
||||||
- **THEN** workflow допускает archive и фиксирует его результат через определённый completion-evidence path без создания post-archive task
|
|
||||||
|
|
||||||
### Requirement: Planning artifact проверяется до запроса approval
|
|
||||||
|
|
||||||
Каждый создаваемый planning artifact SHALL пройти все применимые на его текущем этапе non-mutating structural checks до запроса approval Change Owner. Если полный change validation ещё заблокирован отсутствующими downstream artifacts, workflow MUST выполнить доступные проверки текущего artifact и явно оставить недоступную проверку незавершённой, а не заявлять общий успех. Planning verifier MUST выдавать различимые результаты для нарушения artifact validation, некорректного invocation и environment failure. Только диагностированная техническая ошибка проверяемого artifact SHALL исправляться в artifact и проверяться повторно без передачи ручного исправления Change Owner; invocation или environment failure MUST NOT приводить к изменению planning artifact. Structural success MUST NOT подменять semantic approval.
|
|
||||||
|
|
||||||
#### Scenario: Текущий artifact имеет проверяемое нарушение
|
|
||||||
|
|
||||||
- **WHEN** сгенерированный planning artifact нарушает обязательный формат или ссылочную целостность, доступные для проверки на текущем этапе
|
|
||||||
- **THEN** workflow сообщает artifact validation failure, исправляет указанное нарушение и повторяет structural checks до запроса owner approval
|
|
||||||
|
|
||||||
#### Scenario: Verifier вызван некорректно
|
|
||||||
|
|
||||||
- **WHEN** planning verifier получает отсутствующий или недопустимый input
|
|
||||||
- **THEN** он сообщает invocation failure, а агент исправляет вызов без изменения planning artifact
|
|
||||||
|
|
||||||
#### Scenario: Проверка блокируется окружением
|
|
||||||
|
|
||||||
- **WHEN** verifier не может выполнить проверку из-за отсутствующего runtime, command или иного environment prerequisite
|
|
||||||
- **THEN** он сообщает environment failure, агент сохраняет planning artifact неизменным и диагностирует prerequisite либо передаёт точную блокирующую ошибку Change Owner
|
|
||||||
|
|
||||||
#### Scenario: Downstream artifacts ещё отсутствуют
|
|
||||||
|
|
||||||
- **WHEN** Proposal создан, а downstream artifacts выбранной schema ещё не существуют
|
|
||||||
- **THEN** workflow сообщает результат доступных Proposal checks и не представляет отсутствующую full-change validation как успешную
|
|
||||||
|
|
||||||
### Requirement: Project schema сохраняет заметные самодостаточные правила
|
|
||||||
|
|
||||||
Project schema SHALL показывать обязательные правила текущей стадии до
|
|
||||||
поддерживающих пояснений и SHALL сохранять нормативную семантику artifact graph,
|
|
||||||
artifact boundaries и feedback routing внутри schema. Она MUST NOT зависеть от
|
|
||||||
global agent prompt или параллельного файла правил для корректного выполнения
|
|
||||||
workflow. Поясняющий текст SHALL использовать основной язык project artifacts,
|
|
||||||
сохраняя exact OpenSpec headings, tokens, commands и normative keywords без
|
|
||||||
перевода. Сокращение или перегруппировка instructions MUST NOT удалять
|
|
||||||
действующий lifecycle invariant.
|
|
||||||
|
|
||||||
#### Scenario: Агент получает instruction текущего artifact
|
|
||||||
|
|
||||||
- **WHEN** OpenSpec возвращает agent instruction для разрешённой стадии
|
|
||||||
- **THEN** обязательные правила этой стадии доступны до подробностей и достаточны без внешнего prompt с дублирующей policy
|
|
||||||
|
|
||||||
#### Scenario: Instructions сокращаются
|
|
||||||
|
|
||||||
- **WHEN** повторяющийся или поясняющий текст удаляется либо переносится внутри project schema
|
|
||||||
- **THEN** каждый ранее действующий artifact boundary, approval gate и feedback route остаётся представлен ровно одним authoritative правилом
|
|
||||||
|
|
||||||
### Requirement: Delta Spec template не предрешает операцию
|
|
||||||
|
|
||||||
Исходная форма Delta Spec SHALL быть применима к `ADDED`, `MODIFIED`, `REMOVED`
|
|
||||||
и `RENAMED` requirements и MUST NOT создавать активный пустой раздел или
|
|
||||||
предварительно выбирать одну delta operation. Она SHALL сообщать допустимые
|
|
||||||
формы operations и отдельное правило `Purpose` для новой capability, не
|
|
||||||
заставляя существующую capability начинать с `ADDED Requirements`.
|
|
||||||
|
|
||||||
#### Scenario: Изменяется существующий requirement
|
|
||||||
|
|
||||||
- **WHEN** агент получает исходную форму Delta Spec для существующей capability
|
|
||||||
- **THEN** форма позволяет выбрать `MODIFIED Requirements` без удаления заранее созданного активного `ADDED Requirements`
|
|
||||||
|
|
||||||
#### Scenario: Delta использует одну операцию
|
|
||||||
|
|
||||||
- **WHEN** change требует только одну из поддерживаемых delta operations
|
|
||||||
- **THEN** сохранённый artifact содержит только применимую operation и не содержит пустых sections остальных видов
|
|
||||||
|
|
||||||
### Requirement: Apply читает только разрешённый planning context
|
|
||||||
|
|
||||||
Apply SHALL прочитать каждый artifact path из `contextFiles`, возвращённых
|
|
||||||
OpenSpec для текущего change, а затем применимые локальные routing instructions
|
|
||||||
каждой affected delivery area. Агент MUST NOT вычислять planning context paths
|
|
||||||
самостоятельно или требовать отдельный project context mapping, дублирующий
|
|
||||||
CLI-resolved state.
|
|
||||||
|
|
||||||
#### Scenario: OpenSpec возвращает contextFiles
|
|
||||||
|
|
||||||
- **WHEN** агент начинает Apply утверждённого change
|
|
||||||
- **THEN** он читает все объявленные CLI paths и локальные instructions affected areas до выполнения pending tasks
|
|
||||||
|
|
||||||
#### Scenario: У change нет отдельного context map
|
|
||||||
|
|
||||||
- **WHEN** CLI уже разрешил planning artifacts и affected areas имеют локальные routing instructions
|
|
||||||
- **THEN** Apply использует эти authorities и не блокируется отсутствием второго context mapping artifact
|
|
||||||
|
|
||||||
### Requirement: Agent context следует текущей SDD-фазе
|
|
||||||
|
|
||||||
Project-owned agent workflow SHALL начинать каждую работу с определения текущей
|
|
||||||
SDD-фазы и affected delivery areas, а затем SHALL загружать canonical artifacts,
|
|
||||||
локальные routing instructions и supporting authority, применимые к этой фазе и
|
|
||||||
этим areas. Переход в новую agent-сессию после утверждения planning artifact
|
|
||||||
SHALL использовать canonical artifact и явное решение Change Owner как основание
|
|
||||||
продолжения. Workflow MUST NOT требовать полную историю предыдущей сессии или
|
|
||||||
отдельный handoff/context artifact, дублирующий OpenSpec authority. Supporting
|
|
||||||
material, не влияющий на текущую фазу, затронутую область, доменную семантику или
|
|
||||||
обязательный gate, SHALL загружаться только при появлении наблюдаемой
|
|
||||||
необходимости.
|
|
||||||
|
|
||||||
#### Scenario: Утверждённый artifact передаётся в новую сессию
|
|
||||||
|
|
||||||
- **WHEN** Change Owner явно утверждает текущий planning artifact и следующая agent-сессия продолжает change на разрешённой downstream-фазе
|
|
||||||
- **THEN** workflow восстанавливает работу из canonical change artifacts, owner approval и применимых routing instructions без обязательной передачи полной истории обсуждения или создания второго handoff artifact
|
|
||||||
|
|
||||||
#### Scenario: Работа ограничена одной delivery area
|
|
||||||
|
|
||||||
- **WHEN** текущая фаза затрагивает одну определённую delivery area и не требует cross-system или доменной оценки
|
|
||||||
- **THEN** workflow загружает authority и локальные instructions этой area, а нерелевантные architecture, domain и repository materials остаются lazy context
|
|
||||||
|
|
||||||
#### Scenario: Supporting material становится необходимым
|
|
||||||
|
|
||||||
- **WHEN** во время работы возникает вопрос, влияющий на domain semantics, cross-area architecture, audit disposition или обязательный gate
|
|
||||||
- **THEN** workflow загружает соответствующий authoritative material до принятия решения и не использует token-efficiency guidance как основание пропустить требуемый контекст
|
|
||||||
|
|
||||||
### Requirement: Session handoff сохраняет approval boundary
|
|
||||||
|
|
||||||
Разделение agent-сессий SHALL происходить только на наблюдаемой границе, где
|
|
||||||
завершённый результат представлен canonical artifact, применённым изменением или
|
|
||||||
verification outcome. Handoff SHALL сохранять change identity, последний явно
|
|
||||||
утверждённый artifact, текущую фазу, affected areas, unresolved blockers и
|
|
||||||
следующий разрешённый outcome. Если новая сессия не имеет явного подтверждения
|
|
||||||
approval, workflow MUST повторно запросить решение Change Owner и MUST NOT
|
|
||||||
выводить approval только из наличия artifact.
|
|
||||||
|
|
||||||
#### Scenario: Planning-фаза завершилась approval
|
|
||||||
|
|
||||||
- **WHEN** Change Owner утвердил Proposal, Delta Specs или Design и работа продолжается в новой сессии
|
|
||||||
- **THEN** handoff указывает change identity, утверждённую границу и единственный следующий разрешённый artifact, не перенося нерелевантную историю инструментов и обсуждений
|
|
||||||
|
|
||||||
#### Scenario: Approval невозможно подтвердить
|
|
||||||
|
|
||||||
- **WHEN** canonical artifact существует, но доступный контекст новой сессии не содержит явного решения Change Owner
|
|
||||||
- **THEN** workflow останавливается перед downstream artifact и повторно запрашивает approval
|
|
||||||
|
|
||||||
#### Scenario: Реализация переходит к независимой проверке
|
|
||||||
|
|
||||||
- **WHEN** Apply завершил заявленную работу и change передаётся в свежий verification/review context
|
|
||||||
- **THEN** handoff сохраняет approved artifacts, affected areas, фактический implementation scope и unresolved blockers, а reviewer получает необходимый diff и evidence без полной implementation history
|
|
||||||
|
|
||||||
### Requirement: UI/UX-проработка Design соразмерна изменению
|
|
||||||
|
|
||||||
Design SHALL явно определять применимость UI/UX: новый или существенно
|
|
||||||
изменённый интерфейс, переиспользование согласованного решения либо N/A с
|
|
||||||
конкретной причиной отсутствия влияния на интерфейс. Для применимого scope
|
|
||||||
Design SHALL давать Change Owner однозначное представление ожидаемого результата:
|
|
||||||
затронутые экраны, применимые состояния, взаимодействия и адаптивное поведение.
|
|
||||||
Ссылки на переиспользуемое решение SHALL указывать, какая его часть применима
|
|
||||||
к change и какие различия остаются. Неизменяемые части интерфейса и N/A MUST NOT
|
|
||||||
требовать формальных новых макетов.
|
|
||||||
|
|
||||||
#### Scenario: Change существенно меняет интерфейс
|
|
||||||
|
|
||||||
- **WHEN** Design описывает новый или существенно изменённый пользовательский
|
|
||||||
интерфейс
|
|
||||||
- **THEN** владелец может оценить затронутые экраны, применимые состояния,
|
|
||||||
взаимодействия и поведение при изменении доступного пространства до реализации
|
|
||||||
|
|
||||||
#### Scenario: Используется согласованное решение
|
|
||||||
|
|
||||||
- **WHEN** change переиспользует ранее согласованное UI/UX-решение
|
|
||||||
- **THEN** Design однозначно указывает применимое решение, область
|
|
||||||
переиспользования и различия без обязательного повторного рисования
|
|
||||||
|
|
||||||
#### Scenario: Change не влияет на интерфейс
|
|
||||||
|
|
||||||
- **WHEN** UI/UX неприменим по конкретной причине, приведённой в Design
|
|
||||||
- **THEN** пакет Design допускается без формального макета и дополнительных
|
|
||||||
UI/UX approvals
|
|
||||||
|
|
||||||
### Requirement: Визуальный пакет Design имеет однозначную сохраняемую версию
|
|
||||||
|
|
||||||
Canonical Design SHALL однозначно определять состав и версию своих применимых
|
|
||||||
визуальных материалов. Материалы SHALL оставаться доступны Change Owner,
|
|
||||||
исполнителю и независимому reviewer при передаче между изолированными сессиями
|
|
||||||
и после archive, без зависимости от временного контекста предыдущей сессии.
|
|
||||||
Ссылка, содержимое которой может молча измениться, MUST NOT быть единственным
|
|
||||||
свидетельством согласованной версии. Визуальные материалы MUST NOT создавать
|
|
||||||
конкурирующий versioned planning root вне canonical OpenSpec authority.
|
|
||||||
|
|
||||||
#### Scenario: Design передаётся другому исполнителю
|
|
||||||
|
|
||||||
- **WHEN** новая изолированная сессия получает canonical Design
|
|
||||||
- **THEN** она может однозначно найти полный применимый визуальный пакет и
|
|
||||||
определить именно ту версию, на которую распространяется approval
|
|
||||||
|
|
||||||
#### Scenario: Визуальный источник изменился или недоступен
|
|
||||||
|
|
||||||
- **WHEN** текущий внешний или временный источник отличается от согласованной
|
|
||||||
версии либо перестал открываться
|
|
||||||
- **THEN** согласованная версия остаётся доступна из сохраняемого пакета Design
|
|
||||||
и не заменяется молча новым содержимым
|
|
||||||
|
|
||||||
#### Scenario: Change архивирован
|
|
||||||
|
|
||||||
- **WHEN** участник обращается к Design после archive
|
|
||||||
- **THEN** применимые визуальные материалы согласованной версии доступны вместе
|
|
||||||
с архивным Design и сохраняют однозначную связь с ним
|
|
||||||
|
|
||||||
### Requirement: Соответствие визуальному Design входит в semantic verification
|
|
||||||
|
|
||||||
Реализация SHALL следовать утверждённому Design, включая его применимые
|
|
||||||
визуальные материалы. Semantic verification и независимый read-only review
|
|
||||||
SHALL сопоставлять реализованные экраны, состояния, взаимодействия и адаптивное
|
|
||||||
поведение с этим пакетом в границах change. Наличие каталога или макета MUST NOT
|
|
||||||
считаться approval или доказательством соответствия реализации. Несоответствие
|
|
||||||
реализации SHALL направляться на исправление реализации; необходимость
|
|
||||||
существенно изменить согласованный результат SHALL возвращать работу к самой
|
|
||||||
ранней затронутой planning boundary с действующими cascade approval rules.
|
|
||||||
|
|
||||||
#### Scenario: Реализация расходится с согласованным интерфейсом
|
|
||||||
|
|
||||||
- **WHEN** реализация не соответствует однозначному применимому решению Design
|
|
||||||
- **THEN** проверка сообщает наблюдаемое несоответствие для исправления
|
|
||||||
реализации и не объявляет соответствие только из-за наличия макета или каталога
|
|
||||||
|
|
||||||
#### Scenario: Согласованное решение требует пересмотра
|
|
||||||
|
|
||||||
- **WHEN** выполнить UI/UX-решение без существенного изменения утверждённого
|
|
||||||
результата невозможно либо planning artifacts противоречат друг другу
|
|
||||||
- **THEN** workflow возвращает работу к самой ранней затронутой planning
|
|
||||||
boundary, применяет cascade approval rules и не подгоняет Design под реализацию
|
|
||||||
|
|
||||||
### Requirement: Внедрение UI/UX workflow сохраняет действующие approval boundaries
|
|
||||||
|
|
||||||
Planning `integrate-ui-ux-design-workflow` MAY продолжаться до завершения
|
|
||||||
`optimize-session-oriented-sdd-v2`, но внедрение процессной части MUST ожидать его
|
|
||||||
завершения. Перед Design этого change workflow SHALL повторно сверить действующую
|
|
||||||
canonical authority и определить применимость обновлённого процесса к активным
|
|
||||||
changes. Обновление MUST NOT автоматически переутверждать их artifacts или
|
|
||||||
переписывать historical archives.
|
|
||||||
|
|
||||||
#### Scenario: Предшествующий процессный change ещё не завершён
|
|
||||||
|
|
||||||
- **WHEN** `optimize-session-oriented-sdd-v2` остаётся незавершённым
|
|
||||||
- **THEN** planning текущего change допускается в рамках явных approvals,
|
|
||||||
а внедрение его процессной части остаётся недоступным
|
|
||||||
|
|
||||||
#### Scenario: Начинается Design интеграции
|
|
||||||
|
|
||||||
- **WHEN** Delta Specs этого change явно утверждены и начинается Design
|
|
||||||
- **THEN** Design опирается на повторно сверенную текущую canonical authority
|
|
||||||
и явно определяет применимость процесса к активным changes
|
|
||||||
|
|
||||||
#### Scenario: Обновлённый процесс поставляется
|
|
||||||
|
|
||||||
- **WHEN** процессные изменения становятся доступными участникам
|
|
||||||
- **THEN** прежние approvals активных changes не считаются автоматически
|
|
||||||
обновлёнными, а historical archives сохраняются без переписывания
|
|
||||||
|
|
||||||
### Requirement: Готовность к пилоту отделена от доказанной успешности workflow
|
|
||||||
|
|
||||||
Поставка каталога и обновлённого процесса SHALL позволять использовать их
|
|
||||||
совместно в последующем небольшом UI change с собственными planning approvals.
|
|
||||||
Текущий change MUST NOT включать неявную продуктовую фичу в качестве пилота или
|
|
||||||
заявлять успешность сквозного workflow до его фактического прохождения.
|
|
||||||
|
|
||||||
#### Scenario: Текущая поставка завершена
|
|
||||||
|
|
||||||
- **WHEN** каталог и обновлённый процесс готовы к совместному использованию,
|
|
||||||
но последующий UI change ещё не прошёл workflow
|
|
||||||
- **THEN** результат описывается как готовность к пилоту без заявления об
|
|
||||||
успешном сквозном пилоте
|
|
||||||
|
|
||||||
#### Scenario: Начинается пилотный UI change
|
|
||||||
|
|
||||||
- **WHEN** владелец выбирает небольшой UI change для совместного использования
|
|
||||||
каталога и процесса
|
|
||||||
- **THEN** этот change проходит собственные planning approvals, а вывод о
|
|
||||||
сквозной успешности опирается только на его фактически наблюдаемый результат
|
|
||||||
@@ -0,0 +1,493 @@
|
|||||||
|
# portfolio-concentration Specification
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Позволяет авторизованному User увидеть на странице одного Brokerage Account, какие акции, облигации, секторы и эмитенты занимают наибольшую часть текущей оценки Portfolio в выбранной валюте, без валютной конвертации.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Вкладка «Концентрация» страницы счёта
|
||||||
|
Система SHALL показывать на странице одного Brokerage Account вкладку «Концентрация» рядом с вкладкой «Позиции». Система SHALL NOT показывать вкладку в режиме «Все счета». Добавление вкладки SHALL NOT менять вкладку, открываемую по умолчанию, и содержание остальных вкладок.
|
||||||
|
|
||||||
|
#### Scenario: Вкладка на странице одного счёта
|
||||||
|
- **WHEN** User открывает страницу доступного Brokerage Account
|
||||||
|
- **THEN** рядом с вкладкой «Позиции» доступна вкладка «Концентрация», а по умолчанию открыта прежняя вкладка
|
||||||
|
|
||||||
|
#### Scenario: Режим «Все счета»
|
||||||
|
- **WHEN** User открывает общий портфель в режиме «Все счета»
|
||||||
|
- **THEN** вкладки «Концентрация» нет
|
||||||
|
|
||||||
|
### Requirement: Вкладка в состояниях страницы
|
||||||
|
Система SHALL NOT показывать вкладку «Концентрация», пока Portfolio загружается, при его ошибке или недоступности и при штатном пустом Portfolio по требованию «Состояния и ошибки Portfolio на клиенте» из `portfolio-view`. Вкладка SHALL показываться при Portfolio хотя бы с одной позицией или денежным остатком.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081)
|
||||||
|
|
||||||
|
#### Scenario: Загрузка и ошибка
|
||||||
|
- **WHEN** Portfolio загружается либо получение завершилось ошибкой
|
||||||
|
- **THEN** вкладки «Концентрация» нет
|
||||||
|
|
||||||
|
#### Scenario: Штатный пустой Portfolio
|
||||||
|
- **WHEN** у счёта нет позиций и денежных остатков
|
||||||
|
- **THEN** вкладки «Концентрация» нет
|
||||||
|
|
||||||
|
#### Scenario: Только денежные остатки
|
||||||
|
- **WHEN** у счёта есть Cash Balance и нет позиций
|
||||||
|
- **THEN** вкладка «Концентрация» есть, разрез показывает пустое состояние
|
||||||
|
|
||||||
|
### Requirement: Переключение разрезов
|
||||||
|
Вкладка «Концентрация» SHALL предоставлять разрезы «Акции», «Облигации», «Секторы», «Эмитенты» в этом порядке и показывать одновременно один из них. При новом заходе на страницу счёта SHALL быть открыт разрез «Акции» по требованию «Начальное состояние вкладки». Разрез — набор элементов, на которые делится оценка позиций; элемент — единица ранжирования разреза по требованию «Состав разрезов».
|
||||||
|
|
||||||
|
#### Scenario: Открытие вкладки
|
||||||
|
- **WHEN** User при новом заходе на страницу счёта открывает вкладку «Концентрация»
|
||||||
|
- **THEN** показан только разрез «Акции» и доступны переключатели «Акции», «Облигации», «Секторы», «Эмитенты»
|
||||||
|
|
||||||
|
#### Scenario: Переключение разреза
|
||||||
|
- **GIVEN** открыт разрез «Акции» с выбранной валютой USD
|
||||||
|
- **WHEN** User переключает разрез на «Секторы»
|
||||||
|
- **THEN** показан только разрез «Секторы» в валюте USD
|
||||||
|
|
||||||
|
### Requirement: Начальное состояние вкладки
|
||||||
|
Система SHALL открывать вкладку «Концентрация» при новом заходе на страницу счёта и после перезагрузки с разрезом «Акции» и первой валютой списка. Новый заход — открытие страницы после ухода с неё либо переключение счёта. Пока User остаётся на странице, включая переключение её вкладок, разрез и валюта SHALL сохраняться.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [3081](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081)
|
||||||
|
|
||||||
|
#### Scenario: Возврат с другой вкладки страницы
|
||||||
|
- **GIVEN** на вкладке выбраны разрез «Секторы» и валюта USD
|
||||||
|
- **WHEN** User переключается на вкладку «Позиции» и возвращается на «Концентрация»
|
||||||
|
- **THEN** выбраны разрез «Секторы» и валюта USD
|
||||||
|
|
||||||
|
#### Scenario: Повторный заход
|
||||||
|
- **GIVEN** User выбрал разрез «Секторы» и валюту USD, затем покинул страницу счёта
|
||||||
|
- **WHEN** User снова открывает страницу счёта и вкладку «Концентрация»
|
||||||
|
- **THEN** открыт разрез «Акции» с первой валютой списка
|
||||||
|
|
||||||
|
#### Scenario: Перезагрузка
|
||||||
|
- **GIVEN** на вкладке выбраны разрез «Эмитенты» и валюта USD
|
||||||
|
- **WHEN** User перезагружает страницу
|
||||||
|
- **THEN** после открытия вкладки показаны разрез «Акции» и первая валюта списка
|
||||||
|
|
||||||
|
### Requirement: Состав разрезов
|
||||||
|
Элементы разреза SHALL формироваться из позиций типов по таблице; другие типы, включая `CURRENCY`, SHALL NOT входить во вкладку.
|
||||||
|
|
||||||
|
| Разрез | Типы | Элемент |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Акции | `STOCK` | Позиция |
|
||||||
|
| Облигации | `BOND` | Позиция |
|
||||||
|
| Секторы | `STOCK`, `BOND`, `FUND` | Позиции с одним `sector` |
|
||||||
|
| Эмитенты | `STOCK`, `BOND` | Позиции с одним `issuer.id` |
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3077)
|
||||||
|
|
||||||
|
#### Scenario: Сектор объединяет акции, облигации и фонды
|
||||||
|
- **GIVEN** в RUB есть акция сектора `energy` на 400, облигация `energy` на 100, фонд `financial` на 300 и позиция `CURRENCY` на 50
|
||||||
|
- **WHEN** User открывает разрез «Секторы» в RUB
|
||||||
|
- **THEN** элементы — «Энергетика» 500 ₽ и «Финансы» 300 ₽, позиции `CURRENCY` в разрезе нет
|
||||||
|
|
||||||
|
#### Scenario: Акция и облигация одного эмитента
|
||||||
|
- **GIVEN** в RUB есть акция с `issuer.id` `brand-1` («Сбер») на 300, облигация `brand-1` на 200 и фонд `brand-1` на 100
|
||||||
|
- **WHEN** User открывает разрез «Эмитенты» в RUB
|
||||||
|
- **THEN** есть один элемент «Сбер» на 500 ₽, фонд в него не включён
|
||||||
|
|
||||||
|
#### Scenario: Фонд вне «Акций»
|
||||||
|
- **GIVEN** в RUB есть фонд на 100 и акция на 200
|
||||||
|
- **WHEN** User открывает разрез «Акции» в RUB
|
||||||
|
- **THEN** показана только акция на 200 ₽ с долей 100 %
|
||||||
|
|
||||||
|
### Requirement: Названия элементов
|
||||||
|
Название элемента в «Акциях» и «Облигациях» SHALL быть отображаемым идентификатором позиции по требованию «Нормализованный состав Portfolio» из `portfolio-view` (name, затем ticker, затем FIGI), в «Секторах» — подписью по требованию «Подписи секторов», в «Эмитентах» — `issuer.name`, то есть названием бренда актива T-Bank. Позиции с разными `issuer.id` SHALL NOT объединяться при одинаковом `issuer.name`.
|
||||||
|
|
||||||
|
#### Scenario: Идентификатор позиции без имени
|
||||||
|
- **GIVEN** акция не имеет name, но имеет ticker `SBER`
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** элемент назван `SBER`
|
||||||
|
|
||||||
|
#### Scenario: Название эмитента — название бренда
|
||||||
|
- **GIVEN** акция и облигация имеют `issuer.id` `brand-1` и `issuer.name` «Сбер»
|
||||||
|
- **WHEN** User открывает разрез «Эмитенты»
|
||||||
|
- **THEN** один элемент назван «Сбер»
|
||||||
|
|
||||||
|
#### Scenario: Разные эмитенты с одинаковым названием
|
||||||
|
- **GIVEN** две акции имеют `issuer.name` «Альфа» и разные `issuer.id`
|
||||||
|
- **WHEN** User открывает разрез «Эмитенты»
|
||||||
|
- **THEN** показаны два отдельных элемента «Альфа»
|
||||||
|
|
||||||
|
### Requirement: Название эмитента при разных названиях бренда
|
||||||
|
Если учитываемые позиции одного `issuer.id` имеют разные `issuer.name`, название элемента SHALL быть `issuer.name` позиции с наибольшим `currentValue` в выбранной валюте. При равных значениях SHALL выбираться название, меньшее по алфавитному порядку требования «Порядок элементов с равной суммой».
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081), [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082)
|
||||||
|
|
||||||
|
#### Scenario: Название по наибольшей позиции
|
||||||
|
- **GIVEN** акция `brand-1` на 300 с названием «Сбер» и облигация `brand-1` на 200 с названием «Сбербанк»
|
||||||
|
- **WHEN** User открывает разрез «Эмитенты»
|
||||||
|
- **THEN** один элемент на 500 назван «Сбер»
|
||||||
|
|
||||||
|
#### Scenario: Равные наибольшие значения
|
||||||
|
- **GIVEN** акция `brand-1` на 200 с названием «Сбербанк» и облигация `brand-1` на 200 с названием «Сбер»
|
||||||
|
- **WHEN** User открывает разрез «Эмитенты»
|
||||||
|
- **THEN** элемент назван «Сбер»
|
||||||
|
|
||||||
|
### Requirement: Позиции, учитываемые в разрезе
|
||||||
|
Система SHALL учитывать позицию в ранжировании, долях и диаграмме только при `currentValue` больше нуля в выбранной валюте; остальные позиции SHALL NOT учитываться. Позиция с нулевым `currentValue` не показывается и не считается неучтённой, позиция другой валюты относится к другой валюте выбора.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3078)
|
||||||
|
|
||||||
|
#### Scenario: Отрицательная и неоценённая позиции
|
||||||
|
- **GIVEN** в разрезе «Акции» в RUB есть акции на 600 и 400, акция со стоимостью -50 и акция без `currentValue`
|
||||||
|
- **WHEN** User открывает разрез «Акции» в RUB
|
||||||
|
- **THEN** сумма разреза 1 000 ₽, доли 60 % и 40 %
|
||||||
|
|
||||||
|
#### Scenario: Позиция с нулевой стоимостью
|
||||||
|
- **GIVEN** есть акции на 100 и 0 в выбранной валюте
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** показана только акция на 100 с долей 100 %, сноски нет
|
||||||
|
|
||||||
|
### Requirement: Сноска о не учтённых позициях
|
||||||
|
Система SHALL показывать сноску «Не учтено позиций: N» при N больше нуля. N — число позиций разреза с `currentValue` `null` (в любой валюте) либо отрицательным в выбранной.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [3080](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3080). Примечание: при неполных данных «Структура портфеля» показывает «Доля недоступна», вкладка — доли по учтённым ([3078](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3078)).
|
||||||
|
|
||||||
|
#### Scenario: Сноска с числом позиций
|
||||||
|
- **GIVEN** в разрезе «Акции» в RUB есть акции на 600 и 400, акция со стоимостью -50 и акция без `currentValue`
|
||||||
|
- **WHEN** User открывает разрез «Акции» в RUB
|
||||||
|
- **THEN** показана сноска «Не учтено позиций: 2»
|
||||||
|
|
||||||
|
#### Scenario: Неоценённая позиция при смене валюты
|
||||||
|
- **GIVEN** есть акции на 100 USD и 200 RUB и одна акция без `currentValue`
|
||||||
|
- **WHEN** User выбирает USD
|
||||||
|
- **THEN** показаны акция на 100 $ с долей 100 % и сноска «Не учтено позиций: 1»
|
||||||
|
|
||||||
|
#### Scenario: Отрицательная позиция другой валюты
|
||||||
|
- **GIVEN** есть акции на 100 RUB и -50 USD
|
||||||
|
- **WHEN** User открывает разрез «Акции» в RUB
|
||||||
|
- **THEN** сноски нет
|
||||||
|
|
||||||
|
#### Scenario: Нет не учтённых позиций
|
||||||
|
- **GIVEN** все акции имеют положительную стоимость
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** сноски нет
|
||||||
|
|
||||||
|
### Requirement: Одна валюта за раз
|
||||||
|
Система SHALL показывать значения вкладки в одной выбранной валюте, общей для всех разрезов и сохраняемой при их переключении, и при нескольких доступных валютах предоставлять выбор из них. Смена валюты SHALL пересчитывать разрез по позициям этой валюты. Система SHALL NOT конвертировать валюты и показывать общий итог нескольких валют.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3078)
|
||||||
|
|
||||||
|
#### Scenario: Смена валюты
|
||||||
|
- **GIVEN** акции стоят 1 000 RUB и 100 USD, выбрана RUB
|
||||||
|
- **WHEN** User выбирает USD
|
||||||
|
- **THEN** разрез «Акции» показывает только акции в USD, сумму 100 $ и долю 100 %, без рублёвых значений
|
||||||
|
|
||||||
|
#### Scenario: Валюта сохраняется при смене разреза
|
||||||
|
- **GIVEN** выбрана USD в разрезе «Акции»
|
||||||
|
- **WHEN** User переключает разрез на «Облигации»
|
||||||
|
- **THEN** показаны облигации в USD
|
||||||
|
|
||||||
|
### Requirement: Доступные валюты вкладки
|
||||||
|
Доступные валюты — валюты ненулевых `currentValue` позиций `STOCK`, `BOND` и `FUND`, включая отрицательные (для сноски). Валюта только с нулевой стоимостью в список не входит. Cash Balance и другие типы валюты не определяют. Список упорядочен по ISO-коду, сначала выбрана первая. При одной валюте или без валют выбор SHALL NOT показываться.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48, подтверждено](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3080)
|
||||||
|
|
||||||
|
#### Scenario: Начальная валюта
|
||||||
|
- **GIVEN** акции оценены в USD, облигации в RUB, а Cash Balance есть ещё в EUR и позиция `CURRENCY` оценена в CHF
|
||||||
|
- **WHEN** User впервые открывает вкладку «Концентрация»
|
||||||
|
- **THEN** в выборе RUB и USD, выбрана RUB, EUR и CHF в выборе нет
|
||||||
|
|
||||||
|
#### Scenario: Единственная валюта
|
||||||
|
- **GIVEN** все оценённые акции, облигации и фонды стоят в RUB
|
||||||
|
- **WHEN** User открывает вкладку «Концентрация»
|
||||||
|
- **THEN** выбора валюты нет, значения показаны в RUB
|
||||||
|
|
||||||
|
#### Scenario: Валюта только у позиции с нулевой стоимостью
|
||||||
|
- **GIVEN** акции стоят 100 RUB, а единственная позиция в USD — акция со стоимостью 0
|
||||||
|
- **WHEN** User открывает вкладку «Концентрация»
|
||||||
|
- **THEN** в списке только RUB, USD в нём нет
|
||||||
|
|
||||||
|
#### Scenario: Валюта только у отрицательной позиции
|
||||||
|
- **GIVEN** акции стоят 100 RUB, а единственная позиция в USD — акция со стоимостью -50
|
||||||
|
- **WHEN** User выбирает USD в разрезе «Акции»
|
||||||
|
- **THEN** показаны пустое состояние и сноска «Не учтено позиций: 1»
|
||||||
|
|
||||||
|
#### Scenario: Нет оценённых позиций
|
||||||
|
- **GIVEN** у всех позиций `STOCK`, `BOND` и `FUND` `currentValue` равен `null`
|
||||||
|
- **WHEN** User открывает вкладку «Концентрация»
|
||||||
|
- **THEN** выбора валюты нет, разрез показывает пустое состояние без валюты и сноску с числом таких позиций
|
||||||
|
|
||||||
|
### Requirement: Независимый выбор валюты вкладки
|
||||||
|
Выбор валюты вкладки «Концентрация» SHALL быть независим от выбора валюты в «Структуре портфеля»: смена валюты в одном месте SHALL NOT менять валюту в другом. Если выбранная валюта вкладки пропала из списка после обновления Portfolio, система SHALL выбрать первую валюту списка.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48, подтверждено](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3080)
|
||||||
|
|
||||||
|
#### Scenario: Структура портфеля не влияет
|
||||||
|
- **GIVEN** в «Структуре портфеля» выбрана USD, а на вкладке «Концентрация» выбрана RUB
|
||||||
|
- **WHEN** User меняет валюту в «Структуре портфеля» на RUB и обратно
|
||||||
|
- **THEN** выбранная на вкладке валюта остаётся RUB
|
||||||
|
|
||||||
|
#### Scenario: Валюта пропала после обновления
|
||||||
|
- **GIVEN** на вкладке выбрана USD
|
||||||
|
- **WHEN** обновлённый Portfolio не содержит позиций `STOCK`, `BOND` и `FUND` в USD
|
||||||
|
- **THEN** выбрана первая валюта обновлённого списка
|
||||||
|
|
||||||
|
### Requirement: Топ-5 и строка «Прочее»
|
||||||
|
Система SHALL упорядочивать элементы разреза по сумме по убыванию. Если элементов не больше шести, каждый SHALL показываться строкой с названием, суммой и долей. Если семь и больше, SHALL показываться пять первых строк и строка «Прочее» с суммой, долей и числом остальных элементов («2 элемента», «5 элементов»).
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3079)
|
||||||
|
|
||||||
|
#### Scenario: Семь акций
|
||||||
|
- **GIVEN** в RUB есть семь акций с суммами 400, 250, 150, 100, 50, 30 и 20
|
||||||
|
- **WHEN** User открывает разрез «Акции» в RUB
|
||||||
|
- **THEN** показаны пять строк с суммами 400, 250, 150, 100, 50 и строка «Прочее» 50 ₽ (2 элемента) с долей 5 %
|
||||||
|
|
||||||
|
#### Scenario: Ровно шесть элементов
|
||||||
|
- **GIVEN** в RUB есть шесть акций с суммами 300, 250, 200, 150, 60 и 40
|
||||||
|
- **WHEN** User открывает разрез «Акции» в RUB
|
||||||
|
- **THEN** показаны шесть строк с долями 30 %, 25 %, 20 %, 15 %, 6 % и 4 %, строки «Прочее» нет
|
||||||
|
|
||||||
|
#### Scenario: Ровно пять элементов
|
||||||
|
- **GIVEN** в RUB есть пять акций с суммами 300, 250, 200, 150 и 100
|
||||||
|
- **WHEN** User открывает разрез «Акции» в RUB
|
||||||
|
- **THEN** показаны пять строк, строки «Прочее» нет
|
||||||
|
|
||||||
|
#### Scenario: Меньше пяти элементов
|
||||||
|
- **GIVEN** в RUB есть три акции
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** показаны три строки, строки «Прочее» нет
|
||||||
|
|
||||||
|
### Requirement: Раскрытие строки «Прочее»
|
||||||
|
По нажатию на «Прочее», в том числе с клавиатуры, система SHALL раскрывать полный список остальных элементов в порядке ранжирования с суммой и долей; повторное нажатие сворачивает его. Раскрытие SHALL NOT менять пять первых строк и диаграмму. При показе разреза и смене валюты «Прочее» SHALL быть свёрнуто.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3077)
|
||||||
|
|
||||||
|
#### Scenario: Раскрытие «Прочее»
|
||||||
|
- **GIVEN** показан разрез «Акции» из семи акций (400, 250, 150, 100, 50, 30, 20), «Прочее» свёрнуто
|
||||||
|
- **WHEN** User нажимает на строку «Прочее»
|
||||||
|
- **THEN** видны две акции с суммами 30 ₽ и 20 ₽ и долями 3 % и 2 %, пять первых строк прежние
|
||||||
|
|
||||||
|
#### Scenario: Повторное нажатие
|
||||||
|
- **GIVEN** «Прочее» раскрыто
|
||||||
|
- **WHEN** User нажимает на него ещё раз
|
||||||
|
- **THEN** список остальных элементов скрыт
|
||||||
|
|
||||||
|
#### Scenario: Смена валюты сворачивает «Прочее»
|
||||||
|
- **GIVEN** «Прочее» раскрыто в RUB
|
||||||
|
- **WHEN** User выбирает USD
|
||||||
|
- **THEN** «Прочее» свёрнуто
|
||||||
|
|
||||||
|
### Requirement: Порядок элементов с равной суммой
|
||||||
|
Элементы разреза с равной суммой SHALL упорядочиваться по названию по возрастанию без учёта регистра: сначала названия, начинающиеся с цифры, затем с латинской буквы, затем с кириллической; внутри группы — по алфавиту, при совпадении названия — по порядку первой позиции элемента в Portfolio.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48, подтверждено](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3080)
|
||||||
|
|
||||||
|
#### Scenario: Равные суммы на границе пятой строки
|
||||||
|
- **GIVEN** в RUB семь акций: 400, 300, 200, 150, «Альфа» 100, «Бета» 100 и 50
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** «Альфа» пятая строка, а «Бета» и акция на 50 входят в «Прочее»
|
||||||
|
|
||||||
|
#### Scenario: Цифры, латиница и кириллица при равных суммах
|
||||||
|
- **GIVEN** в RUB три акции с равной суммой 100 и названиями «Сбер», «VK» и «X5»
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** порядок строк: «VK», «X5», «Сбер»
|
||||||
|
|
||||||
|
### Requirement: Расчёт долей
|
||||||
|
Точная доля элемента — сумма его учитываемых позиций, делённая на сумму всех учитываемых позиций разреза в выбранной валюте; Cash Balance в расчёте не участвует. Точные доли элементов SHALL давать в сумме ровно 100 %, точная доля «Прочее» — равняться сумме точных долей остальных элементов, суммы — быть без округления.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3078)
|
||||||
|
|
||||||
|
#### Scenario: Доля без денежных остатков
|
||||||
|
- **GIVEN** акции на 600 RUB и 400 RUB и Cash Balance 1 000 RUB
|
||||||
|
- **WHEN** User открывает разрез «Акции» в RUB
|
||||||
|
- **THEN** доли 60 % и 40 %
|
||||||
|
|
||||||
|
#### Scenario: Доля «Прочее»
|
||||||
|
- **GIVEN** семь акций с суммами 400, 250, 150, 100, 50, 30 и 20
|
||||||
|
- **WHEN** User открывает разрез «Акции» и раскрывает «Прочее»
|
||||||
|
- **THEN** доля «Прочее» 5 % равна сумме долей 3 % и 2 %
|
||||||
|
|
||||||
|
### Requirement: Показ долей
|
||||||
|
Доля SHALL показываться, как в карточке позиции: округление до десятых в русской локали, середина — вверх (6,25 % — «6,3 %»), без «,0» («40 %», «66,7 %»). Положительная доля меньше 0,1 % показывается как «< 0,1 %». Суммарная доля топ-5 — в том же формате; сумма показанных долей может не быть 100 %.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [3079](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3079), [3080](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3080)
|
||||||
|
|
||||||
|
#### Scenario: Три равные доли
|
||||||
|
- **GIVEN** три акции «А», «Б» и «В» по 100 RUB
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** каждая доля показана как «33,3 %»
|
||||||
|
|
||||||
|
#### Scenario: Округление, сумма показанных долей не равна 100 %
|
||||||
|
- **GIVEN** две акции на 1 RUB и 15 RUB, точные доли 6,25 % и 93,75 %
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** доли показаны как «93,8 %» и «6,3 %», хотя в сумме дают 100,1 %
|
||||||
|
|
||||||
|
#### Scenario: Очень малая доля
|
||||||
|
- **GIVEN** акции на 100 000 000 RUB и 1 RUB
|
||||||
|
- **WHEN** User открывает разрез «Акции» в RUB
|
||||||
|
- **THEN** доли показаны как «100 %» и «< 0,1 %», сумма второй акции остаётся 1 ₽
|
||||||
|
|
||||||
|
### Requirement: Суммарная доля топ-5
|
||||||
|
Система SHALL показывать метрику «доля топ-5» — сумму точных долей пяти первых по сумме элементов разреза, в формате требования «Показ долей» — только когда элементов шесть и более. При пяти и менее элементах метрика SHALL NOT показываться.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081)
|
||||||
|
|
||||||
|
#### Scenario: Семь элементов
|
||||||
|
- **GIVEN** в RUB семь акций с суммами 400, 250, 150, 100, 50, 30 и 20
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** доли строк 40 %, 25 %, 15 %, 10 %, 5 % и «Прочее» 5 %, доля топ-5 равна 95 %
|
||||||
|
|
||||||
|
#### Scenario: Ровно шесть элементов
|
||||||
|
- **GIVEN** в RUB шесть акций с суммами 300, 250, 200, 150, 60 и 40
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** доля топ-5 равна 96 %, а шестая строка показана с долей 4 %
|
||||||
|
|
||||||
|
#### Scenario: Ровно пять элементов
|
||||||
|
- **GIVEN** в RUB пять акций с суммами 300, 250, 200, 150 и 100
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** метрика «доля топ-5» не показывается
|
||||||
|
|
||||||
|
#### Scenario: Один элемент
|
||||||
|
- **GIVEN** в RUB одна акция
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** метрика «доля топ-5» не показывается
|
||||||
|
|
||||||
|
### Requirement: Группы «Сектор не указан» и «Эмитент не указан»
|
||||||
|
Система SHALL объединять учитываемые позиции с `sector: null` («Секторы») в элемент «Сектор не указан», а с `issuer: null` («Эмитенты») — в элемент «Эмитент не указан». Эти элементы SHALL ранжироваться и попадать в «Прочее» наравне с остальными, а их название SHALL быть видно в списке и диаграмме. Сектор и эмитент SHALL NOT выводиться из названия.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3078)
|
||||||
|
|
||||||
|
#### Scenario: Позиции без эмитента в топе
|
||||||
|
- **GIVEN** в RUB акции эмитента «Сбер» на 300, эмитента «Газпром» на 300 и без эмитента на 200 и 100
|
||||||
|
- **WHEN** User открывает разрез «Эмитенты» в RUB
|
||||||
|
- **THEN** по убыванию: «Газпром» 300, «Сбер» 300, «Эмитент не указан» 300 (две позиции), группа ранжируется наравне с другими
|
||||||
|
|
||||||
|
#### Scenario: Группа без сектора в «Прочее»
|
||||||
|
- **GIVEN** у шести секторов суммы 600, 500, 400, 300, 200 и 100, у позиций без сектора сумма 50
|
||||||
|
- **WHEN** User раскрывает «Прочее» в разрезе «Секторы»
|
||||||
|
- **THEN** «Прочее» содержит шестой сектор 100 ₽ и «Сектор не указан» 50 ₽
|
||||||
|
|
||||||
|
### Requirement: Подписи секторов
|
||||||
|
Система SHALL показывать известное значение `sector` русской подписью по требованию «Русские подписи известных секторов», неизвестное — как получено, без перевода и пояснений, в списке и текстовом эквиваленте диаграммы. Система SHALL NOT придумывать подписи сверх таблицы и собственную классификацию и SHALL NOT объединять позиции с разными `sector`.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48, подтверждено](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3080)
|
||||||
|
|
||||||
|
#### Scenario: Неизвестное значение сектора
|
||||||
|
- **GIVEN** облигация имеет `sector` `other`, которого нет в таблице подписей
|
||||||
|
- **WHEN** User открывает разрез «Секторы»
|
||||||
|
- **THEN** элемент назван `other`
|
||||||
|
|
||||||
|
### Requirement: Русские подписи известных секторов
|
||||||
|
Система SHALL показывать `sector` подписью по таблице.
|
||||||
|
|
||||||
|
| Значение | Подпись |
|
||||||
|
| --- | --- |
|
||||||
|
| `consumer` | Потребительский сектор |
|
||||||
|
| `energy` | Энергетика |
|
||||||
|
| `financial` | Финансы |
|
||||||
|
| `health_care` | Здравоохранение |
|
||||||
|
| `industrials` | Промышленность |
|
||||||
|
| `it` | Информационные технологии |
|
||||||
|
| `materials` | Материалы |
|
||||||
|
| `real_estate` | Недвижимость |
|
||||||
|
| `telecom` | Телекоммуникации |
|
||||||
|
| `utilities` | Коммунальные услуги |
|
||||||
|
| `government` | Государственный сектор |
|
||||||
|
|
||||||
|
#### Scenario: Известный сектор
|
||||||
|
- **GIVEN** позиция имеет `sector` `it`
|
||||||
|
- **WHEN** User открывает разрез «Секторы»
|
||||||
|
- **THEN** элемент назван «Информационные технологии»
|
||||||
|
|
||||||
|
#### Scenario: Государственные облигации
|
||||||
|
- **GIVEN** облигация имеет `sector` `government`
|
||||||
|
- **WHEN** User открывает разрез «Секторы»
|
||||||
|
- **THEN** элемент назван «Государственный сектор»
|
||||||
|
|
||||||
|
### Requirement: Диаграмма распределения разреза
|
||||||
|
Система SHALL показывать диаграмму разреза с теми же элементами, в том же порядке и с теми же долями, что в списке: для разреза не более чем из шести элементов — сегмент на каждый элемент, для разреза из семи и более — пять сегментов и один сегмент «Прочее», одинаково для свёрнутого и раскрытого списка. Для пустого разреза диаграмма SHALL NOT показываться. Не учтённые позиции SHALL NOT входить в диаграмму.
|
||||||
|
|
||||||
|
#### Scenario: Семь элементов
|
||||||
|
- **GIVEN** семь акций с суммами 400, 250, 150, 100, 50, 30 и 20 RUB
|
||||||
|
- **WHEN** User открывает разрез «Акции» и раскрывает «Прочее»
|
||||||
|
- **THEN** диаграмма состоит из шести сегментов с долями 40 %, 25 %, 15 %, 10 %, 5 %, 5 % в порядке списка, как и при свёрнутом «Прочее»
|
||||||
|
|
||||||
|
#### Scenario: Ровно шесть элементов
|
||||||
|
- **GIVEN** шесть акций с суммами 300, 250, 200, 150, 60 и 40 RUB
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** диаграмма состоит из шести сегментов с долями 30 %, 25 %, 20 %, 15 %, 6 %, 4 %
|
||||||
|
|
||||||
|
### Requirement: Центр диаграммы
|
||||||
|
Система SHALL показывать в центре диаграммы сумму разреза — точную сумму учитываемых позиций в выбранной валюте, а над ней, когда показывается метрика «доля топ-5», подпись «Топ-5 · N %», где N — доля в формате «Показ долей». Без метрики показывается только сумма. Эти значения SHALL входить в текстовый эквивалент диаграммы.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081)
|
||||||
|
|
||||||
|
#### Scenario: Центр при семи акциях
|
||||||
|
- **GIVEN** в RUB семь акций с суммами 400, 250, 150, 100, 50, 30 и 20
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** в центре «Топ-5 · 95 %» и «1 000 ₽»
|
||||||
|
|
||||||
|
#### Scenario: Центр при пяти акциях
|
||||||
|
- **GIVEN** в RUB пять акций с суммами 300, 250, 200, 150 и 100
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** в центре только «1 000 ₽»
|
||||||
|
|
||||||
|
### Requirement: Строки без переходов
|
||||||
|
Строка списка в любом разрезе SHALL NOT вести на другую страницу; единственное действие строки — раскрытие и сворачивание «Прочее». Строки разреза «Эмитенты» SHALL NOT содержать логотипов.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081)
|
||||||
|
|
||||||
|
#### Scenario: Нажатие на строку акции
|
||||||
|
- **WHEN** User нажимает на строку акции в разрезе «Акции»
|
||||||
|
- **THEN** страница не меняется
|
||||||
|
|
||||||
|
#### Scenario: Строка эмитента
|
||||||
|
- **WHEN** User открывает разрез «Эмитенты»
|
||||||
|
- **THEN** строки показаны без логотипов
|
||||||
|
|
||||||
|
### Requirement: Доступность диаграммы без цвета
|
||||||
|
Информация диаграммы SHALL NOT передаваться только цветом: каждый сегмент SHALL быть сопоставим со строкой списка по названию и доле, доступным как текст. Диаграмма SHALL иметь текстовый эквивалент с названиями, суммами и долями сегментов в порядке списка, доступный вспомогательным технологиям.
|
||||||
|
|
||||||
|
#### Scenario: Сегменты различимы без цвета
|
||||||
|
- **GIVEN** показан разрез из шести строк
|
||||||
|
- **WHEN** User читает диаграмму вспомогательной технологией
|
||||||
|
- **THEN** доступны название, сумма и доля каждого сегмента в порядке списка, сопоставление со строкой не требует различения цветов
|
||||||
|
|
||||||
|
### Requirement: Пустое состояние разреза
|
||||||
|
Если выбранный разрез не содержит учитываемых элементов, система SHALL показывать пустое состояние с названием разреза и выбранной валютой (если валюты доступны) вместо списка, суммарной доли и диаграммы. Выбор валюты, если он показывается, и сноска при N больше нуля SHALL оставаться доступными.
|
||||||
|
|
||||||
|
#### Scenario: Нет облигаций в выбранной валюте
|
||||||
|
- **GIVEN** есть акции в RUB и облигации только в USD
|
||||||
|
- **WHEN** User открывает разрез «Облигации» в RUB
|
||||||
|
- **THEN** показано пустое состояние, выбор валюты доступен (валют две)
|
||||||
|
|
||||||
|
#### Scenario: Все позиции разреза отрицательные
|
||||||
|
- **GIVEN** в RUB есть только одна акция со стоимостью -50
|
||||||
|
- **WHEN** User открывает разрез «Акции» в RUB
|
||||||
|
- **THEN** показано пустое состояние и сноска «Не учтено позиций: 1»
|
||||||
|
|
||||||
|
### Requirement: Предупреждение о неполных данных
|
||||||
|
Если `meta` обозначает неполноту по «Результат личного обновления остаётся наблюдаемым» из `tbank-data-sync`, вкладка SHALL показывать предупреждение «Данные неполные» над разрезом, считая разрезы по доступным данным. Страница SHALL NOT дублировать его; позиции без оценки его не вызывают.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081), [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082)
|
||||||
|
|
||||||
|
#### Scenario: Неполный Portfolio
|
||||||
|
- **GIVEN** `meta` обозначает неполноту, акции стоят 600 и 400 RUB
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** показаны предупреждение «Данные неполные» и доли 60 % и 40 %
|
||||||
|
|
||||||
|
#### Scenario: Предупреждение не дублируется
|
||||||
|
- **GIVEN** `meta` обозначает неполноту
|
||||||
|
- **WHEN** User открывает вкладку «Концентрация»
|
||||||
|
- **THEN** на странице одно сообщение о неполноте — «Данные неполные» на вкладке
|
||||||
|
|
||||||
|
#### Scenario: Полный Portfolio с неоценённой позицией
|
||||||
|
- **GIVEN** Portfolio полный, одна акция без `currentValue`
|
||||||
|
- **WHEN** User открывает разрез «Акции»
|
||||||
|
- **THEN** предупреждения «Данные неполные» нет, есть сноска «Не учтено позиций: 1»
|
||||||
|
|
||||||
|
### Requirement: Состояния Portfolio на вкладке «Концентрация»
|
||||||
|
Загрузка, ошибка, устаревание и неполнота Portfolio на вкладке «Концентрация» SHALL соответствовать требованию «Состояния и ошибки Portfolio на клиенте» из `portfolio-view`, как на вкладке «Позиции». Отсутствие сектора или эмитента у позиций SHALL NOT скрывать вкладку и менять успешность и свежесть Portfolio.
|
||||||
|
|
||||||
|
#### Scenario: Устаревший Portfolio
|
||||||
|
- **GIVEN** клиент получает Portfolio с `isStale: true`
|
||||||
|
- **WHEN** User открывает вкладку «Концентрация»
|
||||||
|
- **THEN** разрезы рассчитаны по этому Portfolio, устаревание обозначено так же, как на вкладке «Позиции»
|
||||||
|
|
||||||
|
#### Scenario: Сектор и эмитент отсутствуют
|
||||||
|
- **GIVEN** у всех позиций `sector: null` и `issuer: null`, Portfolio успешен
|
||||||
|
- **WHEN** User открывает разрезы «Секторы» и «Эмитенты»
|
||||||
|
- **THEN** каждый разрез содержит один элемент «Сектор не указан» или «Эмитент не указан» с долей 100 %
|
||||||
@@ -22,7 +22,7 @@ Portfolio Snapshot является результатом наблюдения
|
|||||||
### Requirement: Нормализованный состав Portfolio
|
### Requirement: Нормализованный состав Portfolio
|
||||||
Система MUST возвращать только обычные Portfolio Position с ненулевым количеством и доступные Cash Balance с ненулевой суммой. Cash Balance MUST быть отдельным от Portfolio Position элементом и агрегироваться до одного значения на валюту. Portfolio Position с типом `CURRENCY` MUST означать позицию по торгуемому валютному Instrument и MUST NOT смешиваться с Cash Balance. Порядок Portfolio Position и Cash Balance MUST соответствовать upstream-порядку; система MUST NOT сортировать или объединять Portfolio Position с одинаковым FIGI. Виртуальные позиции и заблокированные денежные остатки MUST NOT входить в Portfolio.
|
Система MUST возвращать только обычные Portfolio Position с ненулевым количеством и доступные Cash Balance с ненулевой суммой. Cash Balance MUST быть отдельным от Portfolio Position элементом и агрегироваться до одного значения на валюту. Portfolio Position с типом `CURRENCY` MUST означать позицию по торгуемому валютному Instrument и MUST NOT смешиваться с Cash Balance. Порядок Portfolio Position и Cash Balance MUST соответствовать upstream-порядку; система MUST NOT сортировать или объединять Portfolio Position с одинаковым FIGI. Виртуальные позиции и заблокированные денежные остатки MUST NOT входить в Portfolio.
|
||||||
|
|
||||||
Каждая Portfolio Position MUST содержать нормализованный тип `STOCK`, `BOND`, `FUND`, `CURRENCY`, `FUTURE`, `OPTION`, `STRUCTURED_NOTE`, `DIGITAL_FINANCIAL_ASSET` либо `OTHER`, строковое `quantity`, nullable `currentValue`, nullable `averagePurchasePrice`, nullable `absoluteReturn`, nullable `isin`, nullable `ticker` и nullable `logoName` — имя файла логотипа бренда инструмента. Имя файла логотипа MUST заполняться из metadata инструмента, когда upstream предоставляет бренд с непустым именем файла логотипа; во всех остальных случаях оно MUST быть `null`. Логотип является presentation metadata: он не влияет на количество, стоимость, агрегаты, успешность или свежесть Portfolio Snapshot. Система MUST искать metadata по instrument UID при его наличии, затем по FIGI. Отображаемый идентификатор MUST предпочитать name, затем ticker, а при недоступности metadata использовать FIGI, не скрывая финансовые значения.
|
Каждая Portfolio Position MUST содержать нормализованный тип `STOCK`, `BOND`, `FUND`, `CURRENCY`, `FUTURE`, `OPTION`, `STRUCTURED_NOTE`, `DIGITAL_FINANCIAL_ASSET` либо `OTHER`, строковое `quantity`, nullable `currentValue`, nullable `averagePurchasePrice`, nullable `absoluteReturn`, nullable `isin`, nullable `ticker` и nullable `logoName` — имя файла логотипа бренда инструмента, nullable `sector` — сектор инструмента и nullable `issuer` — эмитент позиции. Имя файла логотипа MUST заполняться из metadata инструмента, когда upstream предоставляет бренд с непустым именем файла логотипа; во всех остальных случаях оно MUST быть `null`. Логотип является presentation metadata: он не влияет на количество, стоимость, агрегаты, успешность или свежесть Portfolio Snapshot. Поле `sector` позиции типа `STOCK`, `BOND` или `FUND` MUST содержать значение сектора из metadata инструмента в том виде, как его определяет T-Bank, без перекодирования и собственной классификации, с обрезанными пробелами в начале и конце; значение из одних пробелов считается отсутствующим. Во всех остальных случаях, включая остальные типы позиций, оно MUST быть `null`. Поле `issuer` позиции типа `STOCK`, `BOND` или `FUND`, включая фонд, MUST быть объектом с непустыми строками `id` — идентификатор бренда актива инструмента — и `name` — название этого бренда (не название компании), когда T-Bank предоставляет для инструмента бренд актива с идентификатором и названием, непустыми после обрезки пробелов в начале и конце; значение из одних пробелов считается отсутствующим. Во всех остальных случаях, включая остальные типы позиций, оно MUST быть `null`. Система MUST NOT определять эмитента по совпадению названия, тикера или ISIN. Сектор и эмитент не влияют на количество, стоимость, агрегаты, успешность или свежесть Portfolio Snapshot: их отсутствие либо недоступность MUST NOT делать Snapshot неуспешным или устаревшим и MUST NOT скрывать позицию или её финансовые значения, кроме отказа token по требованию «Свежесть и fallback полного Portfolio Snapshot». Система MUST искать metadata по instrument UID при его наличии, затем по FIGI. Отображаемый идентификатор MUST предпочитать name, затем ticker, а при недоступности metadata использовать FIGI, не скрывая финансовые значения.
|
||||||
|
|
||||||
#### Scenario: Позиция с неизвестным upstream-типом
|
#### Scenario: Позиция с неизвестным upstream-типом
|
||||||
- **WHEN** upstream возвращает обычную ненулевую позицию с нераспознанным типом инструмента
|
- **WHEN** upstream возвращает обычную ненулевую позицию с нераспознанным типом инструмента
|
||||||
@@ -76,6 +76,51 @@ Portfolio Snapshot является результатом наблюдения
|
|||||||
- **WHEN** у доступного Brokerage Account нет ненулевых обычных позиций и доступных денежных остатков
|
- **WHEN** у доступного Brokerage Account нет ненулевых обычных позиций и доступных денежных остатков
|
||||||
- **THEN** система отвечает `200` с пустыми `positions`, `cashBalances` и `totalsByCurrency`
|
- **THEN** система отвечает `200` с пустыми `positions`, `cashBalances` и `totalsByCurrency`
|
||||||
|
|
||||||
|
#### Scenario: Сектор инструмента доступен
|
||||||
|
- **WHEN** metadata инструмента позиции содержит сектор `energy`
|
||||||
|
- **THEN** система возвращает в поле `sector` позиции значение `energy` без изменений
|
||||||
|
|
||||||
|
#### Scenario: Сектор инструмента отсутствует
|
||||||
|
- **WHEN** у инструмента позиции нет сектора, сектор пустой либо metadata недоступна
|
||||||
|
- **THEN** система возвращает позицию с `sector: null`, не скрывая финансовые значения
|
||||||
|
|
||||||
|
#### Scenario: Эмитент позиции доступен
|
||||||
|
- **WHEN** T-Bank предоставляет для инструмента позиции бренд актива с идентификатором `brand-1` и названием «Сбер»
|
||||||
|
- **THEN** система возвращает в поле `issuer` позиции идентификатор `brand-1` и название «Сбер»
|
||||||
|
|
||||||
|
#### Scenario: Название эмитента — название бренда
|
||||||
|
- **WHEN** T-Bank предоставляет для инструмента бренд актива с названием «Сбер» и компанией «ПАО Сбербанк»
|
||||||
|
- **THEN** система возвращает в `issuer.name` «Сбер»
|
||||||
|
|
||||||
|
#### Scenario: Эмитент у фонда
|
||||||
|
- **WHEN** T-Bank предоставляет для инструмента позиции `FUND` бренд актива с идентификатором `brand-2` и названием «Фонд»
|
||||||
|
- **THEN** система возвращает в `issuer` позиции идентификатор `brand-2` и название «Фонд»
|
||||||
|
|
||||||
|
#### Scenario: Пробелы по краям обрезаются
|
||||||
|
- **WHEN** T-Bank возвращает сектор " energy " и название бренда " Сбер "
|
||||||
|
- **THEN** система возвращает `sector` `energy` и `issuer.name` «Сбер»
|
||||||
|
|
||||||
|
#### Scenario: Значение из одних пробелов
|
||||||
|
- **WHEN** T-Bank возвращает сектор " " либо название бренда " "
|
||||||
|
- **THEN** система возвращает `sector: null` либо `issuer: null` соответственно
|
||||||
|
|
||||||
|
#### Scenario: Остальные типы позиций
|
||||||
|
- **WHEN** T-Bank предоставляет сектор и бренд актива для инструмента позиции типа `FUTURE`
|
||||||
|
- **THEN** система возвращает у этой позиции `sector: null` и `issuer: null`
|
||||||
|
|
||||||
|
#### Scenario: Эмитент позиции отсутствует
|
||||||
|
- **WHEN** у инструмента позиции нет бренда актива, идентификатор либо название бренда пустые или данные бренда недоступны
|
||||||
|
- **THEN** система возвращает позицию с `issuer: null`, не скрывая финансовые значения
|
||||||
|
|
||||||
|
#### Scenario: Эмитент не определяется по названию
|
||||||
|
- **WHEN** две позиции имеют одинаковое название, но разные идентификаторы бренда актива
|
||||||
|
- **THEN** система возвращает в `issuer` позиций разные идентификаторы бренда и не объединяет их
|
||||||
|
|
||||||
|
#### Scenario: Недоступность сектора и эмитента не нарушает Snapshot
|
||||||
|
- **GIVEN** сектор и бренд актива позиции ещё ни разу не получены
|
||||||
|
- **WHEN** получение сектора и бренда актива завершается ошибкой, а количества и цены позиции получены
|
||||||
|
- **THEN** система сохраняет Snapshot с `sector: null` и `issuer: null` у затронутых позиций; их `currentValue`, `totalsByCurrency`, `lastSuccessfulAt` и `isStale` такие же, как при доступных сектора и бренде
|
||||||
|
|
||||||
### Requirement: Точные значения и валютные агрегаты
|
### Requirement: Точные значения и валютные агрегаты
|
||||||
Все количества и финансовые значения в Portfolio Snapshot MUST передаваться десятичными строками без экспоненциальной записи и без незначащих завершающих нулей. Денежное значение MUST быть единым Money-значением с ISO-кодом валюты и десятичной строкой значения. Система MUST корректно нормализовать отрицательные целую и дробную части upstream-значений. Отсутствующее значение MUST передаваться как `null`, а не как ноль.
|
Все количества и финансовые значения в Portfolio Snapshot MUST передаваться десятичными строками без экспоненциальной записи и без незначащих завершающих нулей. Денежное значение MUST быть единым Money-значением с ISO-кодом валюты и десятичной строкой значения. Система MUST корректно нормализовать отрицательные целую и дробную части upstream-значений. Отсутствующее значение MUST передаваться как `null`, а не как ноль.
|
||||||
|
|
||||||
@@ -94,9 +139,9 @@ Portfolio Snapshot является результатом наблюдения
|
|||||||
- **THEN** система передаёт её как строку `"-0.5"`
|
- **THEN** система передаёт её как строку `"-0.5"`
|
||||||
|
|
||||||
### Requirement: Свежесть и fallback полного Portfolio Snapshot
|
### Requirement: Свежесть и fallback полного Portfolio Snapshot
|
||||||
Система MUST хранить последний полный успешно полученный Portfolio Snapshot с принадлежностью User, экземпляру подключения и Brokerage Account. Обычный GET MUST возвращать `{ data, meta }`, где `data` является сохранённым Snapshot, а `meta` соответствует наблюдаемому состоянию resource по `tbank-data-sync`, читать его без ожидания T-Bank и MUST NOT запускать обновление личного Portfolio, даже если Snapshot отсутствует или старше 60 минут; обновлением владеет часовой обход. Portfolio source MUST считаться свежим в течение 60 минут после успешного получения. Ошибка обхода MUST сохранять прежний полный Snapshot и его время без лимита fallback. Если состав получен полностью, но отдельная позиция не имеет цены, система MUST сохранить новый состав с неполной оценкой; metadata MUST NOT определять успешность или свежесть финансового Snapshot. Сохранённая доступная identity позиции MAY оставаться доступной при недоступности online-справочника.
|
Система MUST хранить последний полный успешно полученный Portfolio Snapshot с принадлежностью User, экземпляру подключения и Brokerage Account. Обычный GET MUST возвращать `{ data, meta }`, где `data` является сохранённым Snapshot, а `meta` соответствует наблюдаемому состоянию resource по `tbank-data-sync`, читать его без ожидания T-Bank и MUST NOT запускать обновление личного Portfolio, даже если Snapshot отсутствует или старше 60 минут; обновлением владеет часовой обход. Portfolio source MUST считаться свежим в течение 60 минут после успешного получения. Ошибка обхода MUST сохранять прежний полный Snapshot и его время без лимита fallback. Если состав получен полностью, но отдельная позиция не имеет цены, система MUST сохранить новый состав с неполной оценкой; metadata MUST NOT определять успешность или свежесть финансового Snapshot, кроме отказа token при получении сектора или бренда актива позиции: он MUST обрабатываться так же, как отказ token при обходе Portfolio (исключение, источник — [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082)). Сохранённая доступная identity позиции MAY оставаться доступной при недоступности online-справочника.
|
||||||
|
|
||||||
Система MUST делать прежние личные datasets недоступными после успешной замены или удаления подключения. Поздняя работа прежнего подключения MUST NOT публиковаться в новом. Самостоятельные справочные сведения и результаты lookup MUST запрашиваться онлайн, а не сохраняться как долговременный справочник; ошибка lookup не подтверждает отсутствие инструмента.
|
Система MUST делать прежние личные datasets недоступными после успешной замены или удаления подключения. Поздняя работа прежнего подключения MUST NOT публиковаться в новом. Самостоятельные справочные сведения и результаты lookup MUST запрашиваться онлайн, а не сохраняться как долговременный справочник; ошибка lookup не подтверждает отсутствие инструмента. Исключение: сектор и бренд актива позиции MUST храниться как последнее известное значение и обновляться по требованию «Обновление сектора и эмитента» ([#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082)).
|
||||||
|
|
||||||
#### Scenario: Свежий Snapshot
|
#### Scenario: Свежий Snapshot
|
||||||
- **WHEN** User повторно запрашивает тот же Portfolio в течение 60 минут после успешного получения
|
- **WHEN** User повторно запрашивает тот же Portfolio в течение 60 минут после успешного получения
|
||||||
@@ -118,6 +163,15 @@ Portfolio Snapshot является результатом наблюдения
|
|||||||
- **WHEN** успешно получен полный состав позиций, но у одной позиции нет вычислимой цены
|
- **WHEN** успешно получен полный состав позиций, но у одной позиции нет вычислимой цены
|
||||||
- **THEN** новый состав становится текущим Portfolio Snapshot с неизвестной стоимостью позиции без подстановки нуля
|
- **THEN** новый состав становится текущим Portfolio Snapshot с неизвестной стоимостью позиции без подстановки нуля
|
||||||
|
|
||||||
|
#### Scenario: Сектор и бренд читаются из хранимого значения
|
||||||
|
- **GIVEN** сектор позиции получен 10 часов назад
|
||||||
|
- **WHEN** User запрашивает Portfolio
|
||||||
|
- **THEN** система возвращает хранимый `sector` без обращения к T-Bank за сектором
|
||||||
|
|
||||||
|
#### Scenario: Отказ token при получении бренда
|
||||||
|
- **WHEN** T-Bank отклоняет token как неаутентифицированный или без прав при получении сектора или бренда актива позиции
|
||||||
|
- **THEN** система не возвращает fallback Snapshot и отвечает `400` Problem Details с code `INVALID_TBANK_TOKEN`, как при отказе token в обходе Portfolio
|
||||||
|
|
||||||
### Requirement: Состояния и ошибки Portfolio на клиенте
|
### Requirement: Состояния и ошибки Portfolio на клиенте
|
||||||
|
|
||||||
Клиент SHALL загружать Portfolio при открытии защищённого маршрута
|
Клиент SHALL загружать Portfolio при открытии защищённого маршрута
|
||||||
@@ -411,3 +465,57 @@ MUST NOT создавать нулевую карточку. Отсутстви
|
|||||||
- **WHEN** `totalsByCurrency` пуст, но `positions` или `cashBalances` непусты
|
- **WHEN** `totalsByCurrency` пуст, но `positions` или `cashBalances` непусты
|
||||||
- **THEN** клиент не создаёт валютные карточки и не заменяет доступный
|
- **THEN** клиент не создаёт валютные карточки и не заменяет доступный
|
||||||
состав Portfolio состоянием пустого портфеля
|
состав Portfolio состоянием пустого портфеля
|
||||||
|
|
||||||
|
### Requirement: Обновление сектора и эмитента
|
||||||
|
Система SHALL обновлять сектор и бренд актива позиции при первом обходе по `hourly-investment-sync`, начавшемся не ранее чем через 24 часа после последнего успешного получения; в остальных обходах значение не меняется. Пока значение не получено, получение повторяется при каждом обходе.
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081), [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082)
|
||||||
|
|
||||||
|
#### Scenario: Обход раньше 24 часов
|
||||||
|
- **GIVEN** бренд позиции получен в понедельник в 09:00, а затем T-Bank сменил его название
|
||||||
|
- **WHEN** обход начинается во вторник в 08:59, то есть через 23 ч 59 мин
|
||||||
|
- **THEN** `issuer.name` остаётся прежним
|
||||||
|
|
||||||
|
#### Scenario: Обход через 24 часа
|
||||||
|
- **GIVEN** бренд позиции получен в понедельник в 09:00, а затем T-Bank сменил его название
|
||||||
|
- **WHEN** обход начинается во вторник в 09:00
|
||||||
|
- **THEN** `issuer.name` новое
|
||||||
|
|
||||||
|
### Requirement: Результат получения сектора и эмитента
|
||||||
|
Результат получения SHALL определять поле позиции и отсчёт 24 часов по таблице; совпадает ровно одна строка.
|
||||||
|
|
||||||
|
| Исход получения | Поле | Отсчёт 24 часов |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Получено значение | Новое значение | Начинается заново |
|
||||||
|
| Ответ «не найдено» или значения нет | `null` | Начинается заново |
|
||||||
|
| Ответ о другом инструменте или активе | Прежнее значение или `null` | Не меняется; получение неуспешно |
|
||||||
|
| Иная ошибка, кроме отказа token | Прежнее значение или `null` | Не меняется; получение неуспешно |
|
||||||
|
|
||||||
|
Неуспешное получение SHALL NOT мешать обновлению остальных данных Portfolio; отказ token — по «Свежесть и fallback полного Portfolio Snapshot».
|
||||||
|
|
||||||
|
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082)
|
||||||
|
|
||||||
|
#### Scenario: Ответ без значения заменяет известное значение
|
||||||
|
- **GIVEN** у позиции известен `sector` `energy`, 24 часа прошли
|
||||||
|
- **WHEN** T-Bank отвечает, что сектора у инструмента нет
|
||||||
|
- **THEN** `sector: null`
|
||||||
|
|
||||||
|
#### Scenario: «Не найдено» перезапускает отсчёт
|
||||||
|
- **GIVEN** у позиции известен `sector` `energy`, 24 часа прошли, и обход получает от T-Bank «не найдено»
|
||||||
|
- **WHEN** следующий обход начинается через час, а T-Bank уже возвращает сектор `financial`
|
||||||
|
- **THEN** `sector` остаётся `null`; значение `financial` появляется при первом обходе, начавшемся не ранее чем через 24 часа после ответа «не найдено»
|
||||||
|
|
||||||
|
#### Scenario: Ответ о другом инструменте
|
||||||
|
- **GIVEN** у позиции известен `sector` `energy`, 24 часа прошли
|
||||||
|
- **WHEN** T-Bank возвращает данные другого инструмента
|
||||||
|
- **THEN** `sector` остаётся `energy`, а следующий обход повторяет получение
|
||||||
|
|
||||||
|
#### Scenario: Недоступность T-Bank сохраняет известное значение
|
||||||
|
- **GIVEN** у позиции известен `sector` `energy`, 24 часа прошли
|
||||||
|
- **WHEN** получение сектора завершается недоступностью T-Bank, а цены и количества получены
|
||||||
|
- **THEN** позиция возвращается с `sector` `energy`, остальные данные Portfolio обновлены, `lastSuccessfulAt` новый
|
||||||
|
|
||||||
|
#### Scenario: Значение ещё не известно
|
||||||
|
- **GIVEN** новая позиция, сектор которой ни разу не получен успешно
|
||||||
|
- **WHEN** получение сектора неуспешно при одном обходе и успешно при следующем
|
||||||
|
- **THEN** после первого обхода `sector: null`, после следующего значение сектора
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
# project-documentation Specification
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
Определяет обязательную документацию архитектурных решений и пользовательских возможностей, сопровождающую SDD-изменения WealthLedger.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
### Requirement: Completion Evidence сохраняет фактическое завершение change
|
|
||||||
|
|
||||||
Canonical archived OpenSpec change SHALL хранить Completion Evidence с
|
|
||||||
фактической Delivery Map, commit identifiers изменённых delivery areas, точными
|
|
||||||
выполненными verification commands и их observed results, а также итогом
|
|
||||||
independent read-only review. Completion Evidence MUST создаваться только после
|
|
||||||
существования этих фактов, MUST быть доступно вместе с canonical archive и MUST
|
|
||||||
NOT представляться как unchecked Task, планируемый результат или обязательная
|
|
||||||
docs-мутация для area со статусом `N/A`.
|
|
||||||
|
|
||||||
#### Scenario: Участник проверяет основание terminal status
|
|
||||||
|
|
||||||
- **WHEN** участник открывает canonical archive завершённого change в новой
|
|
||||||
сессии
|
|
||||||
- **THEN** он может проследить связь от Delivery Map к фактическим commits,
|
|
||||||
affected local gates и independent review без восстановления контекста из
|
|
||||||
чата или параллельного evidence store
|
|
||||||
|
|
||||||
#### Scenario: Реализация ещё продолжается
|
|
||||||
|
|
||||||
- **WHEN** часть delivery commits, commands, observed results или review ещё не
|
|
||||||
существует
|
|
||||||
- **THEN** change не представляет ожидаемые значения как Completion Evidence и
|
|
||||||
не получает terminal status
|
|
||||||
|
|
||||||
#### Scenario: Технический change не меняет as-built documentation
|
|
||||||
|
|
||||||
- **WHEN** фактическая Delivery Map обоснованно устанавливает `docs: N/A`
|
|
||||||
- **THEN** Completion Evidence сохраняет эту причину рядом с canonical archive
|
|
||||||
и не требует несвязанного изменения docs repository
|
|
||||||
|
|
||||||
### Requirement: Важные архитектурные решения фиксируются в ADR
|
|
||||||
Репозиторий docs SHALL содержать ADR для выбора локального хранилища, API-контракта, gRPC-интеграции T-Bank, хранения T-Bank токенов, устойчивости upstream-вызовов, auth-сессий и frontend-кэша. Каждый ADR MUST описывать контекст, решение и последствия.
|
|
||||||
|
|
||||||
#### Scenario: Разработчик оценивает архитектурное ограничение
|
|
||||||
- **WHEN** разработчик хочет изменить один из зафиксированных механизмов
|
|
||||||
- **THEN** он может определить исходное решение и его последствия из соответствующего ADR
|
|
||||||
|
|
||||||
### Requirement: Реализованная фича получает документацию
|
|
||||||
Каждая завершенная пользовательская фича SHALL иметь Markdown-документ в `docs/features`, описывающий пользовательский поток, API-сценарий, ограничения и необходимые Mermaid-диаграммы.
|
|
||||||
|
|
||||||
#### Scenario: Функциональное изменение готово к закрытию
|
|
||||||
- **WHEN** реализация пользовательской фичи завершена
|
|
||||||
- **THEN** ее feature-документ существует и отражает фактическое поведение
|
|
||||||
|
|
||||||
### Requirement: OpenSpec change закрывается только после полной верификации
|
|
||||||
|
|
||||||
OpenSpec change MUST содержать все обязательные planning artifacts и
|
|
||||||
завершённые implementation-owned Tasks до архивирования. Archive MUST быть
|
|
||||||
заблокирован, пока отсутствует успешный canonical gate любой affected area,
|
|
||||||
semantic и acceptance verification реализации относительно approved artifacts
|
|
||||||
либо independent read-only review без Critical и Important findings; для area
|
|
||||||
со статусом `N/A` MUST существовать конкретная проверяемая причина.
|
|
||||||
|
|
||||||
#### Scenario: Команда пытается архивировать незавершенное изменение
|
|
||||||
|
|
||||||
- **WHEN** для change отсутствует обязательный artifact, implementation-owned
|
|
||||||
результат, affected-area gate, semantic или acceptance verification,
|
|
||||||
допустимый independent review либо требуемая as-built documentation
|
|
||||||
- **THEN** change не архивируется и остаётся незавершённым без confirmation
|
|
||||||
override
|
|
||||||
|
|
||||||
#### Scenario: Delivery area не затронута
|
|
||||||
|
|
||||||
- **WHEN** Delivery Map помечает area как `N/A`
|
|
||||||
- **THEN** archive допускает отсутствие её commit и gate только при наличии
|
|
||||||
конкретной проверяемой причины
|
|
||||||
|
|
||||||
### Requirement: Документация процесса содержит remediation registry
|
|
||||||
|
|
||||||
Репозиторий `docs` SHALL содержать immutable versioned audit snapshots в
|
|
||||||
`docs/audits` и versioned remediation registry в development documentation.
|
|
||||||
Registry MUST документировать source audit, допустимые статусы, связанные
|
|
||||||
OpenSpec changes и следующую рекомендуемую задачу. Для завершённого
|
|
||||||
audit-derived change registry MUST ссылаться на canonical archive и его
|
|
||||||
Completion Evidence, а не дублировать commits и verification results как
|
|
||||||
отдельный evidence store.
|
|
||||||
|
|
||||||
#### Scenario: Участник проекта ищет состояние технических улучшений
|
|
||||||
|
|
||||||
- **WHEN** участник открывает development documentation
|
|
||||||
- **THEN** он может найти audit snapshot и registry через documentation indexes
|
|
||||||
и определить, какие findings planned, active, done, deferred или accepted
|
|
||||||
|
|
||||||
#### Scenario: Завершён audit-derived change
|
|
||||||
|
|
||||||
- **WHEN** связанный OpenSpec change получил terminal status после успешной
|
|
||||||
проверки
|
|
||||||
- **THEN** registry содержит его итоговый статус и ссылку на canonical archive
|
|
||||||
с Completion Evidence
|
|
||||||
|
|
||||||
### Requirement: Durable documentation is not a parallel SDD store
|
|
||||||
|
|
||||||
Репозиторий `docs` SHALL хранить только долговечную architecture, development,
|
|
||||||
feature, audit и remediation documentation. Документация MUST описывать
|
|
||||||
фактическое текущее состояние поставленной системы и MUST NOT представлять
|
|
||||||
планируемое или частично реализованное поведение как доступное. Change-specific
|
|
||||||
requirements, proposals, designs, delta specifications, tasks и Completion
|
|
||||||
Evidence MUST храниться только в canonical OpenSpec store и MUST NOT
|
|
||||||
пересказываться в `docs` как параллельная спецификация или evidence store. Docs
|
|
||||||
SHALL обновляться после реализации и проверки только когда её as-built subject
|
|
||||||
действительно affected.
|
|
||||||
|
|
||||||
#### Scenario: Change требует постоянной документации
|
|
||||||
|
|
||||||
- **WHEN** завершённый change меняет поставленное поведение, архитектурную
|
|
||||||
границу, устойчивое решение или другой as-built subject docs
|
|
||||||
- **THEN** documentation фиксирует реализованное состояние и MAY ссылаться на
|
|
||||||
canonical OpenSpec change без дублирования его planning artifacts или
|
|
||||||
Completion Evidence
|
|
||||||
|
|
||||||
#### Scenario: Agent планирует незавершённый change
|
|
||||||
|
|
||||||
- **WHEN** агент создаёт requirements, design или tasks для незавершённого
|
|
||||||
изменения
|
|
||||||
- **THEN** он сохраняет их в canonical OpenSpec store и не создаёт
|
|
||||||
framework-specific planning document или описание будущего поведения в docs
|
|
||||||
|
|
||||||
#### Scenario: Реализация расходится с прежней документацией
|
|
||||||
|
|
||||||
- **WHEN** проверенный change изменяет поставленное поведение, архитектурную
|
|
||||||
границу или устойчивое решение
|
|
||||||
- **THEN** affected docs обновляется до фактического текущего состояния до
|
|
||||||
terminal status и не сохраняет прежнее утверждение как действующее
|
|
||||||
|
|
||||||
#### Scenario: Docs не входит в Delivery Map
|
|
||||||
|
|
||||||
- **WHEN** технический change не меняет ни один as-built subject docs и Delivery
|
|
||||||
Map устанавливает `docs: N/A` с проверяемой причиной
|
|
||||||
- **THEN** terminal status не требует изменения docs только ради Completion
|
|
||||||
Evidence
|
|
||||||
|
|
||||||
### Requirement: Устойчивая документация имеет доступные фактические точки входа
|
|
||||||
Репозиторий `docs` SHALL содержать indexes архитектуры, разработки и фич,
|
|
||||||
которые ведут разработчика или AI-агента к фактической устойчивой документации
|
|
||||||
без обращения к архивированному change или корневому delivery-plan файлу.
|
|
||||||
Архитектурная документация MUST содержать system overview поставленных
|
|
||||||
возможностей и локальных границ, канонический domain glossary, а также
|
|
||||||
Mermaid-диаграммы потоков auth/session и T-Bank → клиент. Feature documentation
|
|
||||||
MUST предоставлять index поставленных фич и MUST NOT описывать поставленные
|
|
||||||
Brokerage Accounts, Portfolio, Account Ledger или Future Cash Events как
|
|
||||||
отложенные.
|
|
||||||
|
|
||||||
Канонический domain glossary MUST закреплять различие между Brokerage Account,
|
|
||||||
доступным через текущее T-Bank connection, Portfolio Snapshot, Portfolio
|
|
||||||
Position, Currency Instrument Position, Cash Balance, Money, Instrument, Ledger
|
|
||||||
Entry и Future Cash Event. Runtime/cache-термины MUST быть отделены от
|
|
||||||
доменных терминов так, чтобы документация не представляла технический механизм
|
|
||||||
как бизнес-сущность.
|
|
||||||
|
|
||||||
#### Scenario: Новый участник находит поставленную систему
|
|
||||||
- **WHEN** новый участник открывает устойчивую документацию
|
|
||||||
- **THEN** он может перейти из index к system overview, glossary, документам
|
|
||||||
поставленных фич и соответствующему development workflow
|
|
||||||
|
|
||||||
#### Scenario: Участник различает близкие доменные понятия
|
|
||||||
- **WHEN** участнику нужно описать cached portfolio data, валютную позицию,
|
|
||||||
денежный остаток или account operation
|
|
||||||
- **THEN** канонический glossary различает runtime/cache-механизмы, Portfolio
|
|
||||||
Snapshot, Currency Instrument Position, Cash Balance, Future Cash Event и
|
|
||||||
Ledger Entry
|
|
||||||
|
|
||||||
### Requirement: README репозиториев являются компактными onboarding entrypoints
|
|
||||||
Репозитории frontend и backend SHALL предоставлять русскоязычные README
|
|
||||||
entrypoints, которые указывают Node 24, lockfile-safe bootstrap, локальные
|
|
||||||
non-mutating verification commands, требуемую локальную configuration и ссылки
|
|
||||||
на authoritative или just-in-time documentation. README MUST различать deferred
|
|
||||||
check и passing verification gate, а detailed rationale deferred Prisma e2e и
|
|
||||||
его review trigger MUST быть ссылкой на remediation registry, а не дублироваться.
|
|
||||||
|
|
||||||
#### Scenario: Участник bootstrap-ит application repository
|
|
||||||
- **WHEN** участник открывает frontend или backend README на чистой локальной
|
|
||||||
машине
|
|
||||||
- **THEN** он может определить требуемый runtime, подготовить local
|
|
||||||
configuration, установить зависимости из lockfile и запустить
|
|
||||||
документированные local gates без угадывания
|
|
||||||
|
|
||||||
#### Scenario: Участник видит ограничение backend e2e
|
|
||||||
- **WHEN** участник читает backend onboarding instructions
|
|
||||||
- **THEN** он узнаёт, что Prisma e2e gate отложен, и может перейти к
|
|
||||||
remediation registry за его точным статусом и review trigger
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
# project-foundation Specification
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
Определяет минимальный, согласованный фундамент рабочих приложений и правила их совместного развития через отдельные репозитории и SDD-изменения.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
### Requirement: Репозитории содержат локальные инструкции для AI-агентов
|
|
||||||
Система SHALL содержать обзорный `AGENTS.md` в корне рабочей области и отдельный `AGENTS.md` в репозиториях frontend, backend, specs и docs. Корневая инструкция MUST содержать только общую карту workspace, Single Source of Truth, cross-repository workflow и общие hard constraints; локальная инструкция MUST добавлять относящиеся к своему репозиторию команды, проверяемые правила стиля и границ, не копируя изменчивые требования, архитектуру или feature documentation. Инструкции MUST описывать назначение области, канонический non-mutating verification entrypoint, границы ответственности и ссылки на authoritative SDD и durable documentation. Каждая инструкция MUST объявлять `wealth-ledger-specs` и `specs/openspec` как canonical OpenSpec authority, требовать явный `--store wealth-ledger-specs` для поддерживаемых OpenSpec операций и запрещать versioned framework-specific planning artifacts вне canonical store. Локальные инструкции MUST направлять агента к durable documentation, относящейся к его области, и к durable remediation registry, когда задача связана с findings технического аудита. Enforceable Engineering Invariants MUST быть сформулированы как проверяемые обязательные правила; непроверяемые предпочтения MUST быть отделены как guidance. Backend instructions MUST различать non-mutating verification commands и явные auto-fix commands.
|
|
||||||
|
|
||||||
#### Scenario: Агент начинает работу в отдельном репозитории
|
|
||||||
- **WHEN** агент открывает любой из репозиториев frontend, backend, specs или docs
|
|
||||||
- **THEN** он может определить локальные правила работы, канонический verification entrypoint, проверяемый стиль и границы, canonical OpenSpec authority и относящийся к области durable documentation без чтения дублирующих требований
|
|
||||||
|
|
||||||
#### Scenario: Агент получает audit-derived задачу из отдельного репозитория
|
|
||||||
- **WHEN** задача ссылается на finding технического аудита
|
|
||||||
- **THEN** локальный `AGENTS.md` указывает на remediation registry и canonical
|
|
||||||
OpenSpec workflow с явным store selection до начала изменения кода
|
|
||||||
|
|
||||||
#### Scenario: Агент выбирает backend quality gate
|
|
||||||
- **WHEN** агент читает backend instructions перед локальной проверкой
|
|
||||||
- **THEN** он запускает документированный канонический non-mutating gate и не получает auto-fix как неявную часть verification
|
|
||||||
|
|
||||||
#### Scenario: Архитектурное устройство изменилось
|
|
||||||
- **WHEN** durable architecture documentation обновлена после поставленного change
|
|
||||||
- **THEN** `AGENTS.md` продолжает ссылаться на authoritative документ и не требует синхронного копирования его описательного содержимого
|
|
||||||
|
|
||||||
### Requirement: Корень рабочей области не хранит delivery-plan файл
|
|
||||||
Корень рабочей области MUST NOT содержать `MVP.md` или другой versioned
|
|
||||||
delivery-plan файл как источник требований, порядка поставки или фактического
|
|
||||||
поведения. Требования SHALL оставаться в OpenSpec, а delivered system overview
|
|
||||||
и долговечные ограничения SHALL находиться в `docs`. Frontend и backend MUST
|
|
||||||
требовать Node 24 и документировать lockfile-safe bootstrap через `npm ci`.
|
|
||||||
|
|
||||||
#### Scenario: Агент определяет границы поставленной системы
|
|
||||||
- **WHEN** агент начинает работу и ищет актуальные границы WealthLedger
|
|
||||||
- **THEN** он находит их в durable documentation и canonical OpenSpec, а не в
|
|
||||||
корневом delivery-plan файле
|
|
||||||
|
|
||||||
#### Scenario: Агент bootstrap-ит application repository
|
|
||||||
- **WHEN** агент начинает локальную проверку frontend или backend на чистой машине
|
|
||||||
- **THEN** он может определить Node 24 и выполнить `npm ci` без угадывания runtime policy
|
|
||||||
|
|
||||||
### Requirement: Frontend предоставляет минимальный каркас приложения
|
|
||||||
Frontend SHALL предоставлять русскоязычный адаптивный каркас приложения с маршрутами `/login`, `/register`, `/accounts`, `/accounts/:accountId` и `/settings`, светлой финансовой темой и навигацией для счетов и настроек. Каркас MUST содержать состояния загрузки, ошибки и пустых данных без реализации доменных сценариев.
|
|
||||||
|
|
||||||
#### Scenario: Пользователь открывает маршрут MVP
|
|
||||||
- **WHEN** пользователь переходит на любой маршрут MVP
|
|
||||||
- **THEN** frontend отображает соответствующий каркас страницы и не показывает шаблонный Todo-интерфейс
|
|
||||||
|
|
||||||
### Requirement: Backend предоставляет безопасный API-фундамент
|
|
||||||
Backend SHALL публиковать HTTP API с префиксом `/api/v1`, принимать разрешенные frontend origins только из конфигурации и возвращать клиенту безопасные ошибки без секретов или внутренних деталей.
|
|
||||||
|
|
||||||
#### Scenario: Запрос приходит с неразрешенного origin
|
|
||||||
- **WHEN** браузер отправляет cross-origin запрос не с настроенного frontend origin
|
|
||||||
- **THEN** backend не разрешает браузеру доступ к ответу через CORS
|
|
||||||
|
|
||||||
### Requirement: Frontend typecheck строго проверяет application и tooling code
|
|
||||||
Frontend MUST включать TypeScript strict mode для application source и Vite tooling source. Команда локального frontend typecheck MUST завершаться с ошибкой при любом нарушении strict TypeScript и завершаться успешно для committed frontend code.
|
|
||||||
|
|
||||||
#### Scenario: Agent проверяет frontend перед завершением задачи
|
|
||||||
- **WHEN** агент запускает documented frontend verification или его typecheck stage
|
|
||||||
- **THEN** проверка выполняет strict TypeScript compilation application и Vite tooling source и сообщает non-zero exit code при strict diagnostic
|
|
||||||
|
|
||||||
### Requirement: Application repositories имеют канонический локальный gate
|
|
||||||
|
|
||||||
Frontend и backend SHALL предоставлять по одному каноническому non-mutating verification entrypoint, который проверяет все обязательные для соответствующего репозитория Enforceable Engineering Invariants. Каждый entrypoint MUST отклонять неподдерживаемый Node runtime до запуска зависимых application checks, MUST возвращать ненулевой результат при ошибке любого обязательного stage и MUST быть одинаковым для человека, AI-агента и общего workspace verifier. Отдельные auto-fix commands MUST NOT использоваться как verification entrypoint.
|
|
||||||
|
|
||||||
#### Scenario: Агент завершает frontend-изменение
|
|
||||||
|
|
||||||
- **WHEN** агент считает frontend implementation готовой
|
|
||||||
- **THEN** он запускает один documented frontend gate и получает совокупный non-mutating результат всех обязательных frontend checks
|
|
||||||
|
|
||||||
#### Scenario: Агент запускает backend gate с неверным Node
|
|
||||||
|
|
||||||
- **WHEN** фактическая major/minor версия Node не соответствует объявленному runtime contract backend
|
|
||||||
- **THEN** gate завершается ошибкой до application checks и сообщает ожидаемую и фактическую версии
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
# workspace-artifact-hygiene Specification
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
Определяет проверяемые границы для dependency advisories, локальной
|
|
||||||
configuration и SQLite runtime-артефактов независимых репозиториев WealthLedger.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
### Requirement: Dependency advisory получает проверяемое решение
|
|
||||||
Для каждого audit-derived dependency advisory система SHALL хранить
|
|
||||||
проверяемую запись с Audit ID, advisory identifier, затронутой package path и
|
|
||||||
installed version, оценкой применимости к runtime или build surface и одним из
|
|
||||||
результатов: исправлено, принято или отложено. Принятое или отложенное решение
|
|
||||||
MUST содержать rationale и review trigger; исправленное решение MUST содержать
|
|
||||||
выбранный поддерживаемый upgrade path и evidence воспроизводимой проверки.
|
|
||||||
|
|
||||||
#### Scenario: Advisory подтверждён в dependency graph
|
|
||||||
- **WHEN** проверка находит advisory в direct или transitive package path
|
|
||||||
- **THEN** remediation record позволяет определить его reachability,
|
|
||||||
выбранный результат и evidence без применения массового автоматического
|
|
||||||
обновления зависимостей
|
|
||||||
|
|
||||||
#### Scenario: Advisory не применим к delivered architecture
|
|
||||||
- **WHEN** assessment устанавливает, что advisory не достижим из runtime или
|
|
||||||
build surface WealthLedger
|
|
||||||
- **THEN** record фиксирует принятие риска, конкретное rationale и условие
|
|
||||||
повторной оценки вместо ошибочного заявления об исправлении
|
|
||||||
|
|
||||||
### Requirement: Рабочая frontend configuration не является versioned input
|
|
||||||
Frontend SHALL поставлять versioned `.env.example`, достаточный для создания
|
|
||||||
локального `.env`, но MUST NOT хранить рабочий `.env` или другой локальный
|
|
||||||
`.env*` файл в source control. Ignore policy MUST исключать локальные frontend
|
|
||||||
configuration files, сохраняя явно разрешённый example template.
|
|
||||||
|
|
||||||
#### Scenario: Участник создаёт local frontend configuration
|
|
||||||
- **WHEN** участник копирует `.env.example` в `.env` для запуска frontend
|
|
||||||
- **THEN** локальный файл доступен runtime, но не появляется среди tracked
|
|
||||||
файлов Git
|
|
||||||
|
|
||||||
### Requirement: Runtime SQLite-данные не являются versioned artifact
|
|
||||||
Backend MUST NOT хранить SQLite database files, созданные runtime или local
|
|
||||||
development, в source control. Ignore policy SHALL покрывать поддерживаемые
|
|
||||||
repository runtime locations, а локальные test/database workflows MUST
|
|
||||||
направлять временные базы вне source tree и не считать их частью
|
|
||||||
коммитируемого результата.
|
|
||||||
|
|
||||||
#### Scenario: Локальный backend создаёт runtime SQLite database
|
|
||||||
- **WHEN** backend workflow создаёт SQLite file для development или test run
|
|
||||||
- **THEN** database находится вне versioned source inputs либо исключена
|
|
||||||
ignore policy и не появляется среди tracked файлов Git
|
|
||||||
|
|
||||||
#### Scenario: В репозитории обнаружен устаревший runtime DB artifact
|
|
||||||
- **WHEN** tracked SQLite database больше не требуется как fixture или source
|
|
||||||
input
|
|
||||||
- **THEN** change удаляет его из source control и сохраняет воспроизводимый
|
|
||||||
local bootstrap через configuration template и documented workflow
|
|
||||||