spec: plan account concentration tab (WealthLedger/main#48)

This commit is contained in:
2026-10-31 13:42:27 +03:00
parent b9ec11f5ba
commit e3cc9c8d25
23 changed files with 3441 additions and 0 deletions
@@ -0,0 +1,68 @@
# Test Cases — meta (sector/issuer enrichment, Snapshot-инварианты)
Cases добавляют данные/порядок событий/oracle сверх Scenarios Delta Specs
`portfolio-view` (PVΔ). Требуют управляемое время обхода (час) и управляемые
ответы T-Bank (integration, configured HTTP tests, моки по proto).
### TC-META-002 Token-отказ при получении сектора/бренда не маскируется fallback
- **Verifies:** `portfolio-view` — `Свежесть и fallback полного Portfolio Snapshot` (исключение token) / Scenario «Отказ token при получении бренда»
- **Risk / Priority:** высокий / high — invalid token, замаскированный старым Snapshot, скрывает от владельца потерю доступа
- **Preconditions:** сохранённый полный Snapshot старше 60 минут; подключение с invalid token; GET выполняется после обхода
- **Test Data:** мок T-Bank: GetPortfolio/GetPositions — PERMISSION_DENIED; типизированный инструмент (sector) — UNAUTHENTICATED
- **Steps:**
1. Дождаться обхода (или вызвать принудительно в тесте).
2. GET Portfolio пользователем.
3. Повторить с отказом только на `GetAssetBy` (бренд), финансы успешны.
- **Expected Results:** шаг 2 — `400` Problem Details, code `INVALID_TBANK_TOKEN`, fallback Snapshot не возвращается. Шаг 3 — тот же `400`/`INVALID_TBANK_TOKEN`: отказ token на любом звене сектора/бренда приравнен к отказу обхода (требование «Свежесть и fallback полного Portfolio Snapshot»), хотя финансы могли быть получены.
- **Automation Candidate:** yes (integration)
### TC-META-003 Суточный цикл обновления сектора
- **Verifies:** `portfolio-view` — `Обновление сектора и эмитента` / Scenario «Обход через 24 часа» + 24h-отсчёт таблицы `Результат получения сектора и эмитента`
- **Risk / Priority:** высокий / high — ошибка отсчёта даёт вечное старое значение или вечный ре-fetch
- **Preconditions:** управляемое время обхода (шаг «час»); позиция P; T-Bank меняет сектор P на `financial` сразу после T0
- **Steps (линейная шкала):**
1. T0: обход — успех, `sector: energy` (отсчёт с T0).
2. T0+1h … T0+23h: обходы — обращений за сектором нет.
3. T0+24h: обход запрашивает сектор, T-Bank отвечает UNAVAILABLE.
4. T0+25h: обход запрашивает сектор (ошибка не сбросила отсчёт), T-Bank отвечает `financial`.
5. T0+26h … T0+48h: обходы.
6. T0+49h: обход.
- **Expected Results:**
- Шаги 2: `sector: energy`.
- Шаг 3: `sector: energy` (последнее известное), отсчёт не сброшен (идёт от T0) — поэтому шаг 4 снова обращается.
- Шаг 4: `sector: financial`, отсчёт с T0+25h.
- Шаги 5: `sector: financial`, обращений нет (T0+25h+24h = T0+49h).
- Шаг 6: первое обращение после успеха — сектор запрошен.
- **Automation Candidate:** yes (integration, управляемое время)
### TC-META-004 Четыре исхода получения: поле и отсчёт 24 часов
- **Verifies:** `portfolio-view` — `Результат получения сектора и эмитента` (каждая строка таблицы) / Scenarios «Ответ без значения заменяет известное значение», «"Не найдено" перезапускает отсчёт», «Ответ о другом инструменте», «Недоступность T-Bank сохраняет известное значение», «Значение ещё не известно»
- **Risk / Priority:** высокий / high — таблица — ядро нового контракта; классификация NOT_FOUND решает поведение
- **Preconditions:** 4 позиции P1–P4, у каждой известен `sector: energy` (успех в T0); управляемое время; моки по proto
- **Test Data:** P1 → ответ со значением `it`; P2 → NOT_FOUND (и вариант «пустой объект без sector» отдельным прогоном); P3 → ответ с чужим `asset_uid`/UID; P4 → UNAVAILABLE (timeout)
- **Steps:**
1. В T0+24h провести обход со всеми четырьмя моками.
2. GET Portfolio, прочитать `sector` P1–P4.
3. В T0+25h: P2 теперь отвечает значением `financial`; P3 и P4 — тоже успех `financial`.
4. Обход T0+25h; GET; прочитать `sector`.
5. Обход T0+48h: P1 и P2 — успех `financial`; P3 и P4 — `energy`.
- **Expected Results:**
- Шаг 2: P1 `it` (отсчёт сброшен на T0+24h), P2 `null` (сброшен на T0+24h), P3 `energy` (не сброшен, retry), P4 `energy` (не сброшен, retry).
- Шаг 4: P2 — по правилу `Обновление сектора и эмитента` значение появляется только при обходе ≥24 ч после «не найдено» (T0+24h), поэтому в T0+25h остаётся `null`; P3 и P4 — `financial` (получено, сброс отсчёта на T0+25h).
- Шаг 5: P1 — запрошен снова (отсчёт сброшен в T0+24h, T0+48h ≥ 24 ч), становится `financial`; P2 — запрошен (≥24 ч от «не найдено»), становится `financial`; P3 и P4 — не запрашиваются (последний успех T0+25h, T0+48h < T0+49h), `sector: financial` остаётся.
- **Automation Candidate:** yes (integration; P2-ветка — минимальное воспроизведение перезапуска отсчёта)
### TC-META-005 Смена и удаление подключения: sector/brand не протекают
- **Verifies:** `portfolio-view` — `Свежесть и fallback` («прежние личные datasets недоступны…»), failure-model F11
- **Risk / Priority:** высокий / high — утечка данных между подключениями
- **Preconditions:** пользователь, подключения K1 (счёт A, позиции с sector/brand) и K2 (счёт B)
- **Steps:**
1. Заменить K1 на новое подключение K1' (новый token, те же счёта): GET счёта A.
2. Удалить K1': GET счёта A.
3. Поздняя публикация обхода K1 (симуляция задержанной попытки) — проверить счёт A и B.
- **Expected Results:** шаг 1 — 404/409/400 по контракту замены, прежние datasets K1 недоступны; sector/brand позиции не выдаются до первого успешного обхода K1'. Шаг 2 — 404. Шаг 3 — публикация отклонена (`id`/`attemptId`/`running`), в Portfolio K2 и нового K1' данные K1 не появляются.
- **Automation Candidate:** yes (integration)