Files
specs/openspec/changes/harden-hourly-sync-lifecycle/system-analysis/analysis.md
T
ksv741 14174a7bb3
Conventional commits / commits (pull_request) Successful in 12s
Specs security / security (pull_request) Successful in 7s
Specs verify / verify (pull_request) Successful in 10s
spec: add harden-hourly-sync-lifecycle change (WealthLedger/backend#56)
2026-10-12 20:28:58 +03:00

13 KiB

System Analysis

Requirement Coverage

Requirement / Scenario Flow Contract / Semantics
Последний результат обхода… — Сбой после частичного обновления hourly-attempt-terminal-barrier.mmd Outcome derivation, terminal barrier
Последний результат обхода… — Сбой до первого обновления hourly-attempt-terminal-barrier.mmd Outcome derivation
Последний результат обхода… — Частичный успех hourly-attempt-terminal-barrier.mmd Step results preserved
Каждая попытка обхода достигает итога в ограниченное время — Шаг не завершается hourly-bounded-wait.mmd Bounded wait per required step
Каждая попытка обхода достигает итога в ограниченное время — Наблюдение не ждёт без ограничения hourly-bounded-wait.mmd Bounded terminal outcome
Восстановление после сбоя сохранения… — Потерянное закрытие попытки hourly-recovery.mmd Recovery of lost settle
Восстановление после сбоя сохранения… — Перезапуск процесса hourly-recovery.mmd Recovery of abandoned attempt
Устаревшая публикация… — Поздняя публикация после появления преемника hourly-recovery.mmd Successor fencing
Устаревшая публикация… — Поздняя публикация до фиксации итога hourly-bounded-wait.mmd Late publication counts before outcome is recorded

Systems and Responsibilities

  • Hourly walk coordinator (backend): резервирует попытку часового обхода для текущего подключения, запускает обязательные шаги, ждёт их терминального результата с ограничением, выводит итог попытки и закрывает её.
  • Durable attempt status (SQLite): единственная durable-запись попытки (состояние, диагностическая причина, результаты шагов) и источник итога для наблюдения и восстановления.
  • Child step owners: шаги membership, Portfolio, операций и будущих событий публикуют свой полный результат в durable-хранилище и обозначают свой терминальный результат; финализатор шага обязан фиксировать результат даже при ошибке.
  • T-Bank и публичные источники: внешние данные; начатые обращения не отменяются по внутреннему ограничению ожидания.
  • Resource GET observer: читает сохранённые данные и meta с состоянием последней попытки; наблюдение не запускает обход.

Interaction Flows

  • sequences/hourly-attempt-terminal-barrier.mmd — попытка, шаги, terminal barrier и вывод итога из фактических результатов шагов.
  • sequences/hourly-bounded-wait.mmd — ограничение ожидания шага, закрытие попытки по его истечении и учёт позднего результата до появления преемника.
  • sequences/hourly-recovery.mmd — восстановление после сбоя сохранения и после перезапуска процесса, отклонение устаревшей публикации.

Contracts

  • Новых и изменённых межсистемных HTTP/event contracts нет. Публичный словарь состояний последней попытки (выполнение, полный успех, частичный успех, неуспех) и форма { data, meta } не меняются.
  • Машинно-читаемый target contract в system-analysis/contracts/ не создаётся: изменения ограничены уточнением значений внутри существующих полей.
  • Диагностическое поле причины остаётся открытым строковым полем; значения причин прерывания (INTERRUPTED — ошибка, сбой сохранения, остановка процесса; DEADLINE — истечение ограничения ожидания шага) дополняют существующие коды ошибок шагов и не требуют изменения формы ответа.
  • Compatibility check до закрытия change: backend-generated OpenAPI остаётся семантически совместимым с текущим контрактом (ожидаются только дополнительные значения открытого строкового поля диагностики).

Data and State Semantics

  • Попытка: running → терминальный итог (succeeded | partial | failed). Попытка, не завершившая обязательный шаг, не может получить succeeded.
  • Terminal barrier: итог попытки выводится только после того, как каждый обязательный шаг достиг терминального результата либо учтён как истёкший по ограничению ожидания. Итог не вычисляется по неполному списку шагов.
  • Вывод итога: succeeded — только когда все обязательные шаги успешны и координатор сам зафиксировал закрытие попытки; partial — успешны некоторые шаги; failed — не успешен ни один. Успешные результаты шагов сохраняются независимо от итога.
  • Причина прерывания: попытка, закрытая до нормального завершения всех шагов, сохраняет причину прерывания в диагностическом поле и не превышает partial.
  • Internal coordinator decisions first, not-due, running, restart, partial: внутренние метки решения о запуске и проверки итога после terminal barrier; в HTTP contract не входят и публично не наблюдаемы.
  • Шаги: каждый шаг владеет своей durable-строкой результата; строка шага устаревшей попытки помечается устаревшей относительно преемника.

Error and Recovery Semantics

  • Сбой шага (внешняя ошибка T-Bank): шаг фиксирует терминальный неуспех со своим кодом ошибки; остальные шаги продолжаются; итог — partial или failed.
  • Сбой сохранения (завершение шага, публикация результата, закрытие попытки): ошибка не подавляется молча в durable-состоянии; попытка, оставшаяся running, закрывается восстановлением по фактическим результатам шагов.
  • Остановка процесса: начатая попытка остаётся running в SQLite; следующий запуск процесса закрывает её как прерванную (partial или failed с сохранёнными результатами шагов) и не создаёт перекрывающийся обход.
  • Ограничение ожидания: истечение ограничивает только ожидание шага; уже начатое обращение к T-Bank не отменяется. Его поздний результат сохраняется и учитывается при выводе итога своей попытки, если итог ещё не зафиксирован, и отклоняется как устаревший после появления преемника.
  • Повтор: неуспешная попытка не повторяется ранее следующего часового срока, отсчитанного от начала этой попытки; восстановление не сокращает и не продлевает этот срок.
  • Overlapping: следующая попытка не резервируется, пока предыдущая не терминальна; восстановление обязано сначала закрыть предыдущую.

Observability Semantics

  • Наблюдаемый итог попытки и безопасный перечень проблемных счетов/разделов — существующее обязательство; значения итога не расширяются.
  • Семантические коды причин: INTERRUPTED — попытка прервана до нормального завершения (ошибка, сбой сохранения, остановка процесса); DEADLINE — шаг не завершился в ограничение ожидания. Коды сохраняются в диагностическом поле попытки и/или шага и дополняют коды ошибок шагов без изменения формы meta.
  • SDK/exporter/logger — вне границ этого изменения; используется существующий структурный лог backend.

Security and NFR at System Boundaries

  • Граница наблюдения попытки остаётся границей текущего подключения: результат прежней границы не раскрывается (существующее обязательство).
  • Ограниченное время достижения итога попытки — наблюдаемое обязательство надёжности: ожидание шага и ожидание наблюдателя ограничены.
  • Новых trust boundaries, authn/authz требований нет.

Compatibility / Migration

  • Схема данных и HTTP contract не меняются; миграция не требуется.
  • Уже застрявшие строки попыток в состоянии выполнения закрываются первым проходом восстановления по правилам этого изменения: итог из фактических результатов шагов, причина прерывания, без полного успеха. Это ожидаемое разовое приведение legacy-состояния к диагностируемому виду.
  • Совместимость с одно-процессной топологией сохраняется; межпроцессный lease не требуется.

Durable Documentation Candidates

  • docs/integrations/tbank.md (раздел «Состояние и ошибки»): итог часовой попытки, причины прерывания и правило ограниченного ожидания как часть наблюдаемого состояния интеграции.
  • docs/architecture/containers.md (раздел «Сохранение и восстановление данных»): восстановление попытки после сбоя сохранения и после перезапуска процесса как durable-свойство системы.
  • Итоговое решение о переносе принимает docs-impact.

Open Questions

  • Нет блокирующих вопросов. Частота проявления механизма в production остаётся не установленной и не влияет на contract.