Polytraders Dev Guide
internal
v3 spine Phase 1 · Shared contracts 9 demo-wired · 0 shadow-ready · 0 production-live · 100 pending · 109 total 15/33 infra tasks the plan status board
HomeBy LayerIntelligence4.8 ResolutionRuleParser

4.8 ResolutionRuleParser

Intelligence Signal Service Read-only PLANNED Spec started capital · Indirect P2 · Data normalisation pending flagship stub

Convert each market's resolution rule into a structured representation: source-of-truth, condition, ambiguity score.

v3 readiness

Docs27/27
donehow scored
Impl0/15
pendinghow scored
Backtest0/4
pendinghow scored
Runtime0/8
pendinghow scored

A bot is done when all four scores are. What does done mean?

1. Bot Identity

LayerIntelligence  Intelligence
Bot classSignal Service
AuthorityRead-only
StatusPLANNED
ReadinessSpec started
Runs before
Runs after
Applies to
Default modeshadow_only
User-visibleAdvanced details only
Developer ownerPolytraders core

2. Purpose

Convert each market's resolution rule into a structured representation: source-of-truth, condition, ambiguity score.

3. Why This Bot Matters

  • Free-text rule treated as if structured

    Resolution rules are written in English and parsed by humans. Without a structured representation, every downstream consumer — ContradictionDetector, RuleChangeMonitor, SourceOfTruthVerifier — re-parses the same string and gets subtly different answers.

  • Ambiguity score not surfaced to strategies

    A resolution rule with high ambiguity carries non-trivial settlement risk. Without an explicit score, strategy bots cannot down-size or skip those markets.

  • Source-of-truth field unused

    A structured 'source-of-truth' field lets SourceOfTruthVerifier check whether the cited source actually publishes the data needed to resolve. The parser is the upstream that makes that check possible.

  • Rule changes hard to diff

    RuleChangeMonitor needs to detect post-listing edits. Diffing structured representations catches semantic changes; diffing raw strings flags every cosmetic edit and misses meaningful ones.

4. Required Polymarket Inputs

InputSourceRequired?Use
Market resolution_rules and resolution_source from Gamma APIgammaYesPrimary source for extracting and hashing resolution rules.
Market condition_id and question textdataYesCross-reference condition_id to market metadata for rule provenance.

5. Required Internal Inputs

InputSourceRequired?Use
KillSwitch active flagKillSwitchYesSuppress all ResolutionRuleParser emissions when KillSwitch is active.

6. Parameter Guide

ParameterDefaultWarningHardWhat it controls
poll_interval_s3009003600Seconds between Gamma API polls for resolution rule updates per active market.
staleness_threshold_s60012007200Seconds after which a cached Gamma response is considered stale.

7. Detailed Parameter Instructions

poll_interval_s

What it means

Seconds between Gamma API polls for resolution rule updates per active market.

Default

{ "poll_interval_s": 300 }

Why this default matters

300 s (5 min) provides timely detection of rule changes without overloading Gamma API.

Threshold logic

ConditionAction
interval <= 300 sNormal
300–900 sWARN — reduced detection speed for rule changes
> 3600 sReject — PARAMETER_CHANGE_REQUIRES_APPROVAL

Developer check

if (p.poll_interval_s > p.hard) throw ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL');

User-facing English

Resolution rules are checked regularly to detect any market condition changes.

staleness_threshold_s

What it means

Seconds after which a cached Gamma response is considered stale.

Default

{ "staleness_threshold_s": 600 }

Why this default matters

600 s matches twice the default poll interval, ensuring at least one retry before stale status.

Threshold logic

ConditionAction
age <= 600 sNormal
600–1200 sWARN — stale data approaching
> 7200 sReject — emit STALE_DATA and suppress

Developer check

if (cache_age_s > p.staleness_threshold_s.hard) emit('STALE_DATA');

User-facing English

Cached resolution rules expire regularly to ensure freshness.

8. Default Configuration

{
  "bot_id": "intel.resolutionruleparser",
  "version": "0.1.0",
  "mode": "planned",
  "defaults": {
    "poll_interval_s": 300,
    "staleness_threshold_s": 600
  },
  "locked": {
    "poll_interval_s": {
      "max": 3600
    },
    "staleness_threshold_s": {
      "max": 7200
    }
  }
}

9. Implementation Flow

— not yet authored —

10. Reference Implementation

