Surface markets whose resolution rule contradicts itself, the title, or a parent neg-risk constraint.
3. Why This Bot Matters
Self-contradicting market traded as if resolvable
A market whose resolution rule contradicts its title or a parent neg-risk constraint may never resolve cleanly. Strategies that trade it can be left holding positions through ambiguous or court-overturned outcomes.
Neg-risk parent constraint silently violated
Polymarket's neg-risk markets share a constraint that exactly one outcome must resolve YES across the set. A child market whose rule allows two simultaneous YES resolutions breaks that invariant; without detection, sizing and hedging logic on those markets is wrong.
Operators surprised at resolution time
Discovery of a contradiction at resolution is the worst possible time. Catching it at listing time lets Discovery exclude the market or Governance flag it for human review days before any trade is placed.
No structured reason for excluding a market
Without this signal, MarketScanner has no defensible reason to filter out a malformed market beyond an operator's gut call. The contradiction record provides the audit trail.
4. Required Polymarket Inputs
Input
Source
Required?
Use
YES prices for all markets in a mutually-exclusive group
data
Yes
Sum YES prices to detect contradiction (sum > 1.0 in mutually-exclusive group).
Market group definitions and related condition_ids
gamma
Yes
Identify which markets form mutually-exclusive groups.
5. Required Internal Inputs
Input
Source
Required?
Use
KillSwitch active flag
KillSwitch
Yes
Suppress all emissions when KillSwitch is active.
6. Parameter Guide
Parameter
Default
Warning
Hard
What it controls
contradiction_threshold
1.05
1.02
1.0
Minimum sum of YES prices in a mutually-exclusive group to trigger a contradiction signal.
poll_interval_s
30
120
300
Seconds between price checks per market group.
7. Detailed Parameter Instructions
contradiction_threshold
What it means
Minimum sum of YES prices in a mutually-exclusive group to trigger a contradiction signal.
Default
{ "contradiction_threshold": 1.05 }
Why this default matters
1.05 absorbs normal bid-ask spread noise while still detecting genuine mis-pricing opportunities.
Threshold logic
Condition
Action
sum >= 1.05
Normal — emit contradiction ObservationReport
1.02–1.05
WARN — borderline contradiction; emit with low_confidence flag
< 1.0
No contradiction — skip emission
Developer check
if (total_yes < p.contradiction_threshold.hard) return;
User-facing English
Contradictions are only reported when market prices are materially inconsistent.
poll_interval_s
What it means
Seconds between price checks per market group.
Default
{ "poll_interval_s": 30 }
Why this default matters
30 s provides near-real-time contradiction detection across related markets.
Threshold logic
Condition
Action
interval <= 30 s
Normal
30–120 s
WARN — reduced detection speed
> 300 s
Reject — PARAMETER_CHANGE_REQUIRES_APPROVAL
Developer check
if (p.poll_interval_s > p.hard) throw ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL');
User-facing English
Prices are checked frequently to catch contradictions as soon as they appear.
Strategy identified a pricing inconsistency across related markets
The prices across related markets don't add up to 100% — one or more outcomes appear over-priced. This is flagged as a potential analytical signal.
No contradiction signal despite related markets
All related markets are priced consistently — their YES prices sum to approximately 100%.
18. Failure-Mode Block
main_failure_mode
Data API outage prevents price fetching for a market group, causing ContradictionDetector to miss genuine contradiction windows during the outage.
false_positive_risk
Momentary wide spreads during low liquidity cause the YES-sum to exceed the threshold briefly, generating a contradiction signal with no tradeable opportunity.
false_negative_risk
A market group with an incomplete set of condition_ids (one market delisted) causes the YES-sum check to be based on a partial group, missing genuine contradictions.
safe_fallback
If Data API is unavailable for any group member, skip that group's contradiction check entirely rather than computing a partial sum. Emit STALE_DATA WARN.
required_dependencies
Polymarket Data API for live prices, Polymarket Gamma API for group definitions, KillSwitch active flag
19. Failure-Injection Recipes
Scenario
How to inject
Expected behaviour
Recovery
DATA_API_DOWN
Block Data API for 10 min
Automatic on API recovery; next poll cycle resumes normally
SYNTHETIC_CONTRADICTION
Set mock prices to sum YES > 1.2 for a test group
Automatic when prices normalise
KILL_SWITCH_ON
Set killswitch.active=true during active polling
Automatic on KillSwitch reset
20. State & Persistence
Cold-start recovery
On cold start, re-fetch all active group prices on first poll cycle.
21. Concurrency & Idempotency
Aspect
Specification
Execution model
async per-group poll loop
Max in-flight
20
Idempotency key
market_group_id + poll_cycle_ms
Per-call timeout (ms)
8000
Backpressure strategy
drop-after-buffer — max 50 pending group checks
Locking / mutual exclusion
Redis SETNX on market_group_id + cycle to prevent duplicate checks
Group of 2 markets, YES prices = [0.62, 0.56], sum = 1.18
ObservationReport emitted with contradiction_detected=true, total_yes_sum=1.18
YES-sum below threshold suppresses emission
YES prices = [0.55, 0.43], sum = 0.98
No ObservationReport; no alert
KillSwitch suppresses emission
killswitch.active=true; contradiction present
No ObservationReport; KILL_SWITCH_ACTIVE logged
Integration Tests
Test
Expected result
Full lifecycle: contradiction detected and consumed by arbitrage strategy
Strategy receives ObservationReport with contradiction_detected=true and total_yes_sum
Data API down: STALE_DATA emitted; group check skipped
STALE_DATA WARN; no ObservationReport for affected groups
Property Tests
Property
Required behaviour
ContradictionDetector never submits or signs orders
Always true
No ObservationReport emitted when KillSwitch is active
Always true
27. Operational Runbook
ContradictionDetector incidents are either Data API outages or genuine price contradictions. Contradictions are signals for strategies, not errors.
On-call actions
Alert
First step
Diagnosis
Mitigation
Escalate to
ContradictionDetectorContradictionActive
Verify prices on Polymarket.com for the affected market group. If genuine, downstream strategies will consume the signal. No manual action required unless prices are clearly erroneous.
Intelligence pod lead if contradiction persists > 30 min
ContradictionDetectorStaleData
Check Data API health. Verify network connectivity from bot host.
Intelligence pod lead if API down > 10 min
Manual overrides
adjust_contradiction_threshold — Update config.contradiction_threshold; requires approval gate if threshold < 1.02 — When market spreads widen due to low liquidity causing false positives
Healthcheck
Endpoint: /internal/health/contradictiondetector | Green: Last check < 2x poll_interval_s AND Redis reachable AND Data API returning 200 | Red: No check for > 10 min OR Redis unreachable
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
Gate
How measured
Threshold
Unit tests pass for contradiction detection, incomplete group handling, and KillSwitch suppression
CI test run
100% pass
Promote to Limited live
Gate
How measured
Threshold
No false positives on 10 synthetic non-contradictory group checks
Integration test with injected prices
0 false positives
Promote to General live
Gate
How measured
Threshold
100% detection of synthetic contradiction injection over 7-day soak