# 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.md` — архитектура, решения и подробные результаты подэтапов 060.29.0–060.29.8; - `build_060_28.md` — Persistent Checkpoint and Startup Recovery; - `dzentra_target_architecture.md` — целевая архитектура Dzentra; - `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, итоговый аудит и документальное закрытие ветки Trades Feed.