Pseudocode is language-agnostic. FETCH = read input. EMIT = produce output. IF/THEN/ELSE = decision. Translate directly to TypeScript, Python, Go, or Rust.

FUNCTION parseResolutionRules(condition_id):
  // 0. KillSwitch check
  IF FETCH internal.killswitch.status == ACTIVE:
    RETURN

  // 1. Fetch market metadata from Gamma
  market = FETCH gamma.GET('/markets/' + condition_id)
  IF market IS NULL:
    EMIT WARN 'STALE_DATA'
    RETURN

  // 2. Extract resolution source and rules
  rules = market.resolution_rules
  source = market.resolution_source
  oracle_bond_pusd = 750  // UMA $750 pUSD bond

  // 3. Validate rule completeness
  IF rules IS NULL OR len(rules) == 0:
    EMIT WARN 'RESOLUTIONRULEPARSER_MISSING_RULES'
    RETURN

  // 4. Check negRisk flag
  neg_risk = market.get('negRisk', False)

  // 5. Emit ObservationReport
  EMIT ObservationReport {
    report_id: gen_id(),
    kind: 'ObservationReport',
    condition_id: condition_id,
    resolution_source: source,
    resolution_rules_hash: hash(rules),
    oracle_bond_pusd: oracle_bond_pusd,
    neg_risk: neg_risk,
    emitted_at_ms: now_ms()
  }

SDK calls used

  • gamma.GET('/markets/<condition_id>')
  • data.GET('/markets/<condition_id>/resolution')
  • internal.killswitch.status

Complexity: O(1) per market; O(M) for bulk pre-load

11. Wire Examples

Input — what arrives on the wire

{
  "label": "Gamma market metadata fetch for resolution rule parsing",
  "source": "gamma",
  "payload": {
    "condition_id": "0xf1a2b30000000000000000000000000000000000000000000000000000000000",
    "question": "Will BTC close above $100k on Dec 31, 2026?",
    "resolution_source": "UMA Optimistic Oracle",
    "resolution_rules": "Resolves YES if Coinbase BTC/USD close price on Dec 31 2026 is >= 100000.",
    "negRisk": false,
    "timestamp_ms": 1746703000000
  }
}

Output — what the bot emits

{
  "label": "ObservationReport — resolution rules parsed",
  "payload": {
    "report_id": "rep_rrp_0xf1a2_1746703000000",
    "trace_id": "trc_0xbeef0102030405060709",
    "bot_id": "intel.resolutionruleparser",
    "kind": "ObservationReport",
    "condition_id": "0xf1a2b30000000000000000000000000000000000000000000000000000000000",
    "resolution_source": "UMA Optimistic Oracle",
    "resolution_rules_hash": "0xabcd1234",
    "oracle_bond_pusd": 750,
    "neg_risk": false,
    "emitted_at_ms": 1746703005000
  }
}

12. Decision Logic

APPROVE

— not yet authored —

RESHAPE_REQUIRED

— not yet authored —

REJECT

— not yet authored —

WARNING_ONLY

— not yet authored —

13. Standard Decision Output

This bot returns a RiskVote object. See RiskVote schema.

{
  "report_id": "rep_rrp_0xf1a2_1746703000000",
  "trace_id": "trc_0xbeef0102030405060709",
  "bot_id": "intel.resolutionruleparser",
  "kind": "ObservationReport",
  "condition_id": "0xf1a2b30000000000000000000000000000000000000000000000000000000000",
  "resolution_source": "UMA Optimistic Oracle",
  "resolution_rules_hash": "0xabcd1234",
  "oracle_bond_pusd": 750,
  "neg_risk": false,
  "change_detected": false,
  "emitted_at_ms": 1746703005000
}

14. Reason Codes

CodeSeverityMeaningActionUser-facing message
RESOLUTIONRULEPARSER_MISSING_RULESWARNMarket resolution_rules field is null or empty in Gamma API response.Skip emission; log WARN for manual review.Resolution rules for this market are not yet published.
STALE_DATAWARNGamma API is unresponsive or returned stale market metadata.Suppress emission; alert on-call if condition persists > 5 min.
KILL_SWITCH_ACTIVEHARD_REJECTKillSwitch active; all ResolutionRuleParser emissions suppressed.Continue parsing but suppress ObservationReport emissions.Rule parsing signals paused while trading is suspended system-wide.
RESOLUTIONRULEPARSER_SOURCE_CHANGEWARNResolution source changed since last parse (e.g. from UMA to manual).Emit ObservationReport with change_detected=true; flag for strategy review.The resolution source for this market has changed.

