Files
specs/openspec/changes/archive/2026-10-12-harden-hourly-sync-lifecycle/proposal.md
T
ksv741 fe295aa73a
Conventional commits / commits (pull_request) Successful in 10s
Specs security / security (pull_request) Successful in 8s
Specs verify / verify (pull_request) Successful in 9s
Specs security / security (push) Successful in 7s
Specs verify / verify (push) Successful in 11s
spec: archive harden-hourly-sync-lifecycle change (WealthLedger/backend#56)
2026-10-12 22:52:44 +03:00

8.9 KiB

Proposal

Why

Почасовая синхронизация T-Bank может завершиться в неконсистентном состоянии после ошибки сохранения: незавершённая попытка записывается как полный успех, ошибка финализации либо подавленная ошибка закрытия оставляет попытку в состоянии выполнения навсегда, а локальная reservation не позволяет запустить следующий обход в том же процессе. Пользователь видит ложный успех и перестаёт получать обновления до перезапуска backend, а неудавшееся ожидание дочерних шагов может ждать без ограничения. Механизм подтверждён статически (BE-002, BE-015, RISK-001, RISK-002, TQ-003); частота проявления в production пока не установлена.

What Changes

  • Итог попытки определяется фактическим результатом каждого обязательного шага: невыполненный шаг даёт частичный успех либо неуспех, но не полный успех, а уже полученные успехи отдельных счетов и разделов сохраняются.
  • Прерванная попытка (ошибка, сбой сохранения, остановка процесса, истечение ожидания) обозначается частичным успехом либо неуспехом и не получает нового публичного состояния; причина прерывания фиксируется существующим диагностическим полём.
  • Попытка достигает итога в ограниченное время: ожидание дочернего шага ограничено, а зависшая попытка не остаётся в выполнении бесконечно.
  • Состояние в SQLite восстанавливается после сбоя сохранения: брошенная попытка закрывается диагностируемым итогом, ожидание завершается, следующая допустимая попытка может стартовать без перезапуска процесса.
  • Восстановление не создаёт перекрытия обходов и не принимает устаревшие результаты: поздняя публикация относительно актуального преемника отклоняется.

Scope

In Scope

  • Итоговый статус попытки часового обхода и обработка ошибок в дочерних финализаторах.
  • Ограниченное ожидание дочерних шагов и восстановление после ошибок завершения шага, публикации результата и закрытия попытки.
  • Защита от перекрытия обходов и от поздней публикации устаревших данных при восстановлении.
  • Контролируемая остановка и перезапуск процесса и их влияние на незавершённую попытку, подтверждённые тестами.
  • Наблюдаемый результат попытки: время начала, состояние, безопасный перечень проблемных счетов и разделов.

Out of Scope / Non-Goals

  • Распределённая очередь, lease, поддержка нескольких реплик и изменение топологии deployment.
  • Удаление данных.
  • Ослабление существующих ограничений CAS для попытки, ревизии подключения и источника данных.
  • Новый публичный статус попытки и изменения HTTP contract.
  • Новый параллельный scheduler или замена владельцев строк синхронизации.
  • Проверка часовой cadence и cleanup workflow — независимые задачи.

Capabilities

New Capabilities

  • Нет.

Modified Capabilities

  • hourly-investment-sync: итог попытки из фактических результатов шагов, ограниченное ожидание шага, диагностируемое закрытие брошенной попытки, отсутствие перекрытий и устаревшей публикации.

Impact

  • Пользователь: достоверный статус последнего обхода вместо ложного успеха и бесконечного «выполняется» после сбоя сохранения; обновления продолжаются без перезапуска процесса.
  • Backend: координатор часового обхода, дочерние финализаторы обновления данных и reservation попытки в SQLite.
  • Frontend: не затрагивается — наблюдаемый словарь состояний и форма ответов не меняются.
  • Внешняя система T-Bank: contract не меняется; начатые запросы к T-Bank могут завершаться поздно и должны корректно отклоняться как устаревшие.
  • Процессы: диагностика причин прерывания попыток и восстановление после ошибок сохранения.

Success Criteria

  • Попытка с невыполненным обязательным шагом никогда не наблюдается как полный успех; частичные успехи счетов и разделов остаются видимыми.
  • После однократной ошибки завершения шага, публикации результата либо закрытия попытки и последующего восстановления ожидание завершается, а следующая допустимая попытка стартует.
  • Устаревшая попытка наблюдается относительно актуального преемника; поздняя публикация старого процесса отклоняется и не меняет данные.
  • Координатор различает состояния first, not-due, running, restart и partial; итог проверяется после terminal barrier.
  • Сценарий остановки и перезапуска доказан тестами: нет бесконечного ожидания, после остановки новые попытки не создаются.
  • Сохранены существующие наборы проверок auth/money/publication, полный backend verify на финальном изменении зелёный.

Assumptions / Dependencies

  • Топология остаётся одно-процессной; межпроцессный lease и мультреплики не требуются.
  • Истечение ожидания не отменяет уже начатый запрос к T-Bank; защита опирается на существующие ограничения CAS и правило срока следующего обхода.
  • Причина прерывания фиксируется существующим диагностическим полём, поэтому HTTP contract и публичный словарь состояний не меняются; упомянутое в задаче состояние interrupted реализуется как частичный успех либо неуспех.
  • Graceful drain добавляется только если тест контролируемой остановки докажет такую необходимость.
  • Правило устаревшей публикации относится к итогу попытки и данным её шагов; существующие требования tbank-data-sync уже запрещают выдавать неполный или продолжающийся результат за полный, поэтому их изменение не планируется.