Files
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

141 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.