Files
dzentra_bot/docs/migrations/build_060_29.md

12 KiB
Raw Blame History

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

Связанные документы


1. Назначение Build

Build 060.29 добавил безопасное чтение сохранённых Canonical Market Data и их детерминированное воспроизведение.

Итоговая цепочка:

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:

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.