Skip to content

Uncertainty:0.09

ИСТОРИЧЕСКИЙ ДОКУМЕНТ. Это прежняя инструкция аудита коллектора для Backtest. После отказа от replay, runtime simulation и standalone capture 2026-08-22 она не является текущей спецификацией или процедурой проверки. Реальная торговая телеметрия, включая полную трассировку ордеров, описана в docs/target/observability.md и openspec/specs/.

Ниже — рабочая инструкция аудита Rust-системы сбора истории Polymarket из WS / RTDS / CLOB / REST для дальнейшего backtest.

Документ рассчитан на то, что аудитор имеет доступ к репозиторию, .env.example, конфигам, тестовой БД, логам и может запускать код локально.


Технический аудит Polymarket History Collector на Rust ​

0. Цель аудита ​

Проверить, что система:

  1. Корректно получает данные из всех заявленных источников:

    • Polymarket WebSocket market/user/sports channels;
    • RTDS;
    • CLOB REST;
    • Gamma/Data API, если используются как reference/source-of-truth.
  2. Корректно нормализует данные:

    • market id;
    • condition id;
    • token id;
    • outcome;
    • side;
    • price;
    • size;
    • timestamp;
    • sequence/update id, если есть;
    • source;
    • latency metadata.
  3. Корректно пишет историю:

    • без потерь;
    • без неконтролируемых дублей;
    • с воспроизводимым порядком событий;
    • с возможностью построить backtest без look-ahead bias.
  4. Корректно восстанавливается после:

    • reconnect;
    • пропуска сообщений;
    • rate limiting;
    • schema drift;
    • деградации одного из источников;
    • частичного отказа БД.
  5. Имеет доказуемое покрытие тестами, property-тестами, интеграционными тестами и reconciliation-проверками.


1. Важные внешние предположения ​

Перед аудитом код сверяется с актуальной документацией Polymarket.

На момент проверки Polymarket документирует WebSocket-каналы для near-real-time orderbook/trade/user activity, включая market, user, sports и RTDS. RTDS используется для streaming comments, crypto/equity prices и работает через wss://ws-live-data.polymarket.com; часть user-specific потоков может требовать gamma_auth. (docs.polymarket.com)

Gamma API, Data API и read-only CLOB endpoints публичные и не требуют authentication; CLOB trading endpoints требуют authentication. Для исторического сборщика это важно: read-only market-data paths и authenticated trading paths не должны смешиваться в collector runtime. (docs.polymarket.com)

CLOB у Polymarket — hybrid-decentralized: off-chain order matching и on-chain settlement. Это означает, что аудит должен отдельно проверять off-chain market data, on-chain activity/settlement и их reconciliation, а не считать один источник полностью достаточным. (docs.polymarket.com)

Для market discovery официальная документация рекомендует использовать Gamma events/markets, включая active=true&closed=false, pagination через limit/offset, а также tag filtering. CLOB предоставляет read endpoints для price, prices, book, books, midpoint, spread и prices-history. (docs.polymarket.com)

API rate limits у Polymarket проходят через Cloudflare throttling, то есть превышение лимитов может проявляться как задержка/очередь, а не только как явный отказ. Аудит должен проверять latency, timeout, retry и backpressure, а не только HTTP status. (docs.polymarket.com)

Отдельно учесть, что в changelog указано: CLOB V2 live on production с 2026-04-28. Аудит должен проверить, что код не завязан на устаревшие V1-форматы, endpoints, SDK semantics или несовместимые assumptions. (docs.polymarket.com)


2. Цикл аудита ​

Аудит проводится по одинаковому циклу для каждого компонента:

text
1. Найти релевантный модуль.
2. Сформулировать expected behavior.
3. Найти фактическое поведение в коде.
4. Проверить тестами / логами / synthetic input.
5. Сравнить с внешней документацией и внутренними invariants.
6. Зафиксировать проблему, если поведение не доказано.
7. Предложить минимальный план исправления.
8. Добавить regression test proposal.

Запрещено считать компонент корректным только потому, что "код выглядит правильно". Корректность должна быть подтверждена одним из способов:

text
- unit test;
- integration test;
- replay test;
- property-based test;
- deterministic fixture;
- reconciliation query;
- production log sample;
- database invariant query;
- explicit proof from code path.

3. Обязательный формат отчёта по каждой найденной проблеме ​

Каждая проблема должна быть оформлена так:

markdown
## ISSUE-NNN: <краткое название>

Severity: Critical | High | Medium | Low
Component: ws | rtds | clob | discovery | normalizer | db | backtest | config | observability | ops
Status: Confirmed | Suspected | Needs reproduction

### Summary
Краткое описание проблемы.

### Evidence
- Файл:
- Функция:
- Строки:
- Лог / тест / SQL / fixture:
- Как воспроизвести:

### Expected behavior
Что должно происходить.

### Actual behavior
Что происходит сейчас.

### Impact
Чем это опасно для backtest / PnL-модели / completeness / correctness.

### Root cause hypothesis
Вероятная причина.

### Fix plan
1.
2.
3.

### Regression test
Какой тест должен гарантировать, что проблема не вернётся.

### Backfill / data repair required
Yes | No | Unknown

### Confidence
0.00–1.00

4. Severity model ​

Critical ​

Проблема делает историю непригодной для backtest или создаёт скрытый look-ahead bias.

Примеры:

text
- потеря WS-сообщений без обнаружения;
- неправильный timestamp, из-за которого события оказываются в будущем/прошлом;
- перепутаны token_id/outcome;
- price/size пишутся с неправильной точностью;
- reconnect делает silent gap;
- snapshot применён после delta без ordering check;
- CLOB book собирается неконсистентно;
- дедупликация удаляет реальные события;
- backtest использует данные, которые на тот момент ещё не были доступны.

High ​

Проблема искажает PnL, liquidity, fill simulation или eligibility рынков.

text
- нет надёжного reconciliation между WS и REST snapshot;
- market discovery пропускает активные рынки;
- rate limit приводит к silent stale state;
- не хранится source timestamp;
- нет versioning схемы;
- replay недетерминированный.

Medium ​

Проблема снижает надёжность, но не всегда портит данные.

text
- недостаточные метрики;
- слабие retry limits;
- нет алерта на reconnect storm;
- не покрыты edge cases;
- нет fixtures для schema drift.

Low ​

Качество, читаемость, minor observability.


5. Карта компонентов для аудита ​

Аудит начинается с построения карты репозитория.

5.1 Найти entrypoints ​

Команды:

bash
find . -maxdepth 3 -type f \( -name "main.rs" -o -name "lib.rs" -o -name "mod.rs" \)
find . -maxdepth 4 -type f \( -name "*.rs" -o -name "*.toml" -o -name "*.sql" -o -name "*.yaml" -o -name "*.yml" -o -name ".env.example" \)

Составить таблицу:

markdown
| Component | Path | Responsibility | External deps | Writes DB | Reads network | Test coverage |
|---|---|---|---|---|---|---|

5.2 Найти все network clients ​

Искать:

bash
rg -n "reqwest|tokio_tungstenite|tungstenite|websocket|wss://|https://|gamma|clob|polymarket|rtds|ws-live-data|prices-history|book|books|midpoint|spread"

Проверить:

text
- где создаётся HTTP client;
- где создаётся WS client;
- есть ли timeout;
- есть ли retry;
- есть ли backoff;
- есть ли rate limit;
- есть ли circuit breaker;
- есть ли per-source metrics;
- есть ли request id / correlation id;
- логируется ли endpoint без секретов;
- не захардкожены ли production/staging endpoints.

5.3 Найти все database writes ​

Искать:

bash
rg -n "INSERT|UPDATE|UPSERT|ON CONFLICT|COPY|execute|query|sqlx|diesel|sea_orm|postgres|sqlite|clickhouse|timescale"

Проверить:

text
- какие таблицы пишутся;
- какие уникальные ключи;
- какие индексы;
- как работает idempotency;
- есть ли transaction boundary;
- есть ли batch insert;
- что происходит при partial failure;
- как обрабатываются duplicate events;
- как пишутся timestamps;
- есть ли raw payload archive.

6. Аудит конфигурации ​

6.1 .env / config schema ​

Проверить наличие и корректность:

text
POLYMARKET_CLOB_BASE_URL
POLYMARKET_GAMMA_BASE_URL
POLYMARKET_DATA_BASE_URL
POLYMARKET_WS_URL
POLYMARKET_RTDS_WS_URL
DATABASE_URL
RUST_LOG
COLLECTOR_MARKET_FILTERS
COLLECTOR_TAG_FILTERS
COLLECTOR_RECONNECT_MIN_MS
COLLECTOR_RECONNECT_MAX_MS
COLLECTOR_HTTP_TIMEOUT_MS
COLLECTOR_WS_PING_INTERVAL_MS
COLLECTOR_SNAPSHOT_INTERVAL_MS
COLLECTOR_BACKFILL_ENABLED

Если используются другие имена — описать фактические.

6.2 Проверки ​

