Files
dzentra_bot/docs/migrations/build_060_29.md

240 lines
12 KiB
Markdown
Raw 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.
# Build 060.29 — Market Data Access and Replay
**Engineering Migration Report**
---
## Контроль документа
| Свойство | Значение |
|---|---|
| Build | 060.29 |
| Статус | Completed |
| Подсистема | Market Data / Historical Access and Replay |
| Компонент | Canonical History and Deterministic Replay |
| Дата завершения | 2026-08-02 |
| Версия | 1.0 |
---
## Связанные документы
- [Build 060.29 Architecture](build_060_29_architecture.md) — архитектура,
решения и подробные результаты подэтапов 060.29.0060.29.8;
- [Build 060.28 Engineering Migration Report](build_060_28.md) —
Persistent Checkpoint and Startup Recovery;
- [Dzentra Target Architecture](../architecture/dzentra_target_architecture.md) —
целевая архитектура Dzentra;
- [Master Roadmap](../roadmap/master-roadmap.md) — дальнейшая
последовательность Build.
---
## 1. Назначение Build
Build 060.29 добавил безопасное чтение сохранённых Canonical Market
Data и их детерминированное воспроизведение.
Итоговая цепочка:
```text
PostgreSQL Canonical Market Data
Historical Access
bounded immutable ReplayPlan
ReplaySession + Deterministic Clock
явно переданный Canonical consumer
```
Historical Access и Replay являются read-side подсистемами. Они не
заменяют Acquisition Runtime, не продвигают operational checkpoint и не
записывают воспроизводимые события обратно в Market Data Storage.
---
## 2. Завершённые подэтапы
| Подэтап | Название | Статус |
|---|---|---|
| 060.29.0 | Architecture, Boundaries and Ordering Policy | Accepted |
| 060.29.1 | Historical Access and Replay Contracts | Accepted |
| 060.29.2 | Global Replay Sequence Migration and PostgreSQL Trade History | Accepted |
| 060.29.3 | Quote/Candle History and Snapshot Plan Builder | Accepted |
| 060.29.4 | Deterministic Replay Clock | Accepted |
| 060.29.5 | Replay Session and Engine | Accepted |
| 060.29.6 | Consumer and Composition Integration | Accepted |
| 060.29.7 | PostgreSQL Replay and Failure Verification | Accepted |
| 060.29.8 | Final Regression and Acceptance | Accepted |
Каждый подэтап проходил отдельный read-only review. Findings
исправлялись и закрывались regression-тестами до принятия.
---
## 3. Реализованная архитектура
### 3.1. Глобальная последовательность Replay
Migration 9 добавила один shared PostgreSQL sequence для Trades, Quotes
и Candle revisions. Неизменяемый `replay_sequence` задаёт общий
детерминированный порядок для событий с одинаковым временем и
сохраняется при duplicate или provenance update.
Существующие writers совместимы с sequence для одиночных, пакетных и
конкурентных записей. Default, существующие месячные и будущие partitions
получают одинаковые constraints, trigger и keyset indexes.
Migration выполняется атомарно и использует единый порядок блокировок с
Partition Manager и writers.
### 3.2. Historical Access
DB-neutral read-контракты отделены от write-only Storage API. Отдельные
PostgreSQL readers возвращают типизированные неизменяемые страницы:
- Trades — по `executed_at`;
- Quotes — по `received_at`;
- Candle revisions — по `open_time`.
Запросы используют полуоткрытый временной диапазон и forward keyset
pagination. Cursor связан с точным query scope. Строки PostgreSQL строго
проверяются перед созданием Canonical `Trade`, `Quote` или `Candle`.
### 3.3. Bounded Replay snapshot
Replay Plan Builder выполняет один статический snapshot-запрос в
короткой транзакции `READ ONLY REPEATABLE READ`. Все выбранные события
материализуются до возврата `ReplayPlan`; cursor, transaction и
connection освобождаются до первого вызова consumer.
Порядок Replay равен `(replay_at, replay_sequence)`. Для Candle временем
Replay является `observed_at`, поэтому ревизия не появляется раньше
момента, когда она стала известна системе. Превышение `max_records`
завершается явной ошибкой без частичного plan.
### 3.4. Clock, Session и Composition
`DeterministicReplayClock` работает только с aware UTC-временем,
разрешает равное время и запрещает движение назад. Он не читает wall
clock и не имеет reset.
`ReplaySession` является необратимой one-shot сущностью. Она
последовательно продвигает Clock и ожидает один consumer-вызов для
каждого события. Ошибки и cancellation сохраняют явное terminal state и
не скрываются.
`ReplaySessionFactory` синхронно подготавливает новый граф
`Plan → Clock → consumer → Session` для каждого вызова. Default consumer,
автоматический startup, скрытая задача и отдельный `ReplayEngine` не
добавлены. Caller отдельно владеет `session.run()`.
### 3.5. Статическая проверка типов
Pyright закреплён как обязательный gate в режиме `standard`, совпадающем
с Pylance проекта. Канонический запуск — `scripts/check_python_types.sh`;
допустимый результат — только `0 errors, 0 warnings`. Тот же gate входит
в обычную offline pytest-регрессию.
---
## 4. Real PostgreSQL verification
Безопасный opt-in harness требует отдельную локальную базу с именем
`dzentra_test_*`, явный флаг и отдельный DSN.
Настоящий PostgreSQL 16 подтвердил:
- атомарный детерминированный backfill migration 9;
- общий sequence и совместимость всех writers/partitions;
- keyset pagination Trades, Quotes и Candle revisions;
- единый mixed-type Replay order;
- устойчивый `REPEATABLE READ` snapshot при concurrent commit;
- освобождение PostgreSQL resources до playback;
- limit, integrity, backend, consumer и cancellation paths;
- независимые графы двух одновременно готовящихся Replay Session;
- полный путь `Loopback Runtime → Storage → History → Replay`;
- отсутствие изменения durable данных и operational checkpoint.
---
## 5. Финальные результаты
Итоговая приёмка выполнена 2026-08-02:
```text
Pyright mandatory gate: 0 errors, 0 warnings
Pyright pytest gate: 1 passed
Expanded Access/Replay/Storage unit: 545 passed
PostgreSQL Replay target repeated: 10 × 12 passed
Full PostgreSQL Storage integration: 77 passed
Full integration with PostgreSQL: 90 passed
PostgreSQL suite without opt-in: 77 skipped
Fixed stress target: 3 passed, 1 deselected
Full offline regression: 2681 passed, 95 deselected
pip check: clean
Compileall через временный pycache: clean
Tracked/untracked whitespace checks: clean
Три независимых read-only review: clean
```
В integration и stress наборах `ResourceWarning` считался ошибкой.
Production-код на финальном подэтапе 060.29.8 не изменялся: матрица не
выявила реального дефекта.
---
## 6. Эксплуатационное предупреждение migration 9
Migration 9 является блокирующей. Её длительность пропорциональна уже
накопленному объёму Market Data, потому что существующие строки получают
глобальный `replay_sequence`, после чего создаются constraints и
индексы.
Для текущей небольшой базы выбранный атомарный вариант разумен. Перед
применением к большой production-базе обязательны резервная копия,
замер длительности на сопоставимом объёме и отдельное maintenance
window. Online staged migration в Build 060.29 не реализована и требует
отдельного архитектурного решения.
---
## 7. Границы Build
Build 060.29 намеренно не реализует:
- initial historical backfill с биржи;
- гарантию полной биржевой истории без completeness metadata;
- точное воспроизведение порядка исходных сетевых пакетов;
- production consumers для persistent Quotes и Candles;
- автоматический запуск Replay из Bootstrap;
- default/no-op Replay consumer;
- Backtesting, Analytics API или торговую симуляцию;
- online migration 9 для большой production-базы.
Каждая Historical page отражает committed-состояние на время своего
запроса. Последовательная pagination охватывает все фактически
сохранённые строки диапазона только при неизменном dataset между
страницами; единого межстраничного snapshot нет. Период доступной истории
определяется моментом включения persistent storage и Retention Policy, а
не самим Replay API.
Постороннее пользовательское изменение `.gitignore` не относится к
Build 060.29 и не должно включаться в его staging.
---
## 8. Итог
Build 060.29 завершён и принят.
Dzentra получила отдельный Historical Access, общий детерминированный
порядок сохранённых Canonical Market Data и caller-owned Replay без
скрытого lifecycle. Сохранённую рыночную историю теперь можно безопасно
читать и воспроизводить одинаковыми Canonical объектами.
Следующий этап — [Build 060.30](build_060_30_architecture.md), итоговый
аудит и документальное закрытие ветки Trades Feed.