Files
dzentra_bot/docs/migrations/build_060_27.md

227 lines
10 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.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](build_060_27_architecture.md) — архитектура,
решения и подробные результаты подэтапов 060.27.0060.27.8;
- [Build 060.26 Engineering Migration Report](build_060_26.md) — итог
Runtime Integration and Regression;
- [Dzentra Target Architecture](../architecture/dzentra_target_architecture.md) —
место Market Data Storage в целевой архитектуре Dzentra;
- [Master Roadmap](../roadmap/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](build_060_28.md), Persistent Checkpoint
and Startup Recovery.