text
[ ] Нет обязательных config values без validation.        R-CFG-REQUIRED-VALIDATED
[ ] Нет silently default-to-production поведения.         R-CFG-NO-SILENT-DEFAULT-PROD
[ ] Нет секретов в логах.                                 R-CFG-NO-SECRETS-IN-LOGS
[ ] Можно явно выбрать staging/prod.                      R-CFG-EXPLICIT-ENV-SELECT
[ ] Невалидный URL даёт fail-fast.                        R-CFG-INVALID-URL-FAIL-FAST
[ ] Невалидный market filter даёт fail-fast.              R-CFG-INVALID-FILTER-FAIL-FAST
[ ] Все durations парсятся безопасно.                     R-CFG-DURATIONS-SAFE-PARSE
[ ] Все числовые лимиты имеют min/max validation.         R-CFG-NUMERIC-MINMAX
[ ] Config dump на старте маскирует sensitive values.     R-CFG-DUMP-MASKS-SECRETS

6.3 Дефекты, которые нужно искать специально ​

text
- unwrap()/expect() на env vars;                          R-CFG-DEFECT-UNWRAP-ON-ENV
- default timeout = infinite;                             R-CFG-DEFECT-INFINITE-TIMEOUT
- hardcoded endpoint;                                     R-CFG-DEFECT-HARDCODED-ENDPOINT
- разные endpoint versions в разных модулях;              R-CFG-DEFECT-MIXED-ENDPOINT-VERSIONS
- mixed staging/prod;                                     R-CFG-DEFECT-MIXED-ENV
- silent fallback на пустой market list;                  R-CFG-DEFECT-SILENT-EMPTY-MARKET-FALLBACK
- отсутствие schema version в config.                     R-CFG-DEFECT-NO-SCHEMA-VERSION

7. Аудит market discovery ​

Market discovery — критический компонент, потому что неполный universe рынков делает backtest смещённым.

7.1 Expected behavior ​

Collector должен уметь:

text
1. Получить список активных рынков.                                    R-DISC-FETCH-ACTIVE
2. Получить markets внутри events.                                     R-DISC-FETCH-MARKETS-IN-EVENTS
3. Обработать pagination.                                              R-DISC-PAGINATION
4. Применить фильтры tag/category/slug/active/closed.                  R-DISC-FILTERS-APPLIED
5. Извлечь:                                                            R-DISC-EXTRACT-FIELDS
   - event_id;
   - market_id;
   - condition_id;
   - question;
   - slug;
   - outcomes;
   - token_ids;
   - end_date;
   - resolution source;
   - active/closed/archived flags;
   - neg-risk/group metadata, если используется.
6. Обновлять metadata при изменениях.                                  R-DISC-METADATA-REFRESHED
7. Не терять рынки при временной ошибке Gamma API.                     R-DISC-NO-LOSS-ON-TRANSIENT-ERROR

7.2 Checklist ​

text
[ ] Используется pagination, а не только первый page.              R-DISC-PAGINATION-USED
[ ] offset/limit цикл завершается корректно.                       R-DISC-PAGINATION-TERMINATES
[ ] Есть защита от infinite pagination loop.                       R-DISC-PAGINATION-NO-INFINITE-LOOP
[ ] active/closed фильтры соответствуют ожидаемой стратегии.       R-DISC-FILTERS-MATCH-STRATEGY
[ ] closed markets не теряются, если нужны для historical backfill.R-DISC-CLOSED-RETAINED-FOR-BACKFILL
[ ] tag filtering не исключает related рынки случайно.             R-DISC-TAG-FILTER-NO-OVER-EXCLUSION
[ ] token_ids соответствуют outcomes по индексу.                   R-DISC-TOKEN-OUTCOME-INDEX-ALIGNED
[ ] condition_id не путается с market_id.                          R-DISC-CONDITION-NOT-MARKET
[ ] slug не используется как единственный immutable id.            R-DISC-SLUG-NOT-SOLE-ID
[ ] market metadata версионируется.                                R-DISC-METADATA-VERSIONED
[ ] end_date/start_date парсятся с timezone.                       R-DISC-DATES-WITH-TZ
[ ] resolved/closed рынки корректно переходят в terminal state.    R-DISC-TERMINAL-STATE
[ ] delisted/archived markets обрабатываются явно.                 R-DISC-ARCHIVED-HANDLED
[ ] unsupported market types логируются, а не silently ignored.    R-DISC-UNSUPPORTED-LOGGED

7.3 Тесты ​

Fixtures для проверки:

text
- single binary market;                       R-DISC-FIXTURE-BINARY
- multi-outcome market;                       R-DISC-FIXTURE-MULTI-OUTCOME
- neg-risk event;                             R-DISC-FIXTURE-NEG-RISK
- market без token_ids;                       R-DISC-FIXTURE-NO-TOKEN-IDS
- market с переставленными outcomes;          R-DISC-FIXTURE-REORDERED-OUTCOMES
- closed market;                              R-DISC-FIXTURE-CLOSED
- active market;                              R-DISC-FIXTURE-ACTIVE
- market с missing end_date;                  R-DISC-FIXTURE-MISSING-END-DATE
- market с unusual decimal price;             R-DISC-FIXTURE-UNUSUAL-DECIMAL
- paginated response на 3 страницы;           R-DISC-FIXTURE-PAGINATED-3
- response с duplicate market.                R-DISC-FIXTURE-DUPLICATE-MARKET

Минимальный тест — R-DISC-TEST-PRESERVE-OUTCOME-TOKEN-ALIGNMENT:

rust
#[test]
fn discovery_preserves_outcome_token_alignment() {
    // Given Gamma market with outcomes ["Yes", "No"] and token_ids ["111", "222"]
    // When normalized
    // Then outcome "Yes" maps to token_id "111", "No" maps to token_id "222"
}

8. Аудит CLOB REST snapshots ​

8.1 Что проверять ​

CLOB REST используется как reference для:

text
- initial order book snapshot;                            R-CLOB-PURPOSE-INITIAL-SNAPSHOT
- periodic reconciliation;                                R-CLOB-PURPOSE-RECONCILIATION
- price/midpoint/spread sanity checks;                    R-CLOB-PURPOSE-SANITY-CHECK
- gap recovery after WS reconnect;                        R-CLOB-PURPOSE-GAP-RECOVERY
- historical price sanity, если используется prices-history. R-CLOB-PURPOSE-HISTORY-SANITY

8.2 Checklist ​

text
[ ] Для каждого subscribed token_id есть initial snapshot.      R-CLOB-SNAPSHOT-PER-TOKEN
[ ] Snapshot timestamp сохраняется отдельно от ingest timestamp.R-CLOB-SNAPSHOT-TS-SEPARATE
[ ] bids/asks сортируются правильно.                            R-CLOB-LEVELS-SORTED
[ ] best_bid <= best_ask invariant проверяется.                 R-CLOB-BBO-INVARIANT-CHECKED
[ ] Цена хранится как Decimal / fixed-point, не f64.            R-CLOB-DEC-PRICE-NO-F64
[ ] Size хранится как Decimal / fixed-point, не f64.            R-CLOB-DEC-SIZE-NO-F64
[ ] Пустой стакан допустим и обрабатывается явно.               R-CLOB-EMPTY-BOOK-HANDLED
[ ] Snapshot не перетирает более свежие deltas.                 R-CLOB-SNAPSHOT-NO-OVERWRITE-FRESH-DELTA
[ ] Snapshot имеет source = clob_rest_snapshot.                 R-CLOB-SNAPSHOT-SOURCE-TAGGED
[ ] REST timeout конечный.                                      R-CLOB-TIMEOUT-FINITE
[ ] Retry ограничен.                                            R-CLOB-RETRY-BOUNDED
[ ] Backoff с jitter.                                           R-CLOB-BACKOFF-JITTER
[ ] Rate limiting не превращается в silent stale book.          R-CLOB-RATE-LIMIT-NO-STALE-BOOK
[ ] HTTP 429/5xx/Cloudflare throttling логируются отдельно.     R-CLOB-THROTTLING-DISTINCT-LOG
[ ] Есть per-endpoint latency histogram.                        R-CLOB-LATENCY-HISTOGRAM
[ ] Есть sanity check между /book, /midpoint и /spread.         R-CLOB-CROSS-ENDPOINT-SANITY

8.3 Инварианты order book ​

Для каждого token_id:

R-CLOB-INV-BBO-NOT-CROSSED ​

Best bid не должен быть выше best ask.

sql
SELECT token_id, ts
FROM orderbook_best
WHERE best_bid_price > best_ask_price;

R-CLOB-INV-PRICE-BOUNDED ​

Цена должна быть в диапазоне [0, 1].

sql
SELECT *
FROM orderbook_levels
WHERE price < 0 OR price > 1;

R-CLOB-INV-SIZE-NON-NEGATIVE ​

Размер на уровне не может быть отрицательным.

sql
SELECT *
FROM orderbook_levels
WHERE size < 0;

R-CLOB-INV-NO-DUPLICATE-LEVEL ​

Duplicate active level после нормализации недопустим.

sql
SELECT token_id, side, price, ts, COUNT(*)
FROM orderbook_levels
GROUP BY token_id, side, price, ts
HAVING COUNT(*) > 1;

