Тема
ADR: Source-client crate boundaries — pm-sdk as the single source client
Status
Accepted — ратифицировано оператором 2026-06-13. Обосновано read-only scouting (openspec/changes/consolidate-source-client-boundaries/scouting-report.md); все ключевые код-факты верифицированы прямым чтением репозитория.
Контекст
pm-bot (отлаженный) и pm-engine (чистая переписка) — необъявленный bake-off одной стратегии. Чтобы судить только логику стратегии, слой данных/IO должен быть общим, а strategy-input — идентичным by construction. Это требует ответа: какой crate ЕСТЬ единый клиент ко всем источникам. Сейчас источнико-производный домен (orderbook-сборка) осел в pm-common, размывая роль pm-sdk.
Решение
Расширить pm-sdk как единый source-client. Граница определяется направлением зависимости, а не «statefulness»:
- ✅ Легально только pm-sdk → pm-common (
pm-sdk/Cargo.toml:65+ cycle-break комментарий; обратногоuse pm_sdkв pm-common нет). Всё, что импортит чистый код pm-common, не может уехать в pm-sdk без цикла. - В pm-sdk переезжает
OrderbookStore(stateful-аккумулятор WS/REST-merge) + provenance-кластер (CachedOrderBook/Source/PriceChange) + materialization- конструкторыfrom_cached/neg_risk::inverted— решение MAXIMAL (приоритет чистой доменной зоны + прозрачность трассировки/тестов). - В pm-common остаётся чистый домен:
BookView/BookFreshness,invariants,pricing(✅ Decimal-only),reconciliation(✅ pure-over-snapshot; runtime уже в pm-bot),RestBookSnapshot(cycle:compare.rs:21его импортит),modelsи пр. pm-market-dataНЕ воскрешать (архивирован 2026-05-02 осознанно; KISS).- Source-нормализация уже в pm-sdk (
parsers.rs/ws/market/parse/gamma) — no-op.
Acceptance-инвариант (CI)
Первой проверкой — grep направления зависимости: нет pm_sdk import в pm-common. Литеральный «no HTTP/WS/RPC» вторичен — реальный режим отказа это reverse-edge через RestBookSnapshot/compare.
Последствия
- Миграция поведение-сохраняющая (golden «до == после» на ~13 потребителей); это перемещение существующего кода, НЕ выбор канона реализации (тот — в
shared-external-io-channelпо ground-truth). - Cycle pre-req: вынести
RestBookSnapshotизstore.rsв отдельный pm-common types-модуль ДО переносаOrderbookStore. - Разблокирует общий I/O-канал (живёт в pm-sdk) → фундамент для bake-off.
Обратимость
Внутренняя структура crate, не wire/data-контракт → обратимо. Полная проработка и задачи — openspec/changes/consolidate-source-client-boundaries/.