spec: address hourly-sync review findings (WealthLedger/backend#56)
Conventional commits / commits (pull_request) Successful in 14s
Specs security / security (pull_request) Successful in 9s
Specs verify / verify (pull_request) Successful in 11s

This commit is contained in:
2026-10-12 22:19:03 +03:00
parent 14174a7bb3
commit 77b211186c
3 changed files with 22 additions and 1 deletions
@@ -91,7 +91,14 @@ QA Analysis.
3. **Ограниченное ожидание на каждый шаг.** `settledWorks` получает per-id
deadline: константа `WORK_WAIT_BOUND_MS = 15 * 60 * 1000`; истёкший id
возвращается как проблемный шаг с причиной `DEADLINE`. Управляемые часы в
возвращается как проблемный шаг с причиной `DEADLINE`. Тем же bound покрыты
и ожидания walk до появления durable-строк шагов (review-замечание,
follow-up WealthLedger/backend#78): `membership.request`/`member.done`,
`access.local` и dispatch `portfolio`/`operations`/`events.refresh` гоняются
с `WORK_WAIT_BOUND_MS` через race; истечение трактуется как проблемная
секция (как failed dispatch), для `access.local` — как закрытие
`INTERRUPTED`. Вызов не отменяется; поздняя durable-строка fenced по
`attemptId`, как любая поздняя публикация. Управляемые часы в
тестах — jest fake timers, инъекция clock в production-код не вводится.
RPC не отменяется; поздний результат шага сохраняется его собственной
строкой — учтён ли он в итоге, решает fence и момент фиксации.
@@ -14,6 +14,9 @@ Durable docs update нужен ограниченно: наблюдаемая с
| update | `docs/architecture/cross-cutting/data-freshness.md` | cross-cutting | Рядом со словарём `lastAttempt` (`none`, `running`, `succeeded`, `partial`, `failed`): итог попытки выводится из фактических результатов её шагов; попытка, не завершившая обязательный шаг, не обозначается полным успехом; ожидание шага ограничено, зависший шаг учитывается как проблемный; попытка, потерявшая выполнение (сбой сохранения, остановка процесса), закрывается частичным успехом либо неуспехом и не блокирует следующий обход дольше обычного срока | System Analysis — Data and State Semantics, Error and Recovery Semantics; Design 1–5 | Страница не противоречит canonical spec `hourly-investment-sync` и фактическому поведению `meta` |
| update | `docs/integrations/tbank.md` | integration | В разделе «Состояние и ошибки»: диагностические причины жизненного цикла попытки (`INTERRUPTED` — прервана до нормального завершения, `DEADLINE` — истечение ожидания шага) — внутренняя диагностика, не ошибки T-Bank; в hourly-read наружу не попадают, начатые обращения к T-Bank не отменяются | System Analysis — Observability Semantics; Design 3, 6 | Раздел различает ошибки подключения/external-коды и внутренние причины жизненного цикла |
PR реализации: WealthLedger/docs#37 (open) — обе страницы обновлены, diff
соответствует таблице выше (задачи 6.1 и 6.2 верифицируемы по нему).
## Diagram Promotion
Не переносить. Sequence-диаграммы (`hourly-attempt-terminal-barrier.mmd`,
@@ -42,6 +42,17 @@
- **Verification:** SQLite-тест перезапуска процесса: брошенная попытка закрыта `partial`/`failed` с сохранёнными результатами шагов, новый обход не ранее следующего часового срока, перекрытия нет
- **Depends on:** 1.1, 1.2
- [x] 2.4 [backend] ожидания walk до durable-строк шагов
(`membership.request`/`member.done`, `access.local`, dispatch
`portfolio`/`operations`/`events.refresh`, post-wait `events.get`)
ограничены тем же `WORK_WAIT_BOUND_MS` через race; истечение — проблемная
секция либо `INTERRUPTED`-закрытие без отмены вызова
(WealthLedger/backend#78)
- **Covers:** `hourly-investment-sync` — «Каждая попытка обхода достигает итога в ограниченное время»
- **Source:** Design — Decision 3; review specs#33 (CRITICAL)
- **Verification:** SQLite-тесты с никогда не завершающимися dispatch/membership/`done`/`get`: попытка терминальна в ограниченное время, поздние вызовы не отменяются
- **Depends on:** 2.1
## 3. Финализаторы шагов
- [x] 3.1 [backend] внешний catch финализаторов шагов (enrichment, operations