8.4 Специальная проверка precision ​

Поиск всех мест, где используются float-типы — R-CLOB-DEC-GREP-FLOATS:

bash
rg -n "f32|f64|as f|parse::<f|Decimal|rust_decimal|BigDecimal|fixed"

Критично:

text
- price не должен проходить через f64 до записи;                    R-CLOB-DEC-PRICE-NO-F64-PATH
- size не должен проходить через f64 до записи;                     R-CLOB-DEC-SIZE-NO-F64-PATH
- PnL/backtest не должен использовать binary floating point для денег; R-CLOB-DEC-NO-BINARY-FLOAT-MONEY
- JSON numeric/string formats должны парситься предсказуемо.        R-CLOB-DEC-JSON-DETERMINISTIC-PARSE

Рекомендуемый стандарт:

text
price: Decimal scale 6 или integer микродоллары/микроценты;         R-CLOB-DEC-STANDARD-PRICE
size: Decimal scale 6 или выше;                                     R-CLOB-DEC-STANDARD-SIZE
notional: Decimal;                                                  R-CLOB-DEC-STANDARD-NOTIONAL
timestamps: i64 nanoseconds/microseconds + original source timestamp. R-CLOB-DEC-STANDARD-TIMESTAMPS

9. Аудит WebSocket market channel ​

9.1 Expected behavior ​

WS collector должен:

text
1. Подключиться.                                                R-WS-CONNECT
2. Подписаться на нужные markets/token_ids.                     R-WS-SUBSCRIBE
3. Получить snapshot или дождаться внешнего REST snapshot.      R-WS-SNAPSHOT-BOOTSTRAP
4. Применять incremental updates в правильном порядке.          R-WS-ORDER-PRESERVATION
5. Обнаруживать gap/stale stream.                               R-WS-GAP-DETECT
6. Reconnect with backoff.                                      R-WS-RECONNECT-BACKOFF
7. После reconnect делать resync.                               R-WS-RESYNC-AFTER-RECONNECT
8. Писать raw events и normalized events.                       R-WS-DUAL-RAW-AND-NORMALIZED
9. Не блокировать receive loop на DB writes.                    R-WS-NONBLOCKING-RECEIVE

9.2 Checklist ​

text
[ ] Subscribe payload соответствует актуальной документации.    R-WS-SUBSCRIBE-PAYLOAD-CURRENT
[ ] Все token_ids из discovery реально подписываются.           R-WS-SUBSCRIBE-COVERS-DISCOVERY
[ ] Есть лимит размера subscription batch.                      R-WS-SUBSCRIBE-BATCH-LIMIT
[ ] Большие universe разбиваются на shards.                     R-WS-SUBSCRIBE-SHARDED-LARGE-UNIVERSE
[ ] Receive loop не содержит тяжёлых sync операций.             R-WS-RECEIVE-LOOP-NO-HEAVY-SYNC
[ ] Parsing error не убивает весь процесс без restart policy.   R-WS-PARSE-ERROR-RESTART-POLICY
[ ] Unknown message type сохраняется в raw payload или dead-letter. R-WS-UNKNOWN-MSG-RAW-OR-DEADLETTER
[ ] Ping/pong реализован.                                       R-WS-PING-PONG
[ ] Idle timeout реализован.                                    R-WS-IDLE-TIMEOUT
[ ] Reconnect exponential backoff с cap.                        R-WS-RECONNECT-EXPBACKOFF-CAP
[ ] Reconnect storm защищён.                                    R-WS-RECONNECT-STORM-PROTECT
[ ] После reconnect выполняется REST resnapshot.                R-WS-RESNAPSHOT-AFTER-RECONNECT
[ ] Есть gap marker в БД.                                       R-WS-GAP-MARKER-DB
[ ] Есть stream session id.                                     R-WS-STREAM-SESSION-ID
[ ] Есть monotonic ingest sequence.                             R-WS-MONOTONIC-INGEST-SEQ
[ ] Есть source_receive_ts.                                     R-WS-SOURCE-RECEIVE-TS
[ ] Есть normalized_event_ts.                                   R-WS-NORMALIZED-EVENT-TS
[ ] Есть raw payload hash.                                      R-WS-RAW-PAYLOAD-HASH
[ ] Есть dedup key.                                             R-WS-DEDUP-KEY

9.3 Нельзя допускать ​

text
- применять delta к неизвестному snapshot;                      R-WS-NO-DELTA-BEFORE-SNAPSHOT
- применять события после reconnect без resync;                 R-WS-NO-EVENTS-AFTER-RECONNECT-WITHOUT-RESYNC
- считать local receive time временем market event;             R-WS-NO-RECEIVE-AS-EVENT-TIME
- удалять unknown fields;                                       R-WS-NO-FIELD-STRIPPING
- silently skip malformed messages;                             R-WS-NO-SILENT-MALFORMED-SKIP
- хранить только final book без event log;                      R-WS-NO-BOOK-WITHOUT-EVENT-LOG
- делать backtest по book state, собранному после reorder без отметки uncertainty. R-WS-NO-REORDER-WITHOUT-UNCERTAINTY-MARK

9.4 Reconnect audit ​

Должны быть покрыты сценарии:

text
1.  WS disconnect.                              R-WS-RECONNECT-CASE-DISCONNECT
2.  Half-open connection.                       R-WS-RECONNECT-CASE-HALF-OPEN
3.  Ping timeout.                               R-WS-RECONNECT-CASE-PING-TIMEOUT
4.  Server sends malformed message.             R-WS-RECONNECT-CASE-MALFORMED
5.  Network pause 30s.                          R-WS-RECONNECT-CASE-NET-PAUSE
6.  DB unavailable 10s.                         R-WS-RECONNECT-CASE-DB-UNAVAIL
7.  Collector receives burst after reconnect.   R-WS-RECONNECT-CASE-BURST
8.  Subscription rejected.                      R-WS-RECONNECT-CASE-SUB-REJECTED
9.  Partial subscription success.               R-WS-RECONNECT-CASE-PARTIAL-SUB
10. Token removed/market closed.                R-WS-RECONNECT-CASE-TOKEN-REMOVED

Для каждого сценария аудит подтверждает:

text
[ ] событие залогировано;                       R-WS-RECONNECT-EVIDENCE-LOGGED
[ ] метрика увеличилась;                        R-WS-RECONNECT-EVIDENCE-METRIC
[ ] состояние source стало degraded/recovering; R-WS-RECONNECT-EVIDENCE-DEGRADED-STATE
[ ] после восстановления сделан snapshot;       R-WS-RECONNECT-EVIDENCE-POST-RESNAPSHOT
[ ] в БД есть gap/recovery marker;              R-WS-RECONNECT-EVIDENCE-GAP-MARKER
[ ] backtest может исключить или пометить этот интервал. R-WS-RECONNECT-EVIDENCE-BACKTEST-EXCLUDABLE

10. Аудит RTDS ​

RTDS нельзя смешивать с CLOB orderbook data. Это отдельный realtime stream, который может содержать comments, crypto/equity prices и другие live-data темы. В документации RTDS имеет отдельный endpoint и subscription model. (docs.polymarket.com)

10.1 Checklist ​

text
[ ] RTDS endpoint отделён от CLOB WS endpoint.                  R-RTDS-ENDPOINT-SEPARATE
[ ] RTDS topics явно перечислены в config.                      R-RTDS-TOPICS-IN-CONFIG
[ ] RTDS message types явно типизированы.                       R-RTDS-MSG-TYPES-TYPED
[ ] filters валидируются.                                       R-RTDS-FILTERS-VALIDATED
[ ] gamma_auth используется только где требуется.               R-RTDS-AUTH-ONLY-WHERE-REQUIRED
[ ] comments не смешиваются с trades.                           R-RTDS-COMMENTS-NOT-MIXED-WITH-TRADES
[ ] external prices не смешиваются с Polymarket prices.         R-RTDS-EXT-PRICES-SEPARATE
[ ] is_carried_forward сохраняется, если поле присутствует.     R-RTDS-CARRIED-FORWARD-PRESERVED
[ ] stale ticks не используются как live signal.                R-RTDS-NO-STALE-AS-LIVE
[ ] RTDS source timestamp сохраняется.                          R-RTDS-SOURCE-TS-SAVED
[ ] RTDS ingest latency измеряется.                             R-RTDS-LATENCY-MEASURED
[ ] Unknown RTDS topics идут в dead-letter.                     R-RTDS-UNKNOWN-TOPIC-DEADLETTER

10.2 Специальная проверка stale data ​

Для external prices:

text
[ ] Есть поле live/stale/carried_forward.                       R-RTDS-FRESHNESS-FIELD-EXISTS
[ ] Backtest не использует carried_forward tick как новое рыночное изменение. R-RTDS-BACKTEST-NO-CARRIED-AS-LIVE
[ ] Есть отдельный флаг freshness.                              R-RTDS-FRESHNESS-FLAG
[ ] Есть max_age_ms для использования сигнала.                  R-RTDS-MAX-AGE-MS

R-RTDS-INV-NO-CARRIED-AS-LIVE-SIGNAL ​

