Files
dzentra_bot/docs/migrations/build_060_7.md

1734 lines
47 KiB
Markdown
Raw Permalink 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.7 — REST Trade Adapter
**Engineering Migration Report**
---
# Контроль документа
| Свойство | Значение |
|---|---|
| Build | 060.7 |
| Название | REST Trade Adapter |
| Статус | Завершён |
| Проект | Dzentra |
| Подсистема | Market Data Acquisition |
| Компонент | Trades Feed / Time & Sales |
| Версия документа | 1.0 |
| Дата завершения | 2026-07-19 |
---
# Цель Build
После завершения Build 060.6 подсистема получения исторических сделок уже содержала полностью сформированный конвейер преобразования транспортных данных.
К этому моменту были реализованы:
- транспортная модель агрегированной сделки REST API;
- проверка структуры REST-документа;
- parser транспортной модели;
- проверка корректности значений;
- mapper транспортной модели в Canonical Trade.
После завершения предыдущего этапа полный pipeline имел следующий вид:
```text
REST JSON
Schema Validation
ValidatedRestAggTradesDocument
Parser
tuple[DzengiRestAggTrade]
Value Validation
Mapper
tuple[Trade]
```
Несмотря на завершённость всех отдельных компонентов, в архитектуре отсутствовал единый публичный интерфейс, объединяющий их в последовательную операцию обработки документа.
Каждый вызывающий компонент должен был самостоятельно помнить:
- какую функцию вызвать первой;
- какую второй;
- какой тип возвращает каждая стадия;
- какой порядок обработки является корректным.
Подобная схема противоречит одной из основных целей Acquisition Layer — предоставить простой и безопасный интерфейс обработки рыночных данных.
Следовательно возникла необходимость в отдельном компоненте, который не реализует новую бизнес-логику, а исключительно объединяет уже существующие стадии обработки.
Именно эту задачу решает Build 060.7.
В рамках данного Build реализуется исключительно REST Trade Adapter.
Build намеренно **не включает**:
- HTTP client;
- REST endpoint;
- получение документа;
- REST polling;
- Feed;
- Registry;
- Runtime Integration;
- Acquisition Service;
- Time & Sales Feed;
- объединение REST и WebSocket сделок;
- хранение истории;
- дедупликацию;
- сортировку;
- агрегацию;
- production-интеграцию.
Все перечисленные задачи относятся к последующим Build.
---
# Архитектурный контекст
Во всей подсистеме Market Data Acquisition используется единый принцип построения pipeline.
Каждый слой выполняет только одну строго определённую задачу.
```text
Transport
Schema Validation
Parser
Value Validation
Mapper
Canonical Model
```
Такой подход уже используется для:
- Instrument;
- REST Quote;
- WebSocket Quote;
- REST Candle;
- WebSocket Candle.
Однако для REST Trades отсутствовал последний объединяющий уровень.
Вызов каждого слоя выполнялся вручную.
Build 060.7 вводит единый Adapter Layer, который становится официальной точкой входа в REST Trade Pipeline.
После завершения Build архитектура принимает следующий вид:
```text
REST JSON
Schema Validation
ValidatedRestAggTradesDocument
REST Trade Adapter
├──────── Parser
├──────── Value Validation
└──────── Mapper
tuple[Trade]
```
Таким образом Adapter становится исключительно координатором уже существующих компонентов.
Сам Adapter не содержит собственной бизнес-логики.
---
# Исходное состояние
До начала Build 060.7 проект уже содержал следующие компоненты.
```text
ValidatedRestAggTradesDocument
DzengiRestAggTrade
Trade
validate_rest_agg_trades_schema()
parse_rest_agg_trades()
validate_rest_agg_trade_values()
map_dzengi_rest_agg_trades_to_trades()
```
Все необходимые стадии обработки документа уже существовали.
Отсутствовал только компонент, объединяющий их в единую последовательность.
При этом ни один из существующих модулей не должен был изменяться.
Это позволяло реализовать Build как полностью additive change.
---
# Предварительный архитектурный аудит
Перед началом реализации был повторно проанализирован существующий код проекта.
Проверены следующие файлы:
```text
app/src/market_data/acquisition/adapters/dzengi/parser.py
app/src/market_data/acquisition/adapters/dzengi/mapper.py
app/src/market_data/acquisition/validation/schema.py
app/src/market_data/acquisition/validation/values.py
app/src/market_data/acquisition/adapters/dzengi/websocket.py
docs/migrations/build_060_1.md
docs/migrations/build_060_2.md
docs/migrations/build_060_3.md
docs/migrations/build_060_4.md
docs/migrations/build_060_5.md
docs/migrations/build_060_6.md
```
Кроме анализа кода был повторно выполнен аудит всей архитектуры Acquisition Pipeline.
В результате были подтверждены следующие выводы.
- Schema Validation уже является самостоятельным архитектурным слоем.
- Parser отвечает исключительно за построение transport-моделей.
- Value Validation отвечает исключительно за корректность значений.
- Mapper отвечает исключительно за построение Canonical Trade.
- Ни один из существующих компонентов не должен изменять собственную ответственность.
- Новый компонент должен выполнять исключительно композицию существующих этапов.
Именно эти выводы легли в основу проектирования Build 060.7.
---
# Архитектурная задача Build
Главная задача Build заключается не в добавлении новой функциональности.
Все необходимые операции обработки документа уже существуют.
Задача Build состоит в создании единой точки входа в REST Trade Pipeline.
После завершения Build вызывающий код должен работать только с одной публичной функцией:
```python
adapt_rest_agg_trades_document(...)
```
Внутри неё последовательно выполняются:
```text
Parser
Value Validation
Mapper
```
При этом вызывающий код полностью освобождается от знания внутренней структуры pipeline.
Такое решение уменьшает связанность компонентов и существенно упрощает дальнейшее сопровождение системы.
# Рассмотренные архитектурные решения
Перед началом реализации Build было рассмотрено несколько вариантов построения REST Trade Adapter.
Основная задача заключалась не в написании кода, а в определении его архитектурной ответственности.
Именно на этом этапе было принято несколько решений, которые впоследствии стали архитектурными инвариантами всей подсистемы Acquisition.
---
## Вариант 1
Разместить всю последовательность обработки непосредственно внутри будущего REST Source.
Например:
```text
HTTP
JSON
Schema Validation
Parser
Value Validation
Mapper
Trade
```
На первый взгляд подобная схема выглядит простой.
Однако после анализа существующей архитектуры данный вариант был отклонён.
Причины:
- REST Source начинает заниматься обработкой данных;
- источник данных становится зависимым от транспортной модели;
- становится невозможно использовать Adapter повторно;
- нарушается разделение ответственности между слоями получения и обработки данных.
В Dzentra источник данных должен отвечать исключительно за получение документа.
Вся обработка документа относится к отдельному компоненту.
---
## Вариант 2
Передавать в Adapter исходный REST JSON.
Например:
```python
adapt_rest_agg_trades_document(
document: object,
symbol="BTC/USDT",
)
```
При таком подходе Adapter самостоятельно вызывал бы:
```text
validate_rest_agg_trades_schema()
parse_rest_agg_trades()
validate_rest_agg_trade_values()
map_dzengi_rest_agg_trades_to_trades()
```
Именно такой вариант первоначально рассматривался во время проектирования.
После повторного анализа существующей архитектуры он был отклонён.
Причины:
Schema Validation уже является самостоятельным архитектурным уровнем.
Если Adapter начинает самостоятельно выполнять проверку структуры документа,
он получает сразу две ответственности:
- обработку документа;
- проверку структуры документа.
Это противоречит принятой архитектуре Acquisition Layer.
Кроме того, подобный подход нарушал бы единообразие остальных pipeline проекта.
Следовательно Schema Validation должна оставаться отдельным независимым этапом.
---
## Утверждённое решение
Adapter получает уже проверенный документ:
```text
ValidatedRestAggTradesDocument
```
После этого выполняются только следующие операции:
```text
Parser
Value Validation
Mapper
```
Таким образом Build полностью сохраняет разделение ответственности между слоями.
---
# Почему Adapter не выполняет Schema Validation
Во время проектирования данный вопрос обсуждался отдельно.
На первый взгляд логично было бы сделать Adapter полностью автономным.
То есть предоставить ему возможность принимать произвольный REST документ.
Однако после анализа существующего проекта было подтверждено,
что подобное решение нарушило бы уже сформированную архитектуру.
К моменту начала Build в системе уже существовали независимые функции:
```python
validate_quote_schema()
validate_candle_schema()
validate_rest_agg_trades_schema()
validate_websocket_ohlc_schema()
```
Все они образуют самостоятельный слой Schema Validation.
Следовательно Adapter не должен дублировать их ответственность.
После Build 060.7 последовательность обработки выглядит следующим образом:
```text
REST Document Source
Schema Validation
ValidatedRestAggTradesDocument
REST Trade Adapter
```
Такое разделение полностью соответствует архитектуре остальных компонентов проекта.
---
# Почему Adapter реализован функцией
Во время проектирования первоначально предполагалось реализовать Adapter как отдельный класс.
Например:
```python
class DzengiRestTradeAdapter:
```
Такой подход выглядит привычным для многих проектов.
Однако после анализа существующего кода Acquisition Layer возник вопрос:
имеет ли Adapter собственное состояние?
Ответ оказался отрицательным.
Adapter:
- не хранит состояние;
- не содержит конфигурацию;
- не управляет ресурсами;
- не использует Dependency Injection;
- не предоставляет расширяемый интерфейс;
- не содержит полиморфизма.
Фактически единственной его задачей является последовательный вызов уже существующих функций.
Следовательно класс не предоставляет никаких преимуществ.
Использование класса лишь увеличило бы объём кода и усложнило архитектуру.
Поэтому было принято решение отказаться от него.
---
# Новый архитектурный принцип
Именно во время реализации Build 060.7 был окончательно сформулирован новый архитектурный принцип проекта.
Он выглядит следующим образом.
```text
Stateful
Class
```
```text
Stateless
Function
```
Именно этот принцип теперь применяется при проектировании новых компонентов Market Data Acquisition.
---
# Почему выбран функциональный API
После отказа от класса оставалось определить форму публичного интерфейса.
Было принято решение использовать одну функцию:
```python
adapt_rest_agg_trades_document()
```
Причины такого решения.
Во-первых,
весь Acquisition Layer уже использует функциональный стиль.
Например:
```python
parse_rest_agg_trades()
validate_rest_agg_trade_values()
map_dzengi_rest_agg_trades_to_trades()
```
Adapter становится естественным продолжением этой цепочки.
Во-вторых,
функция значительно проще тестируется.
Она полностью детерминирована.
При одинаковых входных данных всегда возвращает одинаковый результат.
В-третьих,
отсутствует необходимость создавать экземпляры класса,
что делает публичный API проще для использования.
---
# Почему файл называется rest_trade_adapter.py
Во время проектирования обсуждалось несколько вариантов имени файла.
Например:
```text
trade_adapter.py
```
или
```text
dzengi_rest_trade_adapter.py
```
После анализа структуры проекта было принято решение использовать:
```text
rest_trade_adapter.py
```
Причины.
Каталог уже содержит информацию о конкретной бирже:
```text
adapters/dzengi/
```
Следовательно повторять слово:
```text
dzengi
```
в имени файла не требуется.
Кроме того,
имя:
```text
trade_adapter.py
```
оказалось слишком общим.
В будущем в проекте могут появиться:
- websocket_trade_adapter.py;
- replay_trade_adapter.py;
- simulated_trade_adapter.py.
Название:
```text
rest_trade_adapter.py
```
однозначно определяет назначение компонента и соответствует принятому правилу уникальности имён файлов.
---
# Новый публичный API
Build 060.7 вводит единственную публичную функцию.
```python
adapt_rest_agg_trades_document()
```
Назначение функции:
- принимает документ, уже прошедший Schema Validation;
- запускает Parser;
- выполняет Value Validation;
- выполняет Mapper;
- возвращает immutable tuple Canonical Trade.
Сигнатура имеет следующий вид:
```text
ValidatedRestAggTradesDocument
tuple[Trade]
```
Внутренняя реализация полностью скрыта от вызывающего кода.
После завершения Build именно эта функция становится официальной точкой входа REST Trade Pipeline.
# Семантика REST Trade Adapter
После завершения Build 060.7 Adapter становится единственной точкой композиции всех ранее реализованных компонентов обработки REST Trade.
При этом сам Adapter намеренно остаётся максимально простым.
Его ответственность ограничивается исключительно последовательным вызовом уже существующих функций.
Полная последовательность обработки выглядит следующим образом.
```text
ValidatedRestAggTradesDocument
parse_rest_agg_trades()
tuple[DzengiRestAggTrade]
validate_rest_agg_trade_values()
tuple[DzengiRestAggTrade]
map_dzengi_rest_agg_trades_to_trades()
tuple[Trade]
```
Adapter не выполняет никаких дополнительных преобразований.
Он лишь организует последовательность уже существующих этапов.
---
# Почему Adapter не содержит собственной логики
Во время проектирования обсуждался естественный вопрос.
Если Adapter является самостоятельным компонентом,
не должен ли он выполнять хотя бы часть бизнес-логики?
Ответ оказался отрицательным.
Все необходимые операции уже реализованы в предыдущих Build.
Повторное выполнение каких-либо проверок внутри Adapter привело бы к:
- дублированию кода;
- нарушению принципа Single Responsibility;
- усложнению сопровождения;
- появлению двух различных реализаций одной и той же логики.
Поэтому Adapter сознательно остаётся максимально "тонким".
Его задача — исключительно композиция.
---
# Почему Adapter не перехватывает исключения
Во время реализации рассматривался вариант,
при котором Adapter преобразовывал бы ошибки всех нижележащих компонентов в единый тип исключения.
Например:
```text
TradeAdapterError
```
После анализа архитектуры данный вариант был отклонён.
Причины.
Каждый уровень Acquisition Pipeline уже обладает собственным специализированным типом исключений.
```text
TradeSchemaError
TradeParseError
TradeValueError
TradeMappingError
```
Если Adapter начнёт преобразовывать их в единый тип,
будет потеряна информация о том,
на каком именно этапе возникла ошибка.
Это существенно ухудшит диагностику системы.
Поэтому Adapter намеренно не перехватывает исключения.
Все ошибки пробрасываются вызывающему компоненту без изменений.
---
# Почему Adapter не изменяет порядок выполнения этапов
Последовательность вызова компонентов также обсуждалась отдельно.
Теоретически можно было изменить порядок:
```text
Parser
Mapper
Validation
```
или
```text
Validation
Parser
```
Оба варианта были отклонены.
Причины очевидны.
Parser невозможно выполнить до проверки структуры документа.
Mapper невозможно выполнить до проверки корректности значений.
Следовательно единственная корректная последовательность выглядит следующим образом.
```text
Schema Validation
Parser
Value Validation
Mapper
```
Никакой другой порядок не соответствует архитектуре Acquisition Layer.
---
# Почему Adapter возвращает tuple
Все предыдущие Build закрепили использование immutable-коллекций.
Поэтому Adapter также возвращает:
```python
tuple[Trade]
```
Использование списка не рассматривалось.
Причины.
Immutable-коллекция:
- безопаснее при передаче между слоями;
- исключает случайное изменение результата;
- соответствует остальным компонентам Acquisition;
- делает контракт функции полностью предсказуемым.
Таким образом Build полностью сохраняет существующий архитектурный стиль проекта.
---
# Что намеренно не делает Adapter
Build 060.7 специально не добавляет никакой дополнительной обработки данных.
Adapter намеренно:
не выполняет HTTP-запросы;
не получает REST-документ;
не выполняет Schema Validation;
не сортирует сделки;
не удаляет дубликаты;
не объединяет REST и WebSocket данные;
не агрегирует сделки;
не рассчитывает статистику;
не анализирует последовательность сделок;
не создаёт свечи;
не взаимодействует с Runtime;
не взаимодействует с Feed;
не взаимодействует с Registry;
не сохраняет данные;
не ведёт журнал обработки.
Все перечисленные задачи относятся к другим архитектурным слоям и намеренно исключены из области ответственности Adapter.
---
# Изменённые файлы
В рамках Build 060.7 был добавлен один новый файл проекта.
```text
app/src/market_data/acquisition/adapters/dzengi/rest_trade_adapter.py
```
Также был добавлен новый набор unit-тестов.
```text
app/tests/unit/market_data/acquisition/adapters/dzengi/test_rest_trade_adapter.py
```
Кроме подготовки инженерной документации Build никакие другие файлы проекта не изменялись.
Build полностью соответствует принятому принципу **Local Additive Change**.
---
# Изменения в rest_trade_adapter.py
Новый файл содержит единственную публичную функцию.
```python
adapt_rest_agg_trades_document()
```
Внутри неё отсутствует какая-либо собственная логика обработки.
Функция последовательно вызывает:
```python
parse_rest_agg_trades()
validate_rest_agg_trade_values()
map_dzengi_rest_agg_trades_to_trades()
```
После завершения последнего этапа результат сразу возвращается вызывающему компоненту.
Таким образом Adapter становится исключительно координационным уровнем REST Trade Pipeline.
---
# Изменения в unit-тестах
Для нового Adapter создан отдельный файл тестов.
```text
tests/unit/market_data/acquisition/adapters/dzengi/test_rest_trade_adapter.py
```
Это соответствует принятому соглашению проекта,
согласно которому каждый самостоятельный компонент Acquisition Layer имеет собственный независимый набор unit-тестов.
Существующие тесты:
- Parser;
- Value Validation;
- Mapper;
не изменялись.
Build полностью additive.
---
# Проверяемые сценарии
Новый набор тестов проверяет исключительно ответственность Adapter.
Подтверждаются следующие сценарии.
- успешная обработка корректного документа;
- корректная передача symbol в Mapper;
- корректная обработка пустого документа;
- корректное пробрасывание исключений нижележащих компонентов.
Тем самым подтверждается,
что Adapter не изменяет семантику работы уже существующих этапов обработки.
При этом логика Parser, Validation и Mapper продолжает проверяться их собственными независимыми тестами.
# Что намеренно не изменялось
Build 060.7 специально не изменяет существующие компоненты Acquisition Pipeline.
Без изменений остаются:
```text
app/src/market_data/acquisition/adapters/dzengi/parser.py
app/src/market_data/acquisition/adapters/dzengi/mapper.py
app/src/market_data/acquisition/validation/schema.py
app/src/market_data/acquisition/validation/values.py
app/src/market_data/acquisition/models/trade.py
app/src/market_data/acquisition/runtime/
app/src/market_data/acquisition/feeds/
app/src/market_data/acquisition/service.py
app/src/market_data/acquisition/registry.py
```
Также Build намеренно не включает:
- REST client;
- выполнение HTTP-запросов;
- получение исторических сделок;
- REST polling;
- объединение REST и WebSocket Trade;
- Time & Sales Feed;
- Runtime Integration;
- хранение истории сделок;
- кэширование;
- дедупликацию;
- сортировку;
- агрегацию;
- вычисление аналитики;
- построение свечей;
- взаимодействие с Trading Layer.
Все перечисленные задачи реализуются отдельными Build согласно утверждённой дорожной карте.
Таким образом Build 060.7 остаётся полностью локальным и не выходит за пределы собственной архитектурной ответственности.
---
# Проверка компиляции
После завершения реализации была выполнена проверка компиляции проекта.
Команда выполнялась из каталога:
```text
~/vsprojects/dzentra_bot/app
```
При активированном виртуальном окружении:
```bash
source .venv/bin/activate
```
Выполнена команда:
```bash
python -m compileall src
```
Результат:
```text
успешно
```
Все модули проекта успешно скомпилированы.
Ошибок синтаксиса не обнаружено.
Build не нарушил корректность структуры проекта.
---
# Проверка локальных unit-тестов
После завершения реализации Adapter были выполнены специализированные unit-тесты.
Команда:
```bash
python -m pytest \
tests/unit/market_data/acquisition/adapters/dzengi/test_rest_trade_adapter.py \
-q
```
Результат:
```text
4 passed in 0.02s
```
Проверки подтвердили:
- корректную последовательность вызова компонентов;
- корректную передачу параметра symbol;
- корректную обработку пустого документа;
- корректное пробрасывание исключений.
Ни одна существующая проверка проекта не была нарушена.
---
# Полный regression suite
После завершения Build выполнен полный набор тестов проекта.
Команда:
```bash
python -m pytest
```
Результат:
```text
1096 passed in 2.59s
```
Регрессий не обнаружено.
Все ранее реализованные Build продолжают работать без изменений.
Это подтверждает,
что Build 060.7 полностью соответствует принципу **Local Additive Change**.
---
# Проверка форматирования
После завершения работы выполнена команда:
```bash
git diff --check
```
Вывод отсутствует.
Это подтверждает отсутствие:
- trailing whitespace;
- лишних пробелов;
- нарушений форматирования;
- ошибок оформления diff.
Build соответствует принятым требованиям оформления исходного кода.
---
# Контроль размещения новой функциональности
После завершения Build вся новая функциональность сосредоточена только в предназначенных для неё компонентах.
Adapter расположен исключительно в:
```text
src/market_data/acquisition/adapters/dzengi/rest_trade_adapter.py
```
Unit-тесты расположены исключительно в:
```text
tests/unit/market_data/acquisition/adapters/dzengi/test_rest_trade_adapter.py
```
Другие подсистемы проекта Build не затрагивает.
Архитектурная изоляция полностью сохранена.
---
# Состояние Git
После завершения Build выполнена команда:
```bash
git status
```
Для Build 060.7 зафиксированы изменения:
```text
added:
app/src/market_data/acquisition/adapters/dzengi/rest_trade_adapter.py
app/tests/unit/market_data/acquisition/adapters/dzengi/test_rest_trade_adapter.py
untracked:
docs/migrations/build_060_7.md
```
Ветка разработки:
```text
main
```
опережает `origin/main`.
Данное состояние соответствует текущему процессу разработки и не связано с архитектурой Build.
---
# Фактический diff
В рамках Build добавлен новый компонент:
```text
app/src/market_data/acquisition/adapters/dzengi/rest_trade_adapter.py
```
Публичный API Build:
```python
adapt_rest_agg_trades_document()
```
Функция объединяет:
```text
parse_rest_agg_trades()
validate_rest_agg_trade_values()
map_dzengi_rest_agg_trades_to_trades()
```
Кроме того,
добавлен отдельный набор unit-тестов:
```text
tests/unit/market_data/acquisition/adapters/dzengi/test_rest_trade_adapter.py
```
Все изменения являются полностью additive.
Никакое существующее поведение системы не изменялось.
---
# Архитектурный результат
После завершения Build 060.7 REST Trade Pipeline впервые получает официальную единую точку входа.
Полная архитектура теперь выглядит следующим образом.
```text
REST JSON
Schema Validation
ValidatedRestAggTradesDocument
REST Trade Adapter
Parser
Value Validation
Mapper
tuple[Trade]
```
Каждый слой обладает собственной зоной ответственности.
Ни один слой не выполняет задачи соседнего.
Adapter становится исключительно координатором существующих компонентов.
Это полностью соответствует принципам:
- Single Responsibility;
- Local Additive Change;
- Transport Isolation;
- Canonical Model Separation.
Кроме того,
Build 060.7 окончательно закрепляет разделение между:
- получением документа;
- обработкой документа;
- построением предметной модели.
Именно это разделение станет основой следующего этапа развития REST Trade Pipeline.
# Влияние на последующие Build
Build 060.7 завершает формирование логического слоя обработки REST Trade Document.
После его окончания все последующие компоненты Acquisition Layer могут использовать единый публичный интерфейс:
```python
adapt_rest_agg_trades_document()
```
При этом они полностью освобождаются от необходимости знать внутреннее устройство Pipeline.
Следующие Build будут работать исключительно через данный Adapter.
Это позволяет изменять внутреннюю реализацию Parser, Validation или Mapper без изменения внешнего API обработки документа.
Таким образом Adapter становится стабильной границей между верхними и нижними слоями Acquisition.
---
# Критерии завершения
Build 060.7 считается полностью завершённым, поскольку:
- проведён повторный архитектурный аудит существующего Pipeline;
- реализован отдельный REST Trade Adapter;
- определена единственная публичная точка входа обработки документа;
- сохранено разделение ответственности между Schema Validation, Parser, Value Validation и Mapper;
- Adapter не содержит собственной бизнес-логики;
- Adapter не выполняет HTTP-запросы;
- Adapter не выполняет Schema Validation;
- Adapter не изменяет порядок обработки данных;
- Adapter не сортирует сделки;
- Adapter не удаляет дубликаты;
- Adapter не агрегирует данные;
- Adapter не изменяет транспортные модели;
- Adapter не перехватывает исключения нижележащих компонентов;
- compile-проверка успешно пройдена;
- локальные unit-тесты успешно пройдены;
- полный regression suite успешно пройден;
- проверка форматирования успешно пройдена;
- scope Build не расширен.
---
# Архитектурные инварианты
После завершения Build 060.7 следующие свойства REST Trade Pipeline считаются архитектурным контрактом проекта.
Изменение любого из перечисленных инвариантов требует отдельного архитектурного решения.
---
## Инвариант 1
Schema Validation остаётся самостоятельным слоем Acquisition Pipeline.
Никакие Adapter не должны выполнять проверку структуры документа самостоятельно.
Полная последовательность всегда начинается с отдельного этапа Schema Validation.
---
## Инвариант 2
REST Trade Adapter получает только уже проверенный документ.
Тип входного параметра:
```text
ValidatedRestAggTradesDocument
```
Использование необработанного REST JSON внутри Adapter не допускается.
---
## Инвариант 3
REST Trade Adapter отвечает исключительно за композицию существующих компонентов.
Он не содержит собственной бизнес-логики.
---
## Инвариант 4
REST Trade Adapter не изменяет последовательность обработки.
Pipeline всегда имеет следующий вид:
```text
Schema Validation
Parser
Value Validation
Mapper
```
Изменение порядка выполнения данных этапов не допускается.
---
## Инвариант 5
REST Trade Adapter не перехватывает исключения нижележащих компонентов.
Ошибки каждого уровня должны сохранять собственный специализированный тип.
---
## Инвариант 6
REST Trade Adapter не создаёт предметные объекты самостоятельно.
Создание экземпляров:
```text
Trade
```
остаётся исключительной ответственностью Mapper.
---
## Инвариант 7
REST Trade Adapter не зависит от механизма получения документа.
Он не знает:
- каким способом был получен REST JSON;
- из какого HTTP-клиента он поступил;
- выполнялся ли запрос повторно;
- использовалось ли кэширование.
Эти вопросы относятся исключительно к Source Layer.
---
## Инвариант 8
Stateless-компоненты реализуются функциями.
Если компонент:
- не хранит состояние;
- не содержит конфигурации;
- не управляет жизненным циклом;
- не требует Dependency Injection;
- не реализует полиморфизм,
он должен быть реализован функцией.
---
## Инвариант 9
Stateful-компоненты реализуются классами.
Класс используется только в случаях, когда компонент:
- хранит состояние;
- управляет ресурсами;
- содержит конфигурацию;
- инкапсулирует зависимости;
- предоставляет расширяемый интерфейс.
Использование класса при отсутствии состояния считается нарушением архитектурного стиля проекта.
---
## Инвариант 10
REST Trade Adapter является единственной официальной точкой запуска полного REST Trade Pipeline.
Все последующие компоненты системы должны использовать именно его.
Самостоятельный последовательный вызов:
```text
Parser
Value Validation
Mapper
```
за пределами Adapter не допускается.
---
# Итог
**Build 060.7 завершён успешно.**
Текущее состояние REST Trade Pipeline:
```text
Transport Model — реализована
Schema Validation — реализована
Parser — реализован
Value Validation — реализована
Mapper — реализован
REST Trade Adapter — реализован
Canonical Trade — используется
Compile check — успешно
Target tests — 4 passed
Full regression suite — 1096 passed
Whitespace check — успешно
Production Integration — намеренно не выполнялась
```
После завершения Build 060.7 подсистема получения исторических сделок получила единый координационный слой обработки документа.
Вся логика преобразования REST-документа в канонические сделки теперь доступна через единый публичный интерфейс, при этом все ранее реализованные компоненты сохранили независимость и собственную архитектурную ответственность.
---
# Следующий этап
Следующим этапом развития серии Build 060 становится:
```text
Build 060.8 — REST Trades Document Source
```
На данном этапе будет реализован компонент, отвечающий исключительно за получение документа из REST API и его структурную проверку.
После завершения Build 060.8 полный REST Pipeline примет следующий вид:
```text
HTTP Client
REST API
JSON
Schema Validation
ValidatedRestAggTradesDocument
REST Trade Adapter
Parser
Value Validation
Mapper
tuple[Trade]
```
Таким образом будут окончательно разделены три независимые архитектурные области:
- получение документа;
- обработка документа;
- построение канонической модели.
После этого REST-подсистема получения сделок будет полностью подготовлена к построению **Trades Feed (Time & Sales)** и последующему объединению исторических REST-сделок с потоком WebSocket в рамках единого конвейера обработки рыночных данных.