15. Metrics & Logs

Metrics emitted

MetricTypeUnitLabelsMeaning
polytraders_intel_resolutionruleparser_observations_emitted_totalcountercountresolution_sourceObservationReports emitted per resolution source type.
polytraders_intel_resolutionruleparser_missing_rules_totalcountercountMarkets with missing or empty resolution rules skipped.
polytraders_intel_resolutionruleparser_source_changes_totalcountercountMarkets where resolution source changed since last parse.

Alerts

AlertConditionSeverityRunbook
ResolutionRuleParserMissingRulesHighrate(polytraders_intel_resolutionruleparser_missing_rules_total[30m]) > 5warn#runbook-resolutionruleparser-missing-rules
ResolutionRuleParserSourceChangerate(polytraders_intel_resolutionruleparser_source_changes_total[10m]) > 0warn#runbook-resolutionruleparser-source-change

Dashboards

  • Grafana — Intelligence / ResolutionRuleParser parse rate and source change events

16. Developer Reporting

{
  "bot_id": "intel.resolutionruleparser",
  "condition_id": "0xf1a2b30000000000000000000000000000000000000000000000000000000000",
  "rules_hash": "0xabcd1234",
  "change_detected": false,
  "gamma_response_ms": 120,
  "killswitch_active": false,
  "emitted_at_ms": 1746703005000
}

17. Plain-English Reporting

SituationUser-facing explanation
Strategy paused entry on a market after rule change detectedThe resolution conditions for this market were recently updated. The system flagged this for review before allowing new positions.
Resolution source shows UMA Optimistic OracleThis market resolves via UMA's decentralised oracle, which requires a $750 pUSD bond and a 2-hour challenge window.

18. Failure-Mode Block

main_failure_modeGamma API outage prevents resolution rule fetching, leaving strategy layer with stale or missing rule data for active markets.
false_positive_riskMinor whitespace or formatting changes to resolution_rules text generate false rule-change alerts despite no substantive change.
false_negative_riskGamma API returns cached (stale) rules during a CMS update, causing a genuine rule change to be missed until next successful fresh fetch.
safe_fallbackIf Gamma API is unavailable for > staleness_threshold_s, emit STALE_DATA WARN and suppress new ObservationReports until fresh data is available. Retain last known good rules hash.
required_dependenciesPolymarket Gamma API, KillSwitch active flag, Postgres for rule snapshot storage

19. Failure-Injection Recipes

ScenarioHow to injectExpected behaviourRecovery
GAMMA_API_DOWNBlock Gamma API for 5 minAutomatic on Gamma recovery; re-parse all active markets
RULES_CHANGEModify resolution_rules for a live market in test Gamma instanceAutomatic; downstream strategies receive updated rules hash
KILL_SWITCH_ONSet killswitch.active=true during active parsingAutomatic on KillSwitch reset

20. State & Persistence

Cold-start recovery

On cold start, reload last known state from Postgres; re-parse all active markets.

21. Concurrency & Idempotency

AspectSpecification
Execution modelasync bulk-poll at market open, then per-event on Gamma webhook
Max in-flight10
Idempotency keycondition_id + rules_hash
Per-call timeout (ms)10000
Backpressure strategydrop-after-buffer — queue max 100 pending parses
Locking / mutual exclusionPostgres row lock on condition_id during parse update

22. Dependencies

Depends on (must run first)

BotWhyContract
risk.kill_switchSuppress emissions when KillSwitch is active.

Emits to (downstream consumers)

BotWhyContract
strat.resolution_aware_strategies

Sibling bots (same OrderIntent)

Used by (auto-aggregated)

4.9

External services

ServiceEndpointSLA assumedOn failure
Polymarket Gamma APIhttps://gamma-api.polymarket.com99.9% / 500 ms p99

23. Security Surfaces

Abuse vectors considered

  • Adversary modifies resolution rules in Gamma to manipulate downstream strategy behaviour
  • Source change spoofing to trigger false RESOLUTIONRULEPARSER_SOURCE_CHANGE alerts

Mitigations

  • Rules hash comparison detects any rule text changes between parses
  • ObservationReports are informational only — strategies independently verify before acting

24. Polymarket V2 Compatibility