Если такой query возвращает строки — это потенциальный Critical/High defect.

sql
SELECT *
FROM rtds_ticks
WHERE is_carried_forward = true
  AND used_as_live_signal = true;

11. Аудит trade/activity ingestion ​

Если система собирает trades/activity через Data API или WS:

11.1 Checklist ​

text
[ ] Trade id / transaction id / order id сохраняются.           R-TRADE-IDS-PRESERVED
[ ] side нормализуется однозначно.                              R-TRADE-SIDE-NORMALIZED
[ ] maker/taker, если есть, не теряются.                        R-TRADE-MAKER-TAKER-PRESERVED
[ ] price/size/notional точные.                                 R-TRADE-PRICE-SIZE-NOTIONAL-PRECISE
[ ] token_id связан с market/outcome.                           R-TRADE-TOKEN-LINKED-TO-MARKET
[ ] transaction hash, если есть, сохраняется отдельно.          R-TRADE-TX-HASH-SEPARATE
[ ] on-chain timestamp не смешивается с off-chain execution timestamp. R-TRADE-ONCHAIN-OFFCHAIN-TS-SEPARATE
[ ] activity types явно перечислены.                            R-TRADE-ACTIVITY-TYPES-ENUM
[ ] SPLIT/MERGE/REDEEM/CONVERSION не классифицируются как обычный TRADE. R-TRADE-NON-TRADE-NOT-CLASSIFIED-AS-TRADE
[ ] Duplicate activity не создаёт fake volume.                  R-TRADE-DUPLICATE-NO-FAKE-VOLUME
[ ] Late-arriving activity не ломает ordering.                  R-TRADE-LATE-DOES-NOT-BREAK-ORDERING

11.2 Проверка semantic correctness ​

Поиск enum/model для activity type — R-TRADE-GREP-ACTIVITY-ENUM:

bash
rg -n "TRADE|SPLIT|MERGE|REDEEM|REWARD|CONVERSION|MAKER_REBATE|activity|trade_type"

Проверить:

text
[ ] Unknown type не падает.                                     R-TRADE-UNKNOWN-NO-PANIC
[ ] Unknown type не мапится в TRADE по default.                 R-TRADE-UNKNOWN-NOT-DEFAULT-TRADE
[ ] Все типы имеют raw representation.                          R-TRADE-RAW-REPRESENTATION
[ ] Backtest может фильтровать non-trade activity.              R-TRADE-BACKTEST-FILTER-NON-TRADE

12. Аудит нормализации данных ​

12.1 Canonical entities ​

Должны существовать canonical model для:

text
Event                R-NORM-MODEL-EVENT
Market               R-NORM-MODEL-MARKET
Outcome              R-NORM-MODEL-OUTCOME
Token                R-NORM-MODEL-TOKEN
OrderBookSnapshot    R-NORM-MODEL-ORDERBOOK-SNAPSHOT
OrderBookDelta       R-NORM-MODEL-ORDERBOOK-DELTA
Trade                R-NORM-MODEL-TRADE
Activity             R-NORM-MODEL-ACTIVITY
RTDSTick             R-NORM-MODEL-RTDS-TICK
SourceSession        R-NORM-MODEL-SOURCE-SESSION
IngestionGap         R-NORM-MODEL-INGESTION-GAP
RawPayload           R-NORM-MODEL-RAW-PAYLOAD

Если модели размазаны по коду — зафиксировать как архитектурный риск (R-NORM-MODELS-NOT-SCATTERED).

12.2 Обязательные поля normalized event ​

Для каждого market-data event:

text
event_id/internal_id      R-NORM-FIELD-EVENT-ID
source                    R-NORM-FIELD-SOURCE
source_session_id         R-NORM-FIELD-SOURCE-SESSION-ID
source_sequence nullable  R-NORM-FIELD-SOURCE-SEQUENCE
source_ts nullable        R-NORM-FIELD-SOURCE-TS
receive_ts                R-NORM-FIELD-RECEIVE-TS
ingest_ts                 R-NORM-FIELD-INGEST-TS
market_id nullable        R-NORM-FIELD-MARKET-ID
condition_id nullable     R-NORM-FIELD-CONDITION-ID
token_id nullable         R-NORM-FIELD-TOKEN-ID
outcome nullable          R-NORM-FIELD-OUTCOME
event_type                R-NORM-FIELD-EVENT-TYPE
price nullable            R-NORM-FIELD-PRICE
size nullable             R-NORM-FIELD-SIZE
side nullable             R-NORM-FIELD-SIDE
raw_payload_hash          R-NORM-FIELD-RAW-PAYLOAD-HASH
schema_version            R-NORM-FIELD-SCHEMA-VERSION
normalizer_version        R-NORM-FIELD-NORMALIZER-VERSION

12.3 Checklist ​

text
[ ] Нормализация deterministic.                                 R-NORM-DETERMINISTIC
[ ] Raw payload сохраняется или доступен через hash/archive.    R-NORM-RAW-PAYLOAD-ACCESSIBLE
[ ] Нет lossy преобразования важных полей.                      R-NORM-NO-LOSSY-IMPORTANT-FIELDS
[ ] Все nullable поля осознанны.                                R-NORM-NULLABLE-INTENTIONAL
[ ] Ошибки нормализации идут в dead-letter.                     R-NORM-ERRORS-TO-DEADLETTER
[ ] Dead-letter имеет причину ошибки.                           R-NORM-DEADLETTER-HAS-REASON
[ ] Schema version пишется в каждую запись или batch.           R-NORM-SCHEMA-VERSION-STAMPED
[ ] Normalizer version фиксируется.                             R-NORM-NORMALIZER-VERSION-STAMPED
[ ] Migration меняет version.                                   R-NORM-MIGRATION-BUMPS-VERSION
[ ] Старые события можно replay через текущий или legacy normalizer. R-NORM-LEGACY-REPLAYABLE

13. Аудит timestamp model ​

Это один из самых критичных блоков.

13.1 Обязательные timestamps ​

Система должна различать:

text
source_ts        — время события по источнику, если есть;        R-TS-SOURCE-TS-EXISTS
receive_ts       — время получения collector'ом;                  R-TS-RECEIVE-TS-EXISTS
ingest_ts        — время записи/commit в БД;                      R-TS-INGEST-TS-EXISTS
snapshot_ts      — время получения REST snapshot;                 R-TS-SNAPSHOT-TS-EXISTS
exchange_ts      — если источник даёт exchange/server timestamp;  R-TS-EXCHANGE-TS-EXISTS
chain_ts         — если событие on-chain;                         R-TS-CHAIN-TS-EXISTS
backtest_visible_ts — earliest timestamp, когда событие можно использовать в симуляции. R-TS-VISIBLE-TS-EXISTS

13.2 Checklist ​

text
[ ] Все timestamps хранятся в UTC или явно с timezone.            R-TS-UTC-OR-EXPLICIT-TZ
[ ] Нет naive local datetime.                                     R-TS-NO-NAIVE-LOCAL
[ ] Нет смешивания seconds/ms/us/ns.                              R-TS-CONSISTENT-UNITS
[ ] Все timestamp units проверены тестами.                        R-TS-UNITS-TESTED
[ ] receive_ts берётся максимально близко к network receive.      R-TS-RECEIVE-NEAR-NETWORK
[ ] ingest_ts не используется как market event time.              R-TS-INGEST-NOT-AS-EVENT-TIME
[ ] backtest использует visible_ts, а не source_ts blindly.       R-TS-BACKTEST-USES-VISIBLE
[ ] Есть latency = receive_ts - source_ts, если source_ts есть.   R-TS-LATENCY-COMPUTED
[ ] Negative latency алертится.                                   R-TS-NEGATIVE-LATENCY-ALERT
[ ] Clock skew мониторится.                                       R-TS-CLOCK-SKEW-MONITORED

13.3 SQL-инварианты ​

R-TS-RECEIVE-NOT-BEFORE-SOURCE ​

receive_ts не должен быть сильно раньше source_ts.

sql
SELECT *
FROM normalized_events
WHERE source_ts IS NOT NULL
  AND receive_ts < source_ts - INTERVAL '5 seconds';

R-TS-INGEST-NOT-BEFORE-RECEIVE ​

ingest_ts не должен быть раньше receive_ts.

sql
SELECT *
FROM normalized_events
WHERE ingest_ts < receive_ts;

R-TS-NO-FUTURE-TIMESTAMPS ​

Подозрительные timestamps из будущего.

sql
SELECT *
FROM normalized_events
WHERE source_ts > NOW() + INTERVAL '60 seconds'
   OR receive_ts > NOW() + INTERVAL '60 seconds';

14. Аудит database schema ​

14.1 Checklist ​

