Skip to content

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/.