AspectValue
CLOB versionv2
Collateral assetpUSD
EIP-712 Exchange domain version2
Aware of builderCode fieldno
Aware of negative-risk marketsyes
Multi-chain readyno
SDK usedpy-clob-client-v2
Settlement contractCTFExchangeV2
NotesParses Gamma market resolution rules; references negRisk flag for multi-outcome markets. No order signing.

API surfaces declared

gammadatainternal

Networks supported

polygon

25. Versioning & Migration

FieldValue
spec2.0.0
implementation0.1.0
schema2
releasedNone
planned_releaseQ3-2026

Migration history

DateFromToReasonAction taken
2026-04-28n/av2-specSpec drafted post-CLOB-V2 cutover; bot not yet implementedDesigned against V2 schema (pUSD, builder codes, V2 EIP-712 domain)

26. Acceptance Tests

Unit Tests

TestSetupExpected result
Market with valid resolution rules emits ObservationReportGamma returns market with resolution_rules and resolution_source populatedObservationReport emitted with rules_hash and source
Market with empty resolution rules skips emission and emits WARNGamma returns market with resolution_rules=nullRESOLUTIONRULEPARSER_MISSING_RULES WARN; no ObservationReport
KillSwitch suppresses emissionkillswitch.active=true; valid rules availableNo ObservationReport; KILL_SWITCH_ACTIVE logged

Integration Tests

TestExpected result
Rule change detected and emitted correctlyObservationReport emitted with change_detected=true when rules_hash changes between polls
Gamma API outage: STALE_DATA emitted; last rules hash retainedSTALE_DATA WARN; no new ObservationReports; last rules hash preserved in Postgres

Property Tests

PropertyRequired behaviour
ResolutionRuleParser never submits or signs ordersAlways true
No ObservationReport emitted when KillSwitch is activeAlways true

27. Operational Runbook

ResolutionRuleParser incidents are typically Gamma API outages or unexpected rule changes. Rule changes require prompt strategy notification.

On-call actions

AlertFirst stepDiagnosisMitigationEscalate to
ResolutionRuleParserMissingRulesHighCheck Gamma API health. Verify markets have published resolution rules via Gamma dashboard.Intelligence pod lead if > 10 markets missing rules
ResolutionRuleParserSourceChangeReview which condition_id triggered the change. Confirm with market data team if change is legitimate.Intelligence pod lead immediately on any source change

Manual overrides

  • force_reparse_all — POST /internal/resolutionruleparser/reparse to trigger bulk re-parse of all active markets — After Gamma API recovery from extended outage

Healthcheck

Endpoint: /internal/health/resolutionruleparser | Green: Last parse < 60 min ago AND Postgres reachable AND Gamma API returning 200 | Red: No parse for > 2 h OR Postgres unreachable OR Gamma API down > 15 min

28. Promotion Gates

A bot does not advance to the next readiness state until every gate below is green. Gates are observable from production data — no subjective sign-off.

Promote to Shadow

GateHow measuredThreshold
Unit tests pass for missing-rules gate, source-change detection, and KillSwitch suppressionCI test run100% pass

Promote to Limited live

GateHow measuredThreshold
Bulk parse of all active Gamma markets succeeds with 0 errors on stagingIntegration test0 parse errors

Promote to General live

GateHow measuredThreshold
Rule-change detection verified on synthetic rule mutation over 7-day soakIntegration test log audit100% detection of injected changes

29. Developer Checklist

Ready-to-ship score: 27/27 sections complete · 100%

RequirementStatus
Purpose defined✓ done
Required inputs listed✓ done
Parameters defined✓ done
Defaults defined✓ done
Warning thresholds defined✓ done
Hard thresholds defined✓ done
Safe fallback defined✓ done
Structured output defined✓ done
Developer log defined✓ done
Plain-English explanation✓ done
Unit tests defined✓ done
Integration tests defined✓ done
Property tests defined✓ done
Failure-mode block complete✓ done
Reference implementation pseudocode✓ done
Wire examples (input + output)✓ done
Reason codes listed✓ done
Metrics & logs defined✓ done
State & persistence defined✓ done
Concurrency & idempotency defined✓ done
Dependencies declared✓ done
Security surfaces declared✓ done
Polymarket V2 compatibility declared✓ done
Version & migration history declared✓ done
Operational runbook defined✓ done
Promotion gates defined✓ done
Failure-injection recipes defined✓ done