text
[ ] Есть migrations.                                              R-DB-MIGRATIONS-EXIST
[ ] Migrations применяются в CI.                                  R-DB-MIGRATIONS-IN-CI
[ ] Нет ручного drift между schema и models.                      R-DB-NO-SCHEMA-MODEL-DRIFT
[ ] Primary keys стабильные.                                      R-DB-STABLE-PRIMARY-KEYS
[ ] Unique constraints отражают idempotency.                      R-DB-UNIQUE-REFLECTS-IDEM
[ ] Индексы покрывают backtest queries.                           R-DB-INDEXES-COVER-BACKTEST
[ ] Raw payload таблица не раздувает hot path.                    R-DB-RAW-NOT-ON-HOT-PATH
[ ] Partitioning/retention продуманы.                             R-DB-PARTITION-RETENTION
[ ] Insert path выдерживает burst.                                R-DB-INSERT-BURST-OK
[ ] Batch insert атомарен или имеет recovery.                     R-DB-BATCH-ATOMIC-OR-RECOVERABLE
[ ] Dead-letter таблица есть.                                     R-DB-DEADLETTER-TABLE
[ ] Gap/recovery таблица есть.                                    R-DB-GAP-TABLE
[ ] Source sessions таблица есть.                                 R-DB-SOURCE-SESSIONS-TABLE
[ ] Schema version фиксируется.                                   R-DB-SCHEMA-VERSION-RECORDED

14.2 Минимальный набор таблиц ​

Отсутствие любой таблицы фиксируется как gap:

text
source_sessions          R-DB-TABLE-SOURCE-SESSIONS
raw_payloads             R-DB-TABLE-RAW-PAYLOADS
normalized_events        R-DB-TABLE-NORMALIZED-EVENTS
markets                  R-DB-TABLE-MARKETS
market_versions          R-DB-TABLE-MARKET-VERSIONS
tokens                   R-DB-TABLE-TOKENS
orderbook_snapshots      R-DB-TABLE-ORDERBOOK-SNAPSHOTS
orderbook_levels         R-DB-TABLE-ORDERBOOK-LEVELS
orderbook_deltas         R-DB-TABLE-ORDERBOOK-DELTAS
trades                   R-DB-TABLE-TRADES
activities               R-DB-TABLE-ACTIVITIES
rtds_ticks               R-DB-TABLE-RTDS-TICKS
ingestion_gaps           R-DB-TABLE-INGESTION-GAPS
dead_letters             R-DB-TABLE-DEAD-LETTERS
collector_health         R-DB-TABLE-COLLECTOR-HEALTH

14.3 Idempotency keys ​

Ключи не должны быть слишком широкими и не слишком узкими.

Примеры:

text
raw_payload:                                                      R-DB-IDEM-RAW-PAYLOAD
  source + source_session_id + receive_seq
  или source + raw_hash + receive_ts_bucket

trade:                                                            R-DB-IDEM-TRADE
  source + trade_id
  или tx_hash + log_index
  или market_id + token_id + price + size + source_ts + participant/order ids, если trade_id нет

orderbook_delta:                                                  R-DB-IDEM-ORDERBOOK-DELTA
  source + source_session_id + source_sequence
  если sequence нет:
    source + token_id + side + price + size + source_ts + raw_hash

snapshot:                                                         R-DB-IDEM-SNAPSHOT
  source + token_id + snapshot_ts + raw_hash

Если dedup key основан только на token_id + price + size + timestamp — это риск: реальные разные события могут схлопнуться (R-DB-IDEM-NO-NARROW-DEDUP-KEY).


15. Аудит ordering и replay ​

15.1 Цель ​

Backtest должен воспроизводить состояние рынка на любой момент времени без неявного использования будущей информации.

15.2 Checklist ​

text
[ ] Есть append-only event log.                                   R-ORD-APPEND-ONLY-LOG
[ ] Event log можно replay deterministic.                         R-ORD-REPLAY-DETERMINISTIC
[ ] Replay результат совпадает с materialized book.               R-ORD-REPLAY-MATCHES-MATERIALIZED
[ ] События сортируются по visible_ts + ingest_sequence, а не только source_ts. R-ORD-SORT-VISIBLE-PLUS-SEQ
[ ] При равном timestamp есть tie-breaker.                        R-ORD-TIE-BREAKER
[ ] Gaps представлены явно.                                       R-ORD-GAPS-EXPLICIT
[ ] После gap book state помечается uncertain до resnapshot.      R-ORD-POST-GAP-UNCERTAIN
[ ] Snapshot/delta ordering формализован.                         R-ORD-SNAPSHOT-DELTA-FORMALIZED
[ ] Late events не переписывают историю без versioning.           R-ORD-LATE-NO-DESTRUCTIVE-REWRITE
[ ] Corrections пишутся append-only, не destructive update.       R-ORD-CORRECTIONS-APPEND-ONLY

15.3 Replay test ​

Обязательный тест — R-ORD-REPLAY-TEST:

text
Input:
1. REST snapshot at T0.
2. Delta A at T1.
3. Delta B at T2.
4. Reconnect gap at T3.
5. REST snapshot at T4.
6. Delta C at T5.

Expected:
- book valid from T0 to T3;
- interval T3–T4 marked uncertain;
- after T4 book valid again;
- Delta C applies to post-resnapshot book.

16. Аудит backtest-readiness ​

16.1 Проверить, что история содержит достаточно данных ​

Для realistic backtest нужны:

text
- best bid/ask history;                                          R-BT-DATA-BBO-HISTORY
- depth levels, если стратегия зависит от fill probability;      R-BT-DATA-DEPTH-LEVELS
- trades history;                                                R-BT-DATA-TRADES-HISTORY
- market metadata history;                                       R-BT-DATA-METADATA-HISTORY
- liquidity/spread history;                                      R-BT-DATA-LIQ-SPREAD-HISTORY
- source gaps;                                                   R-BT-DATA-SOURCE-GAPS
- stale markers;                                                 R-BT-DATA-STALE-MARKERS
- latency;                                                       R-BT-DATA-LATENCY
- eligibility state at time T;                                   R-BT-DATA-ELIGIBILITY-STATE
- resolution/closed state;                                       R-BT-DATA-RESOLUTION-STATE
- fees/slippage assumptions separately versioned.                R-BT-DATA-FEES-VERSIONED

16.2 Checklist ​

text
[ ] Backtest не использует current market metadata для прошлого. R-BT-LA-NO-FUTURE-METADATA
[ ] Market eligibility пересчитывается исторически.              R-BT-LA-ELIGIBILITY-RECOMPUTED
[ ] Исторические tags/category изменения учтены или frozen.      R-BT-LA-TAGS-FROZEN-OR-VERSIONED
[ ] Closed/resolved outcome не виден до времени resolution.      R-BT-LA-OUTCOME-HIDDEN-UNTIL-RESOLUTION
[ ] Resolution source/final result не попадает в signal features до публикации. R-BT-LA-RESOLUTION-NOT-IN-SIGNAL
[ ] Orderbook после reconnect gap не используется как continuous truth. R-BT-LA-BOOK-AFTER-GAP-NOT-CONTINUOUS
[ ] Fill simulation использует доступную на тот момент depth.    R-BT-LA-FILL-SIM-HISTORICAL-DEPTH
[ ] События сортируются по visible_ts.                           R-BT-LA-EVENTS-SORTED-BY-VISIBLE-TS
[ ] Есть data_quality_score по market/time interval.             R-BT-DATA-QUALITY-SCORE

16.3 Look-ahead bias checks ​

Искать в коде backtest:

bash
# R-BT-LA-GREP-FUTURE-REFERENCES
rg -n "now\\(|Utc::now|SystemTime::now|latest|current|resolved|closed|winner|outcome|final|end_date|resolution"

Подозрительно:

text
- использовать current closed/resolved status при симуляции прошлого; R-BT-LA-NO-CURRENT-STATUS-IN-PAST
- использовать final winning outcome до resolution;                   R-BT-LA-NO-FINAL-OUTCOME-PRE-RESOLUTION
- использовать final market metadata вместо versioned metadata;       R-BT-LA-NO-FINAL-METADATA
- фильтровать markets по сегодняшней liquidity для прошлого периода;  R-BT-LA-NO-CURRENT-LIQUIDITY-FILTER
- использовать complete dataset для выбора markets без historical availability cutoff. R-BT-LA-HISTORICAL-AVAILABILITY-CUTOFF

17. Аудит observability ​

17.1 Обязательные метрики ​

text
collector_ws_connected{source}                       R-OBS-METRIC-WS-CONNECTED
collector_ws_reconnect_total{source}                 R-OBS-METRIC-WS-RECONNECT-TOTAL
collector_ws_message_total{source,type}              R-OBS-METRIC-WS-MESSAGE-TOTAL
collector_ws_parse_error_total{source,type}          R-OBS-METRIC-WS-PARSE-ERROR-TOTAL
collector_ws_unknown_message_total{source}           R-OBS-METRIC-WS-UNKNOWN-MESSAGE-TOTAL
collector_http_request_total{endpoint,status}        R-OBS-METRIC-HTTP-REQUEST-TOTAL
collector_http_latency_ms{endpoint}                  R-OBS-METRIC-HTTP-LATENCY
collector_http_timeout_total{endpoint}               R-OBS-METRIC-HTTP-TIMEOUT-TOTAL
collector_db_insert_total{table}                     R-OBS-METRIC-DB-INSERT-TOTAL
collector_db_insert_error_total{table}               R-OBS-METRIC-DB-INSERT-ERROR-TOTAL
collector_db_insert_latency_ms{table}                R-OBS-METRIC-DB-INSERT-LATENCY
collector_dead_letter_total{source,reason}           R-OBS-METRIC-DEAD-LETTER-TOTAL
collector_gap_total{source,market}                   R-OBS-METRIC-GAP-TOTAL
collector_snapshot_total{source}                     R-OBS-METRIC-SNAPSHOT-TOTAL
collector_reconciliation_mismatch_total{source}      R-OBS-METRIC-RECONCILIATION-MISMATCH-TOTAL
collector_event_lag_ms{source}                       R-OBS-METRIC-EVENT-LAG
collector_queue_depth{name}                          R-OBS-METRIC-QUEUE-DEPTH
collector_dropped_event_total{source,reason}         R-OBS-METRIC-DROPPED-EVENT-TOTAL

