# 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.