Пустой счёт и страница дохода показывают серверное время и результат последней часовой попытки через существующий SourceSyncStatus. Список access-loss кодов собран в одном предикате.
frontend-user-feedback и frontend-data-resilience запрещают на этих экранах технические предупреждения о чтении, кнопки повтора и ручное обновление. Поэтому spec побеждает:
Делаю только source metadata (время успеха, устаревание, исход последней попытки) там, где её терял код.
Не делаю (AC 2 и часть AC 3 из Issue): cached-503 warning и локальный GET retry; это противоречит specs. Они остаются открытыми и описаны в комментарии к Issue.
Scope: только пробелы метаданных. Search, секции stock/bond и previews вне этого PR.
Access-loss: 3 кода (INVALID_TBANK_TOKEN, NOT_FOUND, TBANK_NOT_CONNECTED) + отдельный UNAUTHORIZED. «Четвёртого» кода в OpenAPI нет. Подмножество Accounts (без NOT_FOUND) не расширялось.
Changes
Account: ветка empty теперь несёт source (VM → AccountPage → AccountPageEmpty → SourceSyncStatus). source вынесен в общий AccountPageContent.
Income: VM отдаёт source: analytics.meta, loaded view рендерит SourceSyncStatus. Время берётся из meta.lastSuccessfulAt, не из часов браузера.
shared/api/problem-details.ts: isBrokerageAccessLoss(code). Использован в client.ts (isPermanentCode = предикат + UNAUTHORIZED), resource-query.ts (invalidate) и AccountPage.vm.ts; локальная копия удалена. Действия по страницам не объединялись.
Тесты: тихие проверки заменены на positive-assertions. Негативные селекторы старого label «Данные получены» (которого уже нет) заменены на проверку видимого «Данные на …» после реального settle запроса.
Verification
Новые тесты падали на старом коде (4 из них), на фиксе проходят: account empty, income full/empty, предикат кодов.
Не проверено: реальный backend и браузер (только RTL/MSW), a11y вручную, search/detail sections, previews.
Breaking Changes (если есть)
Нет. API-контракт не менялся. UpcomingEventsDto.window из backend#55 отсутствует в snapshot фронта: регенерация типов вне этого PR (отдельная задача T27).
## Summary
Пустой счёт и страница дохода показывают серверное время и результат последней часовой попытки через существующий `SourceSyncStatus`. Список access-loss кодов собран в одном предикате.
## Linked Issue
Refs WealthLedger/frontend#55 (audit 2026-10-11: FE-001, FE-002, DRY-004, TQ-004, RISK-005, TA-F05).
## Решения владельца (расхождение Issue и specs)
`frontend-user-feedback` и `frontend-data-resilience` запрещают на этих экранах технические предупреждения о чтении, кнопки повтора и ручное обновление. Поэтому **spec побеждает**:
- Делаю только source metadata (время успеха, устаревание, исход последней попытки) там, где её терял код.
- **Не делаю** (AC 2 и часть AC 3 из Issue): cached-503 warning и локальный GET retry; это противоречит specs. Они остаются открытыми и описаны в комментарии к Issue.
- Scope: только пробелы метаданных. Search, секции stock/bond и previews вне этого PR.
- Access-loss: 3 кода (`INVALID_TBANK_TOKEN`, `NOT_FOUND`, `TBANK_NOT_CONNECTED`) + отдельный `UNAUTHORIZED`. «Четвёртого» кода в OpenAPI нет. Подмножество Accounts (без `NOT_FOUND`) не расширялось.
## Changes
- Account: ветка `empty` теперь несёт `source` (VM → `AccountPage` → `AccountPageEmpty` → `SourceSyncStatus`). `source` вынесен в общий `AccountPageContent`.
- Income: VM отдаёт `source: analytics.meta`, loaded view рендерит `SourceSyncStatus`. Время берётся из `meta.lastSuccessfulAt`, не из часов браузера.
- `shared/api/problem-details.ts`: `isBrokerageAccessLoss(code)`. Использован в `client.ts` (`isPermanentCode` = предикат + `UNAUTHORIZED`), `resource-query.ts` (invalidate) и `AccountPage.vm.ts`; локальная копия удалена. Действия по страницам не объединялись.
- Тесты: тихие проверки заменены на positive-assertions. Негативные селекторы старого label «Данные получены» (которого уже нет) заменены на проверку видимого «Данные на …» после реального settle запроса.
## Verification
- Новые тесты падали на старом коде (4 из них), на фиксе проходят: account empty, income full/empty, предикат кодов.
- `npm run verify`: `openapi:check`, `tsc -b`, eslint `--max-warnings=0`, test:lint, vitest coverage (74 файла / 553 теста), knip, depcruise ×2, build, storybook build — exit 0.
- Не проверено: реальный backend и браузер (только RTL/MSW), a11y вручную, search/detail sections, previews.
## Breaking Changes (если есть)
Нет. API-контракт не менялся. `UpcomingEventsDto.window` из backend#55 отсутствует в snapshot фронта: регенерация типов вне этого PR (отдельная задача T27).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Пустой счёт и страница дохода показывают серверное время и результат последней часовой попытки через существующий
SourceSyncStatus. Список access-loss кодов собран в одном предикате.Linked Issue
Refs WealthLedger/frontend#55 (audit 2026-10-11: FE-001, FE-002, DRY-004, TQ-004, RISK-005, TA-F05).
Решения владельца (расхождение Issue и specs)
frontend-user-feedbackиfrontend-data-resilienceзапрещают на этих экранах технические предупреждения о чтении, кнопки повтора и ручное обновление. Поэтому spec побеждает:INVALID_TBANK_TOKEN,NOT_FOUND,TBANK_NOT_CONNECTED) + отдельныйUNAUTHORIZED. «Четвёртого» кода в OpenAPI нет. Подмножество Accounts (безNOT_FOUND) не расширялось.Changes
emptyтеперь несётsource(VM →AccountPage→AccountPageEmpty→SourceSyncStatus).sourceвынесен в общийAccountPageContent.source: analytics.meta, loaded view рендеритSourceSyncStatus. Время берётся изmeta.lastSuccessfulAt, не из часов браузера.shared/api/problem-details.ts:isBrokerageAccessLoss(code). Использован вclient.ts(isPermanentCode= предикат +UNAUTHORIZED),resource-query.ts(invalidate) иAccountPage.vm.ts; локальная копия удалена. Действия по страницам не объединялись.Verification
npm run verify:openapi:check,tsc -b, eslint--max-warnings=0, test:lint, vitest coverage (74 файла / 553 теста), knip, depcruise ×2, build, storybook build — exit 0.Breaking Changes (если есть)
Нет. API-контракт не менялся.
UpcomingEventsDto.windowиз backend#55 отсутствует в snapshot фронта: регенерация типов вне этого PR (отдельная задача T27).