17.2 Checklist ​

text
[ ] Logs structured JSON.                                         R-OBS-LOGS-STRUCTURED-JSON
[ ] Есть correlation id.                                          R-OBS-CORRELATION-ID
[ ] Есть source_session_id.                                       R-OBS-SOURCE-SESSION-ID
[ ] Ошибки содержат source, market_id/token_id, endpoint.         R-OBS-ERROR-CONTEXT
[ ] Нет секретов в логах.                                         R-OBS-NO-SECRETS-IN-LOGS
[ ] Есть health endpoint или health command.                      R-OBS-HEALTH-ENDPOINT
[ ] Есть readiness/liveness separation.                           R-OBS-READINESS-LIVENESS
[ ] Есть dashboards или хотя бы metric names.                     R-OBS-DASHBOARDS
[ ] Есть alert thresholds.                                        R-OBS-ALERT-THRESHOLDS

17.3 Минимальные алерты ​

text
- WS disconnected > 30s.                                          R-OBS-ALERT-WS-DISCONNECTED
- Reconnect count > N за 5 минут.                                 R-OBS-ALERT-RECONNECT-COUNT
- Dead-letter rate > 0.1%.                                        R-OBS-ALERT-DEAD-LETTER-RATE
- DB insert errors > 0.                                           R-OBS-ALERT-DB-INSERT-ERRORS
- Event lag p95 > заданного SLA.                                  R-OBS-ALERT-EVENT-LAG
- Snapshot reconciliation mismatch > 0.                           R-OBS-ALERT-RECONCILIATION-MISMATCH
- No messages for active subscription > X секунд.                 R-OBS-ALERT-SUBSCRIPTION-SILENT
- Queue depth растёт > Y минут.                                   R-OBS-ALERT-QUEUE-DEPTH-RISING
- Unknown schema/message type появился.                           R-OBS-ALERT-UNKNOWN-SCHEMA

18. Аудит performance и backpressure ​

18.1 Rust async checklist ​

text
[ ] Receive loop не блокируется sync DB write.                    R-PERF-RECEIVE-NONBLOCKING
[ ] Используется bounded channel.                                 R-PERF-BOUNDED-CHANNEL
[ ] Backpressure policy явная.                                    R-PERF-EXPLICIT-BACKPRESSURE
[ ] Нет unbounded memory growth.                                  R-PERF-NO-UNBOUNDED-MEMORY
[ ] CPU-heavy normalization вынесена из hot receive path.         R-PERF-CPU-HEAVY-OFF-HOT-PATH
[ ] Batch writer имеет flush by size/time.                        R-PERF-BATCH-FLUSH-SIZE-TIME
[ ] На shutdown выполняется drain.                                R-PERF-SHUTDOWN-DRAIN
[ ] Есть graceful shutdown signal handling.                       R-PERF-GRACEFUL-SHUTDOWN
[ ] JoinHandles awaited.                                          R-PERF-JOINHANDLES-AWAITED
[ ] Ошибки task не теряются.                                      R-PERF-TASK-ERRORS-NOT-LOST
[ ] Panic в child task приводит к controlled restart/fail-fast.   R-PERF-PANIC-CONTROLLED

Поиск async-опасностей — R-PERF-GREP-ASYNC-HAZARDS:

bash
rg -n "spawn|tokio::spawn|mpsc::unbounded|unbounded_channel|Mutex|RwLock|block_on|std::thread::sleep|tokio::time::sleep|unwrap\\(|expect\\("

18.2 Load test ​

Synthetic load сценарии:

text
- 1 market / 2 token_ids / low traffic;                           R-PERF-LOAD-1-MARKET
- 100 markets / 200 token_ids;                                    R-PERF-LOAD-100-MARKETS
- 1,000 token_ids synthetic messages;                             R-PERF-LOAD-1K-TOKENS
- burst 10,000 messages за 10 секунд;                             R-PERF-LOAD-BURST-10K
- DB pause 5 секунд;                                              R-PERF-LOAD-DB-PAUSE
- network reconnect loop;                                         R-PERF-LOAD-RECONNECT-LOOP
- malformed 1% messages.                                          R-PERF-LOAD-MALFORMED-1PCT

Метрики:

text
- dropped events;                                                 R-PERF-LOAD-METRIC-DROPPED
- p50/p95/p99 receive-to-insert latency;                          R-PERF-LOAD-METRIC-LATENCY
- queue depth;                                                    R-PERF-LOAD-METRIC-QUEUE-DEPTH
- memory;                                                         R-PERF-LOAD-METRIC-MEMORY
- CPU;                                                            R-PERF-LOAD-METRIC-CPU
- DB batch size;                                                  R-PERF-LOAD-METRIC-BATCH-SIZE
- reconnect recovery time.                                        R-PERF-LOAD-METRIC-RECONNECT-RECOVERY

19. Аудит error handling ​

19.1 Checklist ​

text
[ ] Нет unwrap/expect в runtime path.                             R-ERR-NO-UNWRAP-RUNTIME
[ ] Ошибки типизированы.                                          R-ERR-TYPED
[ ] Ошибки имеют context.                                         R-ERR-WITH-CONTEXT
[ ] Network errors отделены от parse errors.                      R-ERR-NETWORK-PARSE-SEPARATE
[ ] DB errors отделены от constraint conflicts.                   R-ERR-DB-CONSTRAINT-SEPARATE
[ ] Constraint conflict может быть нормальной дедупликацией.      R-ERR-CONSTRAINT-AS-DEDUP
[ ] Fatal/non-fatal errors классифицированы.                      R-ERR-FATAL-CLASSIFIED
[ ] Unknown schema не приводит к silent skip.                     R-ERR-UNKNOWN-SCHEMA-NO-SKIP
[ ] Retry не бесконечный без backoff.                             R-ERR-RETRY-BOUNDED
[ ] После max retries состояние source = failed/degraded.         R-ERR-MAX-RETRY-DEGRADED

Поиск опасных паттернов — R-ERR-GREP-HAZARDS:

bash
rg -n "unwrap\\(|expect\\(|panic!|todo!|unimplemented!|\\.ok\\(\\)|let _ =|ignore|TODO|FIXME"

Особенно опасно — R-ERR-NO-IGNORED-SEND:

rust
let _ = sender.send(event);

Если send failed игнорируется — возможна silent data loss.


20. Аудит reconciliation ​

20.1 WS vs REST snapshot ​

Для каждого token_id:

text
1. Собрать WS book state.                                         R-RECON-COLLECT-WS-STATE
2. Периодически взять REST /book.                                 R-RECON-PERIODIC-REST-BOOK
3. Сравнить top N levels.                                         R-RECON-COMPARE-TOP-N
4. Если mismatch:                                                 R-RECON-ON-MISMATCH
   - записать mismatch event;
   - пометить interval uncertain;
   - resync book;
   - сохранить оба состояния для анализа.

20.2 Checklist ​

text
[ ] Reconciliation есть.                                          R-RECON-EXISTS
[ ] Частота reconciliation configurable.                          R-RECON-FREQUENCY-CONFIGURABLE
[ ] Сравнивается не только best bid/ask, но и depth N.            R-RECON-DEPTH-N-COMPARED
[ ] Decimal comparison учитывает scale/tick size.                 R-RECON-DECIMAL-AWARE-COMPARE
[ ] Mismatch не игнорируется.                                     R-RECON-MISMATCH-NOT-IGNORED
[ ] Есть threshold по size dust.                                  R-RECON-SIZE-DUST-THRESHOLD
[ ] Есть automatic resync.                                        R-RECON-AUTO-RESYNC
[ ] Есть audit trail.                                             R-RECON-AUDIT-TRAIL

20.3 SQL для mismatch ​

R-RECON-INV-RECENT-MISMATCHES ​

sql
SELECT *
FROM reconciliation_mismatches
WHERE created_at >= NOW() - INTERVAL '24 hours'
ORDER BY created_at DESC;

21. Аудит schema drift ​

Polymarket может менять поля/форматы. Аудит должен проверить устойчивость к schema drift.

21.1 Checklist ​

