## Контекст Мотивация изложена в `proposal.md`, а поведенческий contract — в delta specs. Backend документирует `200` через OpenAPI decorators, но Nest использует стандартный `201` для трёх auth `POST` handlers, поскольку их runtime status не задан явно. Runtime OpenAPI verifier сравнивает два документа, поэтому не может обнаружить это расхождение HTTP responses. Во frontend Accounts и Account view models выбирают блокирующий loading/error state до проверки cached query data. У auth provider два пути refresh: cold start напрямую вызывает API без `catch`, а общий refresh может отклонить Promise при повторе защищённого запроса. ## Цели и исключения **Цели:** - Согласовать фактические auth success responses, OpenAPI, snapshot и generated types на `200` с детерминированным regression gate без Prisma или базы данных. - Отображать существующие данные Accounts и Portfolio во время refetch и после его ошибки с доступным локализованным warning и retry action. - Дать cold start и повтору защищённого запроса единый non-throwing результат refresh, сохранив текущие serialization и защиту routes. - Фиксировать active remediation и обновлять feature/development документацию только фактически поставленным поведением. **Исключения:** - Исправлять Prisma migration/e2e infrastructure или создавать workspace-wide verifier, отложенный как WL-P2-05 и WL-P2-13. - Менять refresh-cookie attributes, token lifetime, session rotation, unauthorised-error codes, auth routes, cache TTL, refetch triggers или backend Portfolio fallback policy. - Распространять Client Cached Snapshot на постраничные operations/events, чьи cursor и filters могут определять иной result set. ## Решения ### Явно установить `200` для трёх auth handlers успешного ответа Handlers register, login и refresh получают явный HTTP `200`, сохраняя существующие `ApiOkResponse` и payload/cookie code. Frontend artifacts остаются сгенерированными из backend document: запускается штатный sync workflow, а artifact коммитится только если этот workflow создаёт изменение; ручное редактирование generated schema запрещено. Небольшой независимый от БД backend test проверяет status metadata каждого handler. Он защищает decorator, управляющий реальным Nest output, пока Prisma-backed e2e gate остаётся deferred. Существующие e2e assertions меняются с `201` на `200`, но не являются terminal evidence до восстановления Prisma bootstrap. Отклонённые альтернативы: неявный `201` потребовал бы большего перехода snapshot/types и противоречил бы согласованному единообразному contract; опора только на runtime OpenAPI comparison повторила бы исходную blind spot. ### Определять представление refetch по наличию данных, а не `isFetching` или `isError` Accounts и Account view models сначала определяют наличие Client Cached Snapshot. Без данных они сохраняют текущие loading, error и empty views. При наличии данных они возвращают loaded/empty presentation с опциональной информацией об обновлении и его ошибке. Page components сначала отображают данные, добавляют неблокирующий progress indicator во время fetch и передают локализованное warning/retry action в loaded presentation после ошибки. Account view сохраняет backend warning `Portfolio.isStale` отдельно от client warning об ошибке refresh. Оба могут отображаться, когда независимо истинны. Новая терминология документируется в `CONTEXT.md`; это не новое API field и не интерпретация server freshness. Отклонённые альтернативы: полный error/loading view после refetch скрывает уже полезные финансовые данные; применение правила к operations/events могло бы показать прошлую cursor/filter page как запрошенный результат. ### Сделать общий refresh возвращающим `false` при любом неуспешном исходе Auth provider централизует успешное применение session и локальную очистку session. Single-flight refresh function перехватывает transport rejection API, а также no-data/HTTP failures, очищает token, profile и React Query cache и возвращает `false`; она всегда освобождает in-flight Promise. Cold start использует эту общую function и устанавливает `ready` в `finally`. `authenticatedFetch` сохраняет existing one-retry behavior: при `false` он возвращает исходный `401` после очистки, позволяя protected-route state перенаправить на login. Отклонённые альтернативы: перехват только mount effect оставляет 401 retry path способным отклонить Promise; добавление третьего startup error state меняет согласованный anonymous/login recovery flow. ## Риски и компромиссы - [Metadata test не является HTTP e2e test] → WL-P2-05 остаётся deferred, существующие e2e expectations обновляются, а реальное HTTP coverage станет обязательным после выполнения Prisma trigger. - [Ошибка refresh утрачивает in-memory session] → после cold start браузер не имеет действительного access token; очистка state предотвращает неоднозначный protected UI и следует существующему 401 recovery behavior. - [Client warning и backend stale warning могут сосуществовать] → каждому назначается отдельное localized message и проверяется их независимый render. - [Generated sync может затронуть frontend artifacts] → он запускается явно только после backend contract change, а итоговый diff проверяется до принятия. ## План изменений 1. Сначала добавить regression tests, затем сделать backend status явным и обновить существующие e2e assertions, не заявляя, что deferred e2e gate прошёл. 2. Обновить OpenAPI artifacts через штатную sync command, проверить согласованность runtime document и generated client и оставить только намеренный итоговый diff. 3. Добавить observable frontend tests для состояний refetch cached data и ошибок refresh, затем отрефакторить view models, pages, localized copy и auth provider до их прохождения. 4. Обновить feature docs и remediation registry, выполнить применимые non-mutating gates и OpenSpec verification до archive. Rollback затрагивает только код: отмена затронутых commits восстанавливает предыдущий status/UX; data migration, dependency change и очистка persisted state не нужны.