# Build 060.22 — Acquisition Runtime Service **Статус:** Architecture Specification **Build:** 060.22 **Ветка:** Trades Feed (Time & Sales) **Документ:** `build_060_22_architecture.md` **Связанные документы:** - `build_060_21_architecture.md` — архитектурная спецификация Runtime Integration Contracts; - `build_060_21.md` — Engineering Migration Report предыдущего Build; - `build_060_20_1_architecture.md` — спецификация владения состоянием Trade Stream. --- # Назначение документа Настоящий документ является официальной архитектурной спецификацией **Build 060.22 — Acquisition Runtime Service**. Документ определяет создание первого исполняемого сервисного компонента Runtime Layer подсистемы **Market Data Acquisition**. Build 060.21 сформировал типизированную контрактную границу Runtime: ```text AcquisitionRuntimeCommand AcquisitionRuntimeEvent AcquisitionRuntimeCommandDispatcherProtocol AcquisitionRuntimeEventPublisherProtocol ``` Однако созданные контракты пока не имеют производственной реализации. В системе отсутствует компонент, который: - принимает типизированные Runtime-команды; - маршрутизирует их к соответствующим инфраструктурным зависимостям; - публикует результирующие Runtime-события; - формирует единую точку исполнения команд Acquisition Runtime. Build 060.22 закрывает именно эту архитектурную задачу. Документ служит единственным источником истины при реализации данного Build. Изменение зафиксированных решений в процессе написания кода не допускается без отдельного архитектурного пересмотра. --- # Статус Build Build 060.22 является следующим этапом серии Build 060, посвящённой формированию полноценной подсистемы **Trades Feed (Time & Sales)**. К моменту начала данного Build в проекте уже существуют: - транспортные модели WebSocket; - Runtime Commands; - Runtime Events; - WebSocket transport protocol; - WebSocket session protocol; - WebSocket subscription manager protocol; - контракт диспетчеризации Runtime-команд; - контракт публикации Runtime-событий; - Canonical Trade Model; - Trades Feed; - Trade Stream Consistency; - Trade Recovery; - специализированное хранилище `TradeStreamStateStore`. При этом Runtime Layer пока состоит только из контрактов и моделей сообщений. Фактический сервис исполнения Runtime-команд отсутствует. Следовательно, Runtime ещё не является работающей подсистемой. Build 060.22 вводит минимальную исполняемую реализацию сервисного уровня, не подключая её пока к Trades Feed и корневому Acquisition Service. --- # Контекст После завершения Build 060.21 архитектура Runtime Protocol Layer выглядит следующим образом. ```text AcquisitionRuntimeCommand │ ▼ AcquisitionRuntimeCommandDispatcherProtocol ``` и: ```text AcquisitionRuntimeEvent │ ▼ AcquisitionRuntimeEventPublisherProtocol ``` Контракты определяют: - какие команды допустимы внутри Acquisition Runtime; - какие события может публиковать Runtime; - каким образом вызывающий компонент передаёт команду; - каким образом инфраструктурный результат передаётся потребителям. Однако контракт сам по себе не выполняет команду. Например: ```text ConnectCommand ``` уже существует как типизированная команда, но в системе пока отсутствует компонент, который обязан: ```text ConnectCommand │ ▼ WebSocketSessionProtocol.start() ``` Аналогично: ```text DisconnectCommand │ ▼ WebSocketSessionProtocol.stop() ``` Для команд управления подписками и отправки сообщений также пока отсутствует единая точка исполнения. Таким образом между публичным Runtime Protocol Layer и низкоуровневыми WebSocket-контрактами остаётся незаполненная сервисная граница. --- # Предпосылки Настоящий Build опирается на архитектурные решения, принятые в предыдущих этапах. ## Build 059.10 Сформированы базовые контракты WebSocket Runtime: ```text WebSocketTransportProtocol WebSocketSessionProtocol WebSocketSubscriptionManagerProtocol ``` Данные контракты описывают отдельные инфраструктурные возможности, но не объединяют их в единый сервис исполнения команд. --- ## Build 059.11–059.12 Сформированы транспортные команды и события Runtime. Появились типизированные модели: ```text ConnectCommand DisconnectCommand SubscribeCommand UnsubscribeCommand SendTextCommand SendBinaryCommand ``` а также соответствующие инфраструктурные события. --- ## Build 060.18 Создана подсистема Trade Stream Consistency. Она полностью независима от Runtime Transport и принимает только канонические объекты `Trade`. --- ## Build 060.19 Создана подсистема Trade Recovery. Recovery остаётся stateless и зависит только от: ```text TradeStreamConsistencyProtocol ``` --- ## Build 060.20.1 Владение состоянием Trade Stream перенесено в: ```text TradeStreamStateStore ``` Runtime Transport окончательно перестал рассматриваться как владелец состояния предметной области. --- ## Build 060.21 Сформирован интеграционный контракт Runtime Protocol Layer. Добавлены: ```text AcquisitionRuntimeCommand AcquisitionRuntimeEvent AcquisitionRuntimeCommandDispatcherProtocol AcquisitionRuntimeEventPublisherProtocol ``` Имена были намеренно ограничены контекстом `Acquisition`, чтобы исключить конфликт с существующей общесистемной подсистемой: ```text src/runtime_events/ ``` Build 060.21 определил границы взаимодействия, но сознательно не создавал производственную реализацию. --- # Проблема В текущем состоянии каждая Runtime-команда является только неизменяемым объектом данных. Например: ```python ConnectCommand() ``` не содержит логики подключения. Она только выражает намерение вызывающего компонента. То же относится к: ```python DisconnectCommand() SubscribeCommand(...) UnsubscribeCommand(...) SendTextCommand(...) SendBinaryCommand(...) ``` Для выполнения команд необходим отдельный сервис, который: 1. принимает объект команды; 2. определяет его конкретный тип; 3. выбирает соответствующую инфраструктурную зависимость; 4. выполняет строго определённую операцию; 5. не содержит знаний о Trade, Consistency или Recovery. Без такого компонента Runtime Protocol Layer остаётся декларативным и не может использоваться следующими уровнями системы. --- # Основная идея Build Главная идея Build 060.22 заключается в создании тонкого сервиса маршрутизации Runtime-команд. Новый компонент: ```text AcquisitionRuntimeService ``` становится производственной реализацией: ```text AcquisitionRuntimeCommandDispatcherProtocol ``` Сервис принимает типизированную команду и делегирует выполнение уже существующим инфраструктурным контрактам. Концептуально: ```text AcquisitionRuntimeCommand │ ▼ AcquisitionRuntimeService │ ┌─────┴─────┐ ▼ ▼ WebSocket Subscription Session Manager ``` Сервис не реализует WebSocket самостоятельно. Он не содержит сетевого клиента. Он не создаёт транспорт. Он только координирует существующие зависимости. --- # Цель Build Build обязан создать единственную производственную точку исполнения типизированных Acquisition Runtime Commands. После завершения этапа система должна обеспечивать: - приём всех команд из `AcquisitionRuntimeCommand`; - детерминированную маршрутизацию каждой команды; - делегирование lifecycle-команд WebSocket Session; - делегирование управления подписками Subscription Manager; - делегирование отправки транспортных сообщений соответствующей зависимости; - соответствие `AcquisitionRuntimeCommandDispatcherProtocol`; - независимое unit-тестирование без реального сетевого соединения. Build не должен изменять поведение существующих Runtime Commands и Runtime Events. --- # Что НЕ входит в Scope Build Настоящий Build сознательно не реализует: - интеграцию Runtime Service в корневой Acquisition Service; - интеграцию Runtime Service с Trades Feed; - Composition Root; - реальный WebSocket client; - Runtime Supervisor; - Reconnect Controller; - Heartbeat; - Scheduler; - автоматическое восстановление подписок; - автоматический REST Recovery после reconnect; - обработку входящих Trade-сообщений; - публикацию Canonical Trade Stream; - регистрацию Runtime Service в Registry; - общесистемную шину событий; - конкурентную очередь команд; - фоновый worker; - сохранение Runtime-состояния между перезапусками. Эти задачи относятся к Build 060.23–060.25 либо к отдельным последующим этапам. Build 060.22 отвечает только за синхронную с точки зрения порядка и асинхронную с точки зрения Python API диспетчеризацию одной команды за один вызов. --- # Архитектурные принципы При реализации Build 060.22 используются следующие обязательные принципы. ## 1. Unique File Naming Во всём репозитории Dzentra запрещено создание нескольких файлов с одинаковым именем независимо от расположения в каталогах. Единственное разрешённое исключение: ```text __init__.py ``` Поэтому в Build не создаются файлы: ```text service.py protocol.py exceptions.py test_service.py ``` Утверждённые уникальные имена: ```text acquisition_runtime_service.py acquisition_runtime_service_protocol.py test_acquisition_runtime_service.py ``` Имя каждого файла должно однозначно определять его назначение без учёта родительского каталога. --- ## 2. Protocol Before Implementation Публичный контракт Runtime Service фиксируется отдельно от его реализации. Внешние потребители в последующих Build должны зависеть от: ```text AcquisitionRuntimeServiceProtocol ``` а не от конкретного класса: ```text AcquisitionRuntimeService ``` --- ## 3. Thin Application Service Runtime Service является тонким координатором. Он: - принимает команду; - определяет её тип; - делегирует операцию; - завершает вызов. Сервис не переносит в себя логику нижележащих компонентов. --- ## 4. No Domain Knowledge Runtime Service не должен импортировать: ```text Trade TradeStreamConsistencyProtocol TradeRecoveryProtocol TradesFeed TradeStreamStateStore ``` Он работает исключительно с транспортными командами и инфраструктурными контрактами. --- ## 5. Dependency Injection Все зависимости передаются в конструктор. Сервис не создаёт самостоятельно: - WebSocket Session; - Transport; - Subscription Manager; - Publisher; - Adapter. Создание графа зависимостей относится к Composition Root и не входит в Scope Build. --- ## 6. One Command — One Deterministic Route Каждый тип команды должен иметь ровно один допустимый маршрут исполнения. Команда не может быть обработана несколькими зависимостями одновременно, если это отдельно не определено спецификацией. --- ## 7. No Premature Orchestration Runtime Service не является Supervisor. Он не запускает фоновые задачи. Не выполняет retries. Не планирует reconnect. Не контролирует heartbeat. Перечисленные обязанности появятся в специализированных компонентах позднее. --- ## 8. Existing Contracts Remain Stable Build не изменяет публичные модели: ```text runtime_commands.py runtime_events.py transport_messages.py websocket_protocol.py ``` Если реализация обнаружит недостаточность существующего контракта, изменение должно быть отдельно согласовано до внесения в код. --- # Acquisition Runtime Service ## Назначение `AcquisitionRuntimeService` является первым исполняемым компонентом Runtime Layer. Его единственная задача — выполнение типизированных инфраструктурных Runtime-команд. Сервис не содержит собственной бизнес-логики. Он выполняет только маршрутизацию команд к уже существующим инфраструктурным зависимостям. Концептуально: ```text Runtime Command │ ▼ AcquisitionRuntimeService │ ├──────────────► WebSocketSession │ ├──────────────► WebSocketTransport │ └──────────────► SubscriptionManager ``` Таким образом сервис становится единственной производственной точкой исполнения Runtime-команд. --- # Почему появляется отдельный Service Во время проектирования были рассмотрены несколько вариантов. --- ## Вариант №1 Каждый вызывающий компонент самостоятельно выполняет команды. Например: ```text TradesFeed ↓ if ConnectCommand ↓ session.start() ``` Отклонён. Причины: - дублирование логики; - нарушение принципа единственной ответственности; - отсутствие единой точки маршрутизации. --- ## Вариант №2 Перенести выполнение команд внутрь WebSocketSession. Например: ```text session.dispatch(command) ``` Отклонён. Причины: Session начинает знать о: - Subscription; - Transport; - Runtime Commands. Тем самым нарушается разделение обязанностей. --- ## Вариант №3 Создать специализированный Runtime Service. Принят. Именно Runtime Service становится единственным компонентом, который понимает соответствие между: ```text Runtime Command ↓ Infrastructure Action ``` --- # Граница ответственности Runtime Service отвечает исключительно за выполнение Runtime-команд. Он НЕ отвечает за: - сетевой протокол; - обработку сообщений; - Consistency; - Recovery; - Trades Feed; - управление жизненным циклом приложения; - Supervisor; - Scheduler; - Heartbeat; - Reconnect. Все перечисленные обязанности принадлежат другим Build. --- # AcquisitionRuntimeServiceProtocol ## Назначение Build 060.22 вводит отдельный публичный контракт сервисного уровня. ```text AcquisitionRuntimeServiceProtocol ``` Он описывает единственную публичную возможность Runtime Service. ```python dispatch(...) ``` Все последующие Build должны зависеть именно от данного Protocol. Конкретная реализация может изменяться без влияния на потребителей. --- # Почему вводится отдельный Protocol На первый взгляд может показаться, что уже существует: ```text AcquisitionRuntimeCommandDispatcherProtocol ``` Однако данный Protocol описывает инфраструктурную возможность диспетчеризации команд. Он не определяет существование самостоятельного сервисного компонента. Build 060.22 впервые вводит именно сервисный уровень Runtime. Поэтому появляется отдельный сервисный контракт. Это позволяет в будущем заменить реализацию Runtime Service без изменения Composition Root и вышестоящих компонентов. --- # Публичный API Сервис предоставляет только один публичный метод. ```python async def dispatch( command: AcquisitionRuntimeCommand, ) -> None ``` Других публичных методов Build 060.22 не вводит. В частности отсутствуют: ```python connect() disconnect() subscribe() unsubscribe() send() ``` Все операции выражаются исключительно через типизированные команды. --- # Почему отсутствуют отдельные методы Во время проектирования рассматривалась следующая модель. ```python runtime.connect() runtime.disconnect() runtime.subscribe(...) ``` Она была отклонена. Причина: типизированные Runtime Commands уже являются официальным языком взаимодействия Runtime Layer. Создание второго API привело бы к существованию двух независимых способов выполнения одной и той же операции. Архитектура должна содержать единственный публичный механизм. --- # Зависимости Runtime Service Сервис получает все зависимости через Dependency Injection. Минимальный набор зависимостей выглядит следующим образом. ```text AcquisitionRuntimeService │ ├────────► WebSocketSessionProtocol │ ├────────► WebSocketTransportProtocol │ ├────────► WebSocketSubscriptionManagerProtocol │ └────────► AcquisitionRuntimeEventPublisherProtocol ``` Никакие другие зависимости Build 060.22 не предусматривает. --- # Почему внедряется Event Publisher Хотя Build 060.22 ещё не реализует полноценную публикацию Runtime-событий, сервис уже принимает зависимость: ```text AcquisitionRuntimeEventPublisherProtocol ``` Это принципиальное архитектурное решение. Причины: - исключается изменение конструктора в следующих Build; - Runtime Service сразу проектируется как источник инфраструктурных событий; - интеграция публикации становится локальным изменением без перестройки графа зависимостей. На данном этапе Publisher допускается не использовать. --- # Почему внедряется WebSocketTransportProtocol Большинство текущих операций выполняются через: ```text WebSocketSessionProtocol ``` Однако команды: ```text SendTextCommand SendBinaryCommand ``` относятся к транспортному уровню. Поэтому Runtime Service сразу получает доступ к Transport. Это предотвращает последующее изменение конструктора. --- # Маршрутизация команд Главной обязанностью Runtime Service является детерминированная маршрутизация. Каждый тип команды имеет ровно один маршрут исполнения. --- ## ConnectCommand ```text ConnectCommand ↓ WebSocketSession.start() ``` После успешного завершения управление возвращается вызывающему компоненту. Сам Runtime Service не создаёт сетевое соединение. --- ## DisconnectCommand ```text DisconnectCommand ↓ WebSocketSession.stop() ``` Сервис не закрывает транспорт напрямую. Эта ответственность принадлежит Session. --- ## SubscribeCommand ```text SubscribeCommand ↓ WebSocketSubscriptionManager.subscribe() ``` Runtime Service не хранит список активных подписок. Он лишь делегирует выполнение соответствующему компоненту. --- ## UnsubscribeCommand ```text UnsubscribeCommand ↓ WebSocketSubscriptionManager.unsubscribe() ``` После завершения операции Runtime Service не изменяет собственного состояния. --- ## SendTextCommand ```text SendTextCommand ↓ WebSocketTransport.send_text() ``` Передаваемое сообщение считается полностью сформированным. Runtime Service не сериализует полезную нагрузку повторно. --- ## SendBinaryCommand ```text SendBinaryCommand ↓ WebSocketTransport.send_binary() ``` Команда делегируется транспортному уровню без каких-либо преобразований. --- # Официальная матрица маршрутизации | Runtime Command | Исполнитель | |-----------------|-------------| | ConnectCommand | WebSocketSessionProtocol | | DisconnectCommand | WebSocketSessionProtocol | | SubscribeCommand | WebSocketSubscriptionManagerProtocol | | UnsubscribeCommand | WebSocketSubscriptionManagerProtocol | | SendTextCommand | WebSocketTransportProtocol | | SendBinaryCommand | WebSocketTransportProtocol | Данная таблица считается официальной спецификацией Build 060.22. Любое изменение маршрутов требует отдельного архитектурного решения (ADR). --- # Детерминированность маршрутизации Runtime Service рассматривается как детерминированный маршрутизатор. Для каждого входящего объекта существует единственный допустимый маршрут. Формально: ```text Runtime Command ↓ Dispatch Table ↓ Infrastructure Operation ``` Никакие дополнительные проверки, эвристики или выбор стратегии Build 060.22 не предусматривает. --- # Обработка неизвестной команды Build 060.22 не допускает существование неизвестных Runtime-команд. Если в сервис поступает объект, не входящий в объединение: ```text AcquisitionRuntimeCommand ``` это считается внутренней архитектурной ошибкой. В таком случае сервис обязан немедленно завершить выполнение исключением. Это гарантирует, что добавление новой команды никогда не останется незамеченным и потребует явного обновления таблицы маршрутизации. --- # Диаграмма взаимодействия После реализации Build 060.22 выполнение Runtime-команд приобретает следующий вид. ```text Caller │ │ dispatch(command) ▼ AcquisitionRuntimeService │ ├──────────────► WebSocketSessionProtocol │ ├──────────────► WebSocketTransportProtocol │ ├──────────────► WebSocketSubscriptionManagerProtocol │ └──────────────► AcquisitionRuntimeEventPublisherProtocol ``` Важно отметить, что Runtime Service остаётся полностью синхронным с точки зрения архитектуры. Он: - не создаёт фоновых задач; - не ставит команды в очередь; - не выполняет повторные попытки; - не содержит собственного event loop. Каждый вызов `dispatch()` завершается только после завершения соответствующей инфраструктурной операции. --- # Жизненный цикл Runtime Service Runtime Service является долгоживущим инфраструктурным сервисом. Типичный жизненный цикл выглядит следующим образом. ```text Composition Root ↓ создание зависимостей ↓ создание Runtime Service ↓ передача Runtime Service вызывающим компонентам ↓ многократные вызовы dispatch() ↓ завершение приложения ``` Сам Runtime Service не требует отдельной инициализации. Также отсутствуют методы: ```python start() stop() shutdown() dispose() ``` Экземпляр полностью готов к работе сразу после создания. --- # Отношение к состоянию Runtime Service является stateless-компонентом. Он не хранит: - состояние подключения; - список подписок; - очередь сообщений; - информацию о последней выполненной команде; - счётчики reconnect; - состояние Recovery; - состояние Consistency. Все перечисленные данные принадлежат специализированным компонентам. Следовательно экземпляр Runtime Service можно считать чистым координатором. --- # Обработка исключений Build 060.22 сознательно не вводит собственую иерархию исключений. Причина проста. Runtime Service не принимает самостоятельных решений. Он лишь вызывает инфраструктурные зависимости. Следовательно любые исключения должны передаваться вызывающему компоненту без изменения. Например: ```text Caller ↓ Runtime Service ↓ WebSocket Session ↓ ConnectionError ``` Исключение должно пройти обратно без обёртки. Это сохраняет прозрачность поведения системы. --- # Почему исключения не преобразуются Во время проектирования рассматривался вариант создания: ```text RuntimeDispatchError ``` Он был отклонён. Причины: - потеря информации о первичном исключении; - необходимость лишнего уровня обработки; - усложнение диагностики; - нарушение принципа прозрачной инфраструктуры. Runtime Service не должен скрывать происхождение ошибки. --- # Влияние на существующую архитектуру Build 060.22 практически не изменяет существующую систему. Новый сервис располагается между контрактами Runtime и инфраструктурными зависимостями. До Build: ```text Runtime Commands ↓ (нет реализации) ``` После Build: ```text Runtime Commands ↓ AcquisitionRuntimeService ↓ Infrastructure ``` Никакие другие подсистемы не изменяются. --- # Влияние на Trade Stream Consistency Подсистема: ```text Trade Stream Consistency ``` не получает никаких новых зависимостей. Она продолжает работать исключительно с: ```text Trade ``` и ```text TradeStreamConsistencyProtocol ``` Build 060.22 не создаёт прямой связи между Runtime и Consistency. --- # Влияние на Trade Recovery Trade Recovery также не изменяется. Контроллер восстановления по-прежнему зависит только от: ```text TradeStreamConsistencyProtocol ``` Runtime Service не импортирует Recovery. Recovery не импортирует Runtime Service. Архитектурная независимость сохраняется полностью. --- # Влияние на Trades Feed На данном этапе Trades Feed ещё не использует Runtime Service. Интеграция будет выполнена отдельным Build: ```text 060.23 ``` Это позволяет протестировать Runtime Service изолированно. --- # План изменения структуры проекта Build добавляет только два новых файла. ```text runtime/ ├── acquisition_runtime_service.py └── acquisition_runtime_service_protocol.py ``` Также добавляется один файл тестов. ```text tests/ runtime/ └── test_acquisition_runtime_service.py ``` Другие файлы Runtime Build 060.22 не изменяет. --- # Почему используется отдельный Protocol Наличие собственного: ```text AcquisitionRuntimeServiceProtocol ``` позволяет в будущем заменить реализацию. Например: ```text Simple Runtime Service ↓ Queued Runtime Service ↓ Distributed Runtime Service ``` Все перечисленные варианты смогут реализовывать один и тот же публичный контракт. Поэтому вышестоящие компоненты не будут зависеть от конкретного класса. --- # Стратегия тестирования Build 060.22 покрывается исключительно Unit Test. Никакие интеграционные тесты пока не требуются. Каждая Runtime-команда проверяется отдельно. Минимальный набор сценариев включает: - соответствие `AcquisitionRuntimeServiceProtocol`; - корректную маршрутизацию `ConnectCommand`; - корректную маршрутизацию `DisconnectCommand`; - корректную маршрутизацию `SubscribeCommand`; - корректную маршрутизацию `UnsubscribeCommand`; - корректную маршрутизацию `SendTextCommand`; - корректную маршрутизацию `SendBinaryCommand`; - отсутствие побочных эффектов; - прозрачное распространение исключений; - отсутствие собственного состояния между вызовами. Все зависимости заменяются простыми Fake-реализациями. Использование реального WebSocket Build 060.22 запрещает. --- # ADR (Architecture Decision Record) ## ADR-060.22-01 **Решение** Создать специализированный сервис: ```text AcquisitionRuntimeService ``` реализующий выполнение всех типизированных Runtime-команд. **Статус** Accepted. --- ## ADR-060.22-02 **Решение** Ввести отдельный публичный контракт: ```text AcquisitionRuntimeServiceProtocol ``` независимо от уже существующего: ```text AcquisitionRuntimeCommandDispatcherProtocol ``` **Статус** Accepted. --- ## ADR-060.22-03 **Решение** Runtime Service остаётся stateless. **Статус** Accepted. --- ## ADR-060.22-04 **Решение** Все зависимости передаются исключительно через Dependency Injection. **Статус** Accepted. --- ## ADR-060.22-05 **Решение** Не создавать новых файлов с именами: ```text service.py protocol.py test_service.py ``` Использовать только уникальные имена файлов. **Статус** Accepted. --- # Definition of Done Build считается завершённым только при выполнении всех условий. Обязательно должны существовать: - `acquisition_runtime_service_protocol.py`; - `acquisition_runtime_service.py`; - `test_acquisition_runtime_service.py`. Runtime Service обязан: - реализовывать `AcquisitionRuntimeServiceProtocol`; - принимать зависимости через конструктор; - поддерживать все типы `AcquisitionRuntimeCommand`; - выполнять детерминированную маршрутизацию; - не хранить собственного состояния; - не создавать зависимости самостоятельно; - прозрачно распространять исключения. Все новые Unit Test должны успешно проходить. Build не должен изменять поведение существующих Runtime Commands, Runtime Events, Trade Recovery и Trade Stream Consistency. --- # Следующий Build После завершения Build 060.22 архитектура Runtime впервые получит полноценный исполняемый сервисный слой. Следующим этапом станет: ```text Build 060.23 Acquisition Integration ``` На этом этапе `AcquisitionRuntimeService` будет интегрирован в подсистему получения рыночных данных и станет использоваться как единая точка исполнения инфраструктурных Runtime-команд. После Build 060.23 Runtime перестанет существовать только как набор контрактов и сервисов и начнёт участвовать в реальном конвейере получения данных от биржи.