text
[ ] Serde models используют deny_unknown_fields только там, где это безопасно. R-SCHEMA-DENY-UNKNOWN-SCOPED
[ ] Unknown fields могут сохраняться в raw.                       R-SCHEMA-UNKNOWN-FIELDS-RAW-SAVED
[ ] Missing optional fields обрабатываются.                       R-SCHEMA-MISSING-OPTIONAL-HANDLED
[ ] Required fields валидируются.                                 R-SCHEMA-REQUIRED-VALIDATED
[ ] Unknown enum variants поддерживаются.                         R-SCHEMA-UNKNOWN-ENUM-SUPPORTED
[ ] Есть schema snapshot fixtures.                                R-SCHEMA-SNAPSHOT-FIXTURES
[ ] Есть тесты на старые и новые payloads.                        R-SCHEMA-OLD-AND-NEW-PAYLOAD-TESTS
[ ] Changelog/API docs проверяются перед релизом.                 R-SCHEMA-CHANGELOG-PRE-RELEASE

21.2 Тестовые payloads ​

Fixtures для проверки устойчивости:

text
- payload с extra field;                                          R-SCHEMA-FIXTURE-EXTRA-FIELD
- payload без optional field;                                     R-SCHEMA-FIXTURE-NO-OPTIONAL
- payload с unknown enum value;                                   R-SCHEMA-FIXTURE-UNKNOWN-ENUM
- payload с null вместо string;                                   R-SCHEMA-FIXTURE-NULL-INSTEAD-STRING
- payload с numeric string;                                       R-SCHEMA-FIXTURE-NUMERIC-STRING
- payload с number вместо string;                                 R-SCHEMA-FIXTURE-NUMBER-INSTEAD-STRING
- payload с пустым array;                                         R-SCHEMA-FIXTURE-EMPTY-ARRAY
- payload с огромным orderbook;                                   R-SCHEMA-FIXTURE-HUGE-ORDERBOOK
- payload с duplicate levels.                                     R-SCHEMA-FIXTURE-DUPLICATE-LEVELS

22. Аудит безопасности ​

Даже read-only collector может утечь secrets или повредить данные.

22.1 Checklist ​

text
[ ] Private keys/API keys не нужны для read-only collector.       R-SEC-NO-KEYS-FOR-READONLY
[ ] Если auth используется — secrets не логируются.               R-SEC-AUTH-SECRETS-NOT-LOGGED
[ ] .env не коммитится.                                           R-SEC-ENV-NOT-COMMITTED
[ ] Config dump маскирует secrets.                                R-SEC-CONFIG-DUMP-MASKED
[ ] DB credentials не попадают в panic/error.                     R-SEC-DB-CREDS-NOT-IN-PANIC
[ ] Dependency audit выполняется.                                 R-SEC-DEPENDENCY-AUDIT
[ ] TLS verification не отключён.                                 R-SEC-TLS-VERIFY-ENABLED
[ ] Нет accept_invalid_certs.                                     R-SEC-NO-INVALID-CERTS
[ ] Нет произвольной загрузки URL из внешних данных.              R-SEC-NO-DYNAMIC-URL-LOAD
[ ] Raw payload storage не создаёт injection-risk в downstream tools. R-SEC-RAW-PAYLOAD-NO-INJECTION

Поиск secret-leak паттернов — R-SEC-GREP-SECRETS:

bash
rg -n "PRIVATE|SECRET|KEY|TOKEN|PASSWORD|accept_invalid|danger|insecure|tls|Authorization|POLY_"

23. Аудит dependency и supply chain ​

Команды:

bash
cargo tree
cargo audit
cargo deny check
cargo outdated
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
cargo fmt --check

Если cargo audit или cargo deny не настроены — зафиксировать Medium issue (R-DEP-AUDIT-AND-DENY-CONFIGURED).

Проверить:

text
[ ] Cargo.lock committed.                                         R-DEP-CARGO-LOCK-COMMITTED
[ ] Нет git dependencies без pinned revision.                     R-DEP-GIT-DEPS-PINNED
[ ] Нет wildcard versions.                                        R-DEP-NO-WILDCARD-VERSIONS
[ ] Нет deprecated crates в hot path.                             R-DEP-NO-DEPRECATED-HOT-PATH
[ ] TLS/HTTP/WebSocket crates актуальны.                          R-DEP-TLS-HTTP-WS-CURRENT
[ ] Decimal/time crates устойчивы.                                R-DEP-DECIMAL-TIME-STABLE

24. Аудит CI/CD ​

24.1 Checklist ​

text
[ ] CI запускает fmt.                                             R-CI-FMT
[ ] CI запускает clippy.                                          R-CI-CLIPPY
[ ] CI запускает unit tests.                                      R-CI-UNIT-TESTS
[ ] CI запускает integration tests с test DB.                     R-CI-INTEGRATION-TESTS
[ ] CI применяет migrations на clean DB.                          R-CI-MIGRATIONS-ON-CLEAN-DB
[ ] CI запускает property tests хотя бы smoke.                    R-CI-PROPERTY-TESTS-SMOKE
[ ] CI проверяет cargo audit/deny.                                R-CI-CARGO-AUDIT-DENY
[ ] CI собирает release build.                                    R-CI-RELEASE-BUILD
[ ] CI не требует production secrets.                             R-CI-NO-PROD-SECRETS
[ ] Есть reproducible test fixtures.                              R-CI-REPRODUCIBLE-FIXTURES

24.2 Release gates ​

Релиз collector нельзя считать безопасным, если не проходят:

text
- discovery pagination test;                                      R-CI-GATE-DISCOVERY-PAGINATION
- timestamp unit test;                                            R-CI-GATE-TIMESTAMP-UNIT
- price precision test;                                           R-CI-GATE-PRICE-PRECISION
- WS reconnect/resnapshot test;                                   R-CI-GATE-WS-RECONNECT-RESNAPSHOT
- DB idempotency test;                                            R-CI-GATE-DB-IDEMPOTENCY
- replay determinism test;                                        R-CI-GATE-REPLAY-DETERMINISM
- backtest look-ahead guard test;                                 R-CI-GATE-BT-LOOKAHEAD
- reconciliation mismatch test.                                   R-CI-GATE-RECONCILIATION

25. Аудит data quality scoring ​

Для backtest лучше не просто хранить данные, а иметь quality model.

25.1 Минимальная модель качества ​

Для каждого market_id/token_id/time_bucket:

text
quality_score: 0.0–1.0                            R-DQ-FIELD-SCORE
has_ws: bool                                      R-DQ-FIELD-HAS-WS
has_snapshot: bool                                R-DQ-FIELD-HAS-SNAPSHOT
has_gap: bool                                     R-DQ-FIELD-HAS-GAP
gap_duration_ms                                   R-DQ-FIELD-GAP-DURATION
dead_letter_count                                 R-DQ-FIELD-DEAD-LETTER-COUNT
reconciliation_mismatch_count                     R-DQ-FIELD-RECONCILIATION-MISMATCH-COUNT
max_event_lag_ms                                  R-DQ-FIELD-MAX-EVENT-LAG
stale_duration_ms                                 R-DQ-FIELD-STALE-DURATION
source_count                                      R-DQ-FIELD-SOURCE-COUNT

25.2 Checklist ​

text
[ ] Есть таблица или view data_quality.                           R-DQ-TABLE-OR-VIEW
[ ] Backtest может исключить poor-quality intervals.              R-DQ-BACKTEST-CAN-EXCLUDE
[ ] Gaps влияют на score.                                         R-DQ-GAPS-AFFECT-SCORE
[ ] Reconciliation mismatches влияют на score.                    R-DQ-RECONCILIATION-AFFECTS-SCORE
[ ] Stale RTDS ticks влияют на score.                             R-DQ-STALE-TICKS-AFFECT-SCORE
[ ] Высокая latency влияет на score.                              R-DQ-HIGH-LATENCY-AFFECTS-SCORE

26. Аудит конкретных failure modes ​

Каждый failure mode помечается как покрытый / не покрытый / неизвестно (R-FM-COVERAGE-MATRIX).

markdown
| Failure mode | Rule-ID | Covered? | Evidence | Severity if uncovered |
|---|---|---:|---|---|
| WS disconnect              | R-FM-WS-DISCONNECT            |  |  | Critical |
| WS half-open               | R-FM-WS-HALF-OPEN             |  |  | High |
| Subscription rejected      | R-FM-SUB-REJECTED             |  |  | High |
| Partial subscription       | R-FM-PARTIAL-SUB              |  |  | High |
| Message parse error        | R-FM-PARSE-ERROR              |  |  | High |
| Unknown message type       | R-FM-UNKNOWN-MSG              |  |  | Medium |
| REST timeout               | R-FM-REST-TIMEOUT             |  |  | High |
| Cloudflare throttling      | R-FM-CLOUDFLARE-THROTTLING    |  |  | High |
| DB unavailable             | R-FM-DB-UNAVAILABLE           |  |  | Critical |
| Duplicate event            | R-FM-DUPLICATE-EVENT          |  |  | High |
| Lost event                 | R-FM-LOST-EVENT               |  |  | Critical |
| Out-of-order event         | R-FM-OUT-OF-ORDER             |  |  | Critical |
| Snapshot/delta race        | R-FM-SNAPSHOT-DELTA-RACE      |  |  | Critical |
| Market metadata drift      | R-FM-METADATA-DRIFT           |  |  | High |
| Token/outcome mismatch     | R-FM-TOKEN-OUTCOME-MISMATCH   |  |  | Critical |
| Decimal precision loss     | R-FM-DECIMAL-PRECISION-LOSS   |  |  | Critical |
| Timestamp unit mismatch    | R-FM-TIMESTAMP-UNIT-MISMATCH  |  |  | Critical |
| Local timezone bug         | R-FM-LOCAL-TZ-BUG             |  |  | Critical |
| Backtest look-ahead        | R-FM-BACKTEST-LOOKAHEAD       |  |  | Critical |
| Schema drift               | R-FM-SCHEMA-DRIFT             |  |  | High |
| Reconnect storm            | R-FM-RECONNECT-STORM          |  |  | Medium |
| Memory leak / unbounded channel | R-FM-MEMORY-LEAK         |  |  | High |
| Dead-letter ignored        | R-FM-DEAD-LETTER-IGNORED      |  |  | Medium |

