Build 060.27: implement Persistent Market Data Storage

This commit is contained in:
2026-08-01 03:22:25 +03:00
parent cb8acfe5fe
commit 58e5a12a4d
54 changed files with 10243 additions and 101 deletions

View File

@@ -0,0 +1,224 @@
# Build 060.27 — Persistent Market Data Storage
**Engineering Migration Report**
---
## Контроль документа
| Свойство | Значение |
|---|---|
| Build | 060.27 |
| Статус | Completed |
| Подсистема | Market Data Acquisition / Persistent Storage |
| Компонент | Canonical Market Data Storage |
| Дата завершения | 2026-08-01 |
| Версия | 1.0 |
---
## Связанные документы
- `build_060_27_architecture.md` — архитектура, решения и подробные
результаты подэтапов 060.27.0060.27.8;
- `build_060_26.md` — итог Runtime Integration and Regression;
- `dzentra_target_architecture.md` — место Market Data Storage в целевой
архитектуре Dzentra;
- `master-roadmap.md` — дальнейшая последовательность Build.
---
## 1. Назначение Build
Build 060.27 добавил долговременное PostgreSQL-хранилище Canonical
Market Data. Production Trade Stream теперь может сохранять Trades
независимо от времени жизни процесса, а Quotes и Candles получили
готовые storage-контракты и repositories без подключения существующих
consumers.
Главная гарантия интеграции:
```text
validated Canonical Trade
durable PostgreSQL write
operational checkpoint advancement
```
Ошибка включённого persistent storage является фатальной. Runtime не
продвигает checkpoint и не продолжает работу так, будто Trade сохранён.
---
## 2. Завершённые подэтапы
| Подэтап | Название | Статус |
|---|---|---|
| 060.27.0 | Storage Contract and Boundaries | Accepted |
| 060.27.1 | PostgreSQL Schema, Migrations and Pool | Accepted |
| 060.27.2 | Persistent Trade Repository | Accepted |
| 060.27.3 | Quote and Candle Repositories | Accepted |
| 060.27.4 | Storage API and Retention | Accepted |
| 060.27.5 | Trade Runtime Persistence Integration | Accepted |
| 060.27.6 | Bootstrap and Lifecycle Integration | Accepted |
| 060.27.7 | Integration and Failure Verification | Accepted |
| 060.27.8 | Final Regression and Acceptance | Accepted |
Каждый подэтап проходил отдельный read-only review. Findings
исправлялись и закрывались regression-тестами до принятия.
---
## 3. Реализованная архитектура
### 3.1. Schema, migrations и pool
Создана PostgreSQL schema `market_data` с partitioned таблицами:
- `trades` — Canonical Trades;
- `quotes` — неизменяемые Canonical Quote snapshots;
- `candle_revisions` — наблюдавшиеся ревизии Candles;
- `partition_registry` — реестр Dzentra-managed partitions.
Семь упорядоченных миграций применяются в одной транзакции под
transaction-level advisory lock. История хранится в
`public.storage_schema_migrations`; неизвестная версия или другое имя
миграции являются фатальным schema mismatch.
`PostgresConnectionPool` не выполняет I/O в конструкторе. Pool явно
открывается Application lifecycle перед Runtime и закрывается только
после полной остановки Trade Runtime.
### 3.2. Canonical repositories
Repository-контракты различают три результата:
- `INSERTED` — сохранено новое событие;
- `DUPLICATE` — идентичное событие уже существует;
- `PROVENANCE_UPDATED` — Canonical payload совпал, добавлен новый путь
наблюдения.
Trade identity задаётся `venue + symbol + trade_id + executed_at`.
Время защищает историю от коллизии после полного signed 32-bit rollover
Trade ID. Разный transport source не создаёт Canonical conflict, а
различие цены, количества, времени или стороны создаёт явную ошибку.
Quote identity использует `venue + symbol + received_at`. Candle
identity использует `venue + symbol + interval + open_time +
observed_at`, поэтому промежуточные и финальные ревизии не
перезаписываются скрытно.
Одиночные и пакетные операции транзакционны. Конфликт или database
error откатывает всю пакетную запись.
### 3.3. Partitions и retention
Каждая основная таблица имеет default partition. Управляемый partition
manager под общим advisory lock:
1. проверяет фактическое состояние PostgreSQL и registry;
2. создаёт месячную таблицу;
3. переносит подходящие default rows;
4. подключает partition в той же транзакции.
Retention по умолчанию выключен. Явный запуск удаляет только
зарегистрированные истёкшие partitions и строки раньше точного UTC
cutoff. Очистка всех выбранных типов выполняется атомарно.
### 3.4. Runtime и Bootstrap
Live и Recovery используют один `TradeObservationSinkProtocol` через
общий `TradeStreamConsistencyController`. Единственный владелец записи
обеспечивает одинаковую последовательность для обоих путей данных.
Синхронная PostgreSQL-запись выполняется вне asyncio event loop через
принадлежащую Runtime задачу. Cancellation ожидает уже начатую запись и
не оставляет фонового worker.
Storage включается только явным `MARKET_DATA_STORAGE_ENABLED=true` и
требует включённый Trade Stream. При выключенном флаге зависимости не
строятся, pool не открывается, migrations не запускаются.
---
## 4. Real PostgreSQL verification
Безопасный opt-in harness требует одновременно:
- `DZENTRA_RUN_POSTGRES_TESTS=1`;
- отдельный `DZENTRA_TEST_POSTGRES_DSN`;
- явный localhost, loopback address или local socket;
- имя базы с префиксом `dzentra_test_`.
PostgreSQL service, неявный endpoint и смешанный local/remote fallback
запрещены. Перед destructive cleanup harness повторно проверяет точное
имя фактической базы и специальное имя контрольного соединения.
Настоящий PostgreSQL подтвердил:
- атомарность migrations и repositories;
- участие обеих concurrent migration/partition caller-сессий;
- insert, duplicate, provenance и conflict paths;
- перенос default rows и точность retention cutoff;
- Runtime persistence через Live и reconnect/recovery;
- fatal propagation database failure;
- правильное закрытие pool и отсутствие оставшихся соединений.
---
## 5. Финальные результаты
Итоговая приёмка выполнена 2026-08-01:
```text
Targeted Storage/Runtime unit suite: 307 passed
PostgreSQL control run: 15 passed
PostgreSQL repeated ten times: 150 passed
Combined integration suite: 26 passed
Fixed stress target: 3 passed, 1 deselected
PostgreSQL suite without opt-in: 15 skipped
Full offline regression: 2119 passed, 31 deselected
git diff --check: clean
Untracked files diff check: clean
```
В integration и stress наборах `ResourceWarning` считался ошибкой.
Одноразовый PostgreSQL 16 работал на `tmpfs` и после приёмки был
остановлен и удалён. Итоговый read-only review не обнаружил открытых
findings.
---
## 6. Границы Build
Build 060.27 намеренно не реализует:
- persistent Runtime checkpoint;
- Startup Recovery после перезапуска процесса;
- Historical Queries и Data Access Layer;
- Replay API и Analytics API;
- автоматический partition/retention scheduler;
- подключение существующих Quote/Candle consumers;
- хранение raw exchange documents.
Persistent Checkpoint и Startup Recovery относятся к Build 060.28.
Historical Access и Replay относятся к Build 060.29. Полная итоговая
ревизия документации подсистемы остаётся задачей Build 060.30.
Постороннее пользовательское изменение `.gitignore` не относится к
Build 060.27 и не должно включаться в его staging.
---
## 7. Итог
Build 060.27 завершён и принят.
Dzentra получила транзакционное долговременное хранилище Canonical
Market Data и production persistence для Trades. Operational checkpoint
теперь продвигается только после подтверждённой durable-записи, а
ошибка Storage завершает Runtime без скрытой потери истории.
Следующий этап — Build 060.28, Persistent Checkpoint and Startup
Recovery.