27. Минимальный набор regression tests ​

27.1 Unit tests ​

text
[ ] parse_market_metadata_binary                                  R-TEST-UNIT-PARSE-MARKET-BINARY
[ ] parse_market_metadata_multi_outcome                           R-TEST-UNIT-PARSE-MARKET-MULTI
[ ] preserve_outcome_token_alignment                              R-TEST-UNIT-OUTCOME-TOKEN-ALIGN
[ ] parse_decimal_price_without_f64                               R-TEST-UNIT-DECIMAL-PRICE
[ ] parse_decimal_size_without_f64                                R-TEST-UNIT-DECIMAL-SIZE
[ ] timestamp_ms_vs_s_detection                                   R-TEST-UNIT-TIMESTAMP-UNITS
[ ] unknown_enum_variant_goes_to_unknown                          R-TEST-UNIT-UNKNOWN-ENUM
[ ] malformed_payload_goes_to_dead_letter                         R-TEST-UNIT-MALFORMED-DEADLETTER
[ ] config_invalid_url_fails_fast                                 R-TEST-UNIT-CONFIG-FAIL-FAST
[ ] env_secret_masking                                            R-TEST-UNIT-ENV-MASKING

27.2 Integration tests ​

text
[ ] discovery_pagination_three_pages                              R-TEST-INT-DISCOVERY-PAGINATION
[ ] clob_snapshot_insert_idempotent                               R-TEST-INT-CLOB-SNAPSHOT-IDEM
[ ] ws_delta_after_snapshot_updates_book                          R-TEST-INT-WS-DELTA-AFTER
[ ] ws_delta_before_snapshot_is_rejected_or_buffered              R-TEST-INT-WS-DELTA-BEFORE
[ ] reconnect_creates_gap_and_resnapshot                          R-TEST-INT-RECONNECT-GAP-RESNAPSHOT
[ ] db_partial_failure_does_not_drop_uncommitted_events           R-TEST-INT-DB-PARTIAL-FAILURE
[ ] duplicate_trade_does_not_duplicate_volume                     R-TEST-INT-DUPLICATE-TRADE
[ ] rtds_carried_forward_not_live_signal                          R-TEST-INT-RTDS-CARRIED-FORWARD
[ ] reconciliation_mismatch_creates_audit_event                   R-TEST-INT-RECONCILIATION-AUDIT

27.3 Property-based tests ​

text
[ ] arbitrary orderbook levels always produce sorted valid book   R-TEST-PROP-ORDERBOOK-VALID
[ ] duplicate events are idempotent                               R-TEST-PROP-DUPLICATE-IDEM
[ ] replay same events twice gives same final state               R-TEST-PROP-REPLAY-STABLE
[ ] event order tie-breaker deterministic                         R-TEST-PROP-TIE-BREAKER
[ ] decimal roundtrip stable                                      R-TEST-PROP-DECIMAL-ROUNDTRIP

28. Рекомендуемая декомпозиция зон ответственности ​

Аудит может быть распараллелен по 5 зонам. Зона = логический срез по компонентам, не привязка к конкретному исполнителю.

Зона A — External API & Discovery ​

Scope:

text
- Gamma/Data/CLOB endpoints;
- market discovery;
- pagination;
- token/outcome mapping;
- endpoint configuration;
- CLOB V2 compatibility.

Deliverables:

text
- API assumption report;
- discovery test gaps;
- ISSUE list;
- recommended fixtures.

Зона B — WS/RTDS Runtime ​

Scope:

text
- WebSocket connection lifecycle;
- RTDS lifecycle;
- subscription batching;
- reconnect;
- ping/pong;
- stale detection;
- gap markers.

Deliverables:

text
- stream lifecycle diagram;
- failure mode coverage table;
- reconnect/resync issues;
- synthetic WS test plan.

Зона C — Normalization & Schema ​

Scope:

text
- Rust models;
- serde parsing;
- Decimal/timestamps;
- DB schema;
- idempotency;
- raw payload/dead-letter.

Deliverables:

text
- canonical model diff;
- schema invariant report;
- SQL checks;
- precision/timestamp issues.

Зона D — Replay & Backtest Correctness ​

Scope:

text
- event ordering;
- visible_ts;
- replay determinism;
- look-ahead bias;
- data quality scoring;
- historical metadata versioning.

Deliverables:

text
- backtest-readiness report;
- look-ahead risk list;
- replay tests;
- data-quality model proposal.

Зона E — Reliability, Performance & Ops ​

Scope:

text
- async Rust hot path;
- queues;
- DB writer;
- backpressure;
- observability;
- CI/CD;
- dependency audit.

Deliverables:

text
- performance bottlenecks;
- runtime safety issues;
- missing metrics/alerts;
- CI gate recommendations.

29. Финальный сводный отчёт ​

По завершении аудита собрать единый документ:

markdown
# Polymarket Collector Technical Audit Report

Audit date: YYYY-MM-DD
Repository commit: <hash>

## Executive Summary
- Overall status: Pass | Pass with risks | Fail
- Backtest readiness: Ready | Limited | Not ready
- Critical issues: N
- High issues: N
- Medium issues: N
- Low issues: N

## System Map
<component table>

## Confirmed Correct Behaviors
<список доказанных корректных свойств>

## Critical Issues
<ISSUE links>

## High Issues
<ISSUE links>

## Data Integrity Risks
<описание>

## Backtest Bias Risks
<описание>

## Missing Tests
<список>

## Required Fixes Before Production Use
1.
2.
3.

## Recommended Improvements
1.
2.
3.

## Appendix
- SQL invariant queries
- Test fixtures
- Reproduction commands
- API assumptions
- Known unknowns

30. Definition of Done для аудита ​

Аудит считается завершённым только если:

text
[ ] Построена карта компонентов.                                  R-DOD-COMPONENT-MAP
[ ] Проверены все network clients.                                R-DOD-NETWORK-CLIENTS
[ ] Проверен market discovery.                                    R-DOD-DISCOVERY
[ ] Проверены WS и RTDS lifecycle.                                R-DOD-WS-RTDS-LIFECYCLE
[ ] Проверены CLOB snapshots.                                     R-DOD-CLOB-SNAPSHOTS
[ ] Проверены timestamps.                                         R-DOD-TIMESTAMPS
[ ] Проверена Decimal precision.                                  R-DOD-DECIMAL-PRECISION
[ ] Проверена DB schema.                                          R-DOD-DB-SCHEMA
[ ] Проверена idempotency.                                        R-DOD-IDEMPOTENCY
[ ] Проверен replay.                                              R-DOD-REPLAY
[ ] Проверен backtest на look-ahead bias.                         R-DOD-BACKTEST-LOOKAHEAD
[ ] Проверена observability.                                      R-DOD-OBSERVABILITY
[ ] Проверены failure modes.                                      R-DOD-FAILURE-MODES
[ ] Запущены cargo fmt/clippy/test.                               R-DOD-CARGO-CHECKS
[ ] Составлен список всех unwrap/expect в runtime path.           R-DOD-UNWRAP-LIST
[ ] Составлен список всех мест, где используется f32/f64.         R-DOD-FLOAT-LIST
[ ] Составлен список всех мест, где timestamp парсится/конвертируется. R-DOD-TIMESTAMP-LIST
[ ] Все проблемы оформлены в ISSUE format.                        R-DOD-ISSUES-FORMATTED
[ ] Для каждой High/Critical проблемы есть fix plan.              R-DOD-FIX-PLAN
[ ] Для каждой High/Critical проблемы есть regression test proposal. R-DOD-REGRESSION-PROPOSAL
[ ] Явно указано, можно ли использовать текущую историю для backtest. R-DOD-BACKTEST-VERDICT

31. Главный критерий оценки ​

Система не считается корректной, пока не доказано следующее свойство (R-MAIN-CRITERION):

text
Для любого market/token_id и момента времени T backtest получает только те данные,
которые collector реально мог знать к T, с корректными price/size/timestamp,
с явной маркировкой gaps/stale/mismatch intervals.

Если это свойство не доказано — система может быть полезна как raw data logger, но не как надёжная база для quantitative backtest.