{
  "schema_version": "1.0.0",
  "bot_id": "3.14",
  "bot_name": "Liquidity-Pulse",
  "slug": "liquidity-pulse",
  "layer": "Strategy",
  "layer_key": "strat",
  "bot_class": "Alpha Strategy",
  "authority": [
    "Trade"
  ],
  "status": "planned",
  "readiness": "Spec started",
  "flagship": false,
  "is_reference": false,
  "public_export": false,
  "identity": {
    "layer": "Strategy",
    "bot_class": "Alpha Strategy",
    "authority": "Trade",
    "runs_before": "Risk guardrail pipeline",
    "runs_after": "Market scanner / Observation bus",
    "applies_to": "Polymarket binary markets that are gaining attention but currently have wide spreads and thin depth, offering attractive conditions for early market-making analytics",
    "default_mode": "shadow_only",
    "user_visible": "Advanced details only",
    "developer_owner": "Polytraders core \u2014 Strategy pod"
  },
  "purpose": "Liquidity-Pulse is a market-analytics tool that monitors emerging Polymarket markets for early liquidity opportunities. When a market's volume and attention signal crosses configured thresholds, the bot emits an OrderIntent for user-controlled maker quote placement. All execution decisions remain with the user; this bot provides structured analytics and sizing recommendations only.",
  "why_it_matters": [
    {
      "failure": "Quote placed before sufficient volume confirmation",
      "consequence": "Early quotes on unproven markets may sit unmatched or attract adverse selection from informed traders who discovered the market first."
    },
    {
      "failure": "Spread tightening faster than quote updates",
      "consequence": "Quotes placed at the initial wide spread become the worst price on the book as other makers tighten, leading to adverse selection."
    },
    {
      "failure": "Market resolves before position unwinds",
      "consequence": "Short-lived markets may reach resolution before an early maker position can be exited, forcing settlement at a potentially unfavorable resolution price."
    }
  ],
  "polymarket_inputs": [
    {
      "input": "CLOB book depth, spread, and volume",
      "source": "ws_market",
      "required": true,
      "use": "Measure current spread width and depth; detect volume pickup above tighten_at_volume_usd."
    },
    {
      "input": "Market metadata (creation time, category, status)",
      "source": "gamma",
      "required": true,
      "use": "Compute market age; verify event_lead_time_h; confirm market is open."
    },
    {
      "input": "Market status (open/closed)",
      "source": "clob_public",
      "required": true,
      "use": "Skip closed or resolved markets."
    }
  ],
  "internal_inputs": [
    {
      "input": "KillSwitch active flag",
      "source": "KillSwitch",
      "required": true,
      "use": "Abort all intent emission if KillSwitch active."
    },
    {
      "input": "Attention signal (volume trend, social mention rate)",
      "source": "internal (market scanner)",
      "required": true,
      "use": "Gate quote entry on attention signal exceeding threshold."
    },
    {
      "input": "Builder code bytes32",
      "source": "internal config",
      "required": true,
      "use": "Injected into builder field on every signed V2 OrderIntent."
    }
  ],
  "raw_params": [
    "initial_spread_bps \u00b7 int",
    "tighten_at_volume_usd \u00b7 int",
    "max_pre_event_position_usd \u00b7 int",
    "event_lead_time_h \u00b7 int (\u2264 6)"
  ],
  "parameters": [
    {
      "name": "initial_spread_bps",
      "default": 200,
      "warning": 100,
      "hard": 50,
      "controls": "Initial maker quote spread in bps around the current mid-price for early-liquidity quote recommendations.",
      "why_default_matters": "200 bps provides sufficient maker edge on thin, uncertain markets before volume develops.",
      "threshold_logic": [
        {
          "condition": ">= 200 bps",
          "action": "Standard early-liquidity quote"
        },
        {
          "condition": "100\u2013200 bps",
          "action": "WARN LP_TIGHT_SPREAD; reduced confidence"
        },
        {
          "condition": "< 50 bps",
          "action": "HARD_REJECT LP_SPREAD_BELOW_FLOOR"
        }
      ],
      "dev_check": "if params.initial_spread_bps < params.hard: return skip('LP_SPREAD_BELOW_FLOOR')",
      "user_facing": "The recommended spread is too tight for the current market conditions."
    },
    {
      "name": "tighten_at_volume_usd",
      "default": 5000,
      "warning": 2000,
      "hard": 500,
      "controls": "Total traded volume threshold in pUSD above which the bot recommends tightening the spread by 50%.",
      "why_default_matters": "5000 pUSD signals enough market activity to justify tighter spreads with lower adverse-selection risk.",
      "threshold_logic": [
        {
          "condition": ">= 5000 pUSD volume",
          "action": "Tighten spread recommendation by 50%"
        },
        {
          "condition": "< 500 pUSD",
          "action": "Maintain wide initial spread"
        }
      ],
      "dev_check": "if total_volume >= params.tighten_at_volume_usd: spread = initial_spread_bps * 0.5",
      "user_facing": "Volume has reached the threshold for a tighter spread recommendation."
    },
    {
      "name": "max_pre_event_position_usd",
      "default": 300,
      "warning": 500,
      "hard": 750,
      "controls": "Maximum pUSD maker position recommended per market during the pre-event attention phase.",
      "why_default_matters": "300 pUSD limits adverse-selection exposure on thin pre-event markets.",
      "threshold_logic": [
        {
          "condition": "<= 300 pUSD",
          "action": "Normal pre-event sizing"
        },
        {
          "condition": "> 750 pUSD",
          "action": "Reject config \u2014 PARAMETER_CHANGE_REQUIRES_APPROVAL"
        }
      ],
      "dev_check": "if params.max_pre_event_position_usd > params.hard: raise ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL')",
      "user_facing": "Position size was capped at the configured pre-event maximum."
    },
    {
      "name": "event_lead_time_h",
      "default": 24,
      "warning": 6,
      "hard": 1,
      "controls": "Minimum hours before the event for the bot to emit early-liquidity quote recommendations. Avoids posting too close to resolution.",
      "why_default_matters": "24h lead time ensures the market has time to develop depth before resolution risk dominates.",
      "threshold_logic": [
        {
          "condition": ">= 24h",
          "action": "Standard lead time"
        },
        {
          "condition": "6\u201324h",
          "action": "WARN LP_SHORT_LEAD_TIME; halve max position"
        },
        {
          "condition": "< 1h",
          "action": "HARD_REJECT LP_TOO_CLOSE_TO_RESOLUTION"
        }
      ],
      "dev_check": "if hours_to_event < params.hard: return skip('LP_TOO_CLOSE_TO_RESOLUTION')",
      "user_facing": "The market is too close to its resolution time for an early liquidity position."
    }
  ],
  "default_config": {
    "bot_id": "strat.liquidity_pulse",
    "version": "0.1.0",
    "mode": "shadow_only",
    "defaults": {
      "initial_spread_bps": 200,
      "tighten_at_volume_usd": 5000,
      "max_pre_event_position_usd": 300,
      "event_lead_time_h": 24
    },
    "locked": {
      "initial_spread_bps": {
        "min": 50
      },
      "max_pre_event_position_usd": {
        "max": 750
      },
      "event_lead_time_h": {
        "min": 1
      }
    }
  },
  "implementation_flow": [
    "Check KillSwitch; if active, emit no OrderIntents.",
    "FETCH gamma market metadata; compute hours_to_event.",
    "IF hours_to_event < hard (1h): skip LP_TOO_CLOSE_TO_RESOLUTION.",
    "FETCH attention signal from market scanner; if below threshold, skip.",
    "FETCH ws_market book; compute current spread and total_volume.",
    "Compute recommended spread: initial_spread_bps * (0.5 if total_volume >= tighten_at_volume_usd else 1.0).",
    "IF recommended_spread < spread_hard (50 bps): skip LP_SPREAD_BELOW_FLOOR.",
    "Compute position_size = min(max_pre_event_position_usd, available_capital).",
    "Adjust size down 50% if hours_to_event < warning (6h).",
    "EMIT OrderIntent: post_only=true, bid=mid-spread/2, ask=mid+spread/2, size=position_size, builder=code.",
    "EMIT DecisionReport with intent_emitted=true, reason=LP_QUOTE_EMITTED."
  ],
  "decision_logic": {
    "approve": "hours_to_event >= 1h, attention signal above threshold, spread >= 50 bps, market open, KillSwitch inactive.",
    "reshape_required": "Not applicable \u2014 reshaping handled by downstream Risk guardrail.",
    "reject": "hours_to_event < 1h; spread < 50 bps; KillSwitch active.",
    "warning_only": "hours_to_event 6\u201324h triggers warning and 50% position reduction; spread 100\u2013200 bps triggers tight-spread warning."
  },
  "decision_output_schema": "OrderIntent",
  "decision_output_example": {
    "intent_id": "oi_01HLP0000001A",
    "trace_id": "tr_01HLP000TR001",
    "market_id": "0xlp000000000000000000000000000000000000000000000000000000000000001",
    "outcome": "YES",
    "side": "buy",
    "price": "0.490",
    "size_pUSD": "150.00",
    "tif": "GTC",
    "post_only": true,
    "builder": {
      "code": "0x706f6c7974726164657273000000000000000000000000000000000000000000",
      "fee_bps": 10
    },
    "negrisk_aware": false,
    "decision": {
      "spread_bps": 200,
      "hours_to_event": 36.0,
      "total_volume_usd": 850.0,
      "reasons": [
        "LP_QUOTE_EMITTED"
      ]
    },
    "comment": "fees are operator-set at match time in V2 \u2014 feeRateBps is NOT on the signed order"
  },
  "developer_log": {
    "bot_id": "strat.liquidity_pulse",
    "market_id": "0xlp000000000000000000000000000000000000000000000000000000000000001",
    "spread_bps": 200,
    "hours_to_event": 36.0,
    "total_volume_usd": 850.0,
    "intent_emitted": true,
    "reason": "LP_QUOTE_EMITTED",
    "emitted_at_ms": 1746790800000
  },
  "user_explanations": [
    {
      "situation": "Early-liquidity quote placed",
      "message": "This market is attracting attention but still has a wide spread. A maker quote was placed to provide early liquidity at an attractive spread."
    },
    {
      "situation": "Market too close to resolution",
      "message": "Less than 1 hour remains before the event. No new maker positions were opened to avoid resolution-time risk."
    },
    {
      "situation": "Volume threshold reached \u2014 spread tightened",
      "message": "Traded volume crossed the threshold. The recommended spread was narrowed to remain competitive."
    }
  ],
  "failure_modes": {
    "main_failure_mode": "Adverse selection: informed traders arrive first and take liquidity at the initial wide spread before the market develops, leaving the maker with a systematically mispriced position.",
    "false_positive_risk": "Attention signal fires on markets that spike briefly but have no underlying trading interest, producing wasted quote placement.",
    "false_negative_risk": "event_lead_time_h too large misses genuine early-liquidity windows on rapidly developing markets.",
    "safe_fallback": "If ws_market feed stale or gamma metadata unavailable, skip without emitting any OrderIntent.",
    "required_dependencies": [
      "ws_market",
      "clob_public",
      "gamma",
      "internal market scanner",
      "KillSwitch",
      "internal builder code"
    ]
  },
  "acceptance_tests": {
    "unit": [
      {
        "test": "Emit GTC post-only maker quote when attention signal fires, hours_to_event=36",
        "setup": "initial_spread_bps=200, max_pre_event_position_usd=300",
        "expected": "GTC post_only OrderIntent; reason=LP_QUOTE_EMITTED"
      },
      {
        "test": "Skip when hours_to_event < 1h hard floor",
        "setup": "hours_to_event=0.5",
        "expected": "No OrderIntent; reason=LP_TOO_CLOSE_TO_RESOLUTION"
      },
      {
        "test": "Tighten spread when total_volume >= 5000 pUSD",
        "setup": "total_volume=5500, initial_spread_bps=200",
        "expected": "OrderIntent with spread_bps=100"
      }
    ],
    "integration": [
      {
        "test": "Full cycle: attention signal \u2192 quote \u2192 GTC post-only OrderIntent on Polygon testnet",
        "expected": "Order has builder.code, post_only=true, no feeRateBps, EIP-712 domain v2"
      }
    ],
    "property": [
      {
        "property": "Bot never emits OrderIntent when hours_to_event < 1h",
        "required": "Always true"
      },
      {
        "property": "feeRateBps never present on any signed OrderIntent",
        "required": "Always true"
      }
    ]
  },
  "checklist_overrides": {},
  "legacy_goal": "Provide liquidity in markets about to get attention but not yet trading.",
  "legacy_pm_signals": [
    "Pre-event volume on the target market",
    "Cross-market correlation: related markets moving while this one is asleep"
  ],
  "legacy_external_feeds": [
    "NewsIngest mention-volume spikes by topic",
    "Calendar of scheduled events"
  ],
  "reporting_groups": [
    "strategy_decision"
  ],
  "reason_codes": [
    {
      "code": "LP_QUOTE_EMITTED",
      "severity": "INFO",
      "meaning": "Attention signal fired, spread viable, hours_to_event OK. GTC post-only maker OrderIntent emitted.",
      "action": "Emit GTC maker OrderIntent.",
      "user_message": "An early-liquidity maker quote was placed."
    },
    {
      "code": "LP_TOO_CLOSE_TO_RESOLUTION",
      "severity": "HARD_REJECT",
      "meaning": "hours_to_event < 1h hard floor. Resolution risk too high for new maker positions.",
      "action": "Skip; no OrderIntent.",
      "user_message": "Too close to the event time for a new maker position."
    },
    {
      "code": "LP_TIGHT_SPREAD",
      "severity": "WARN",
      "meaning": "Recommended spread between 100 and 200 bps; adverse selection risk elevated.",
      "action": "Emit with lower confidence; log warning.",
      "user_message": "The spread is tighter than ideal for early liquidity."
    },
    {
      "code": "LP_SPREAD_BELOW_FLOOR",
      "severity": "HARD_REJECT",
      "meaning": "Computed spread < 50 bps hard floor.",
      "action": "Skip; no OrderIntent.",
      "user_message": "The spread was below the minimum required."
    },
    {
      "code": "KILL_SWITCH_ACTIVE",
      "severity": "HARD_REJECT",
      "meaning": "Global kill switch is active.",
      "action": "Skip all markets; no OrderIntents emitted.",
      "user_message": "Trading is currently paused."
    }
  ],
  "metrics": {
    "emitted": [
      {
        "name": "polytraders_strat_liquiditypulse_decisions_total",
        "type": "counter",
        "unit": "count",
        "labels": [
          "verdict",
          "reason_code"
        ],
        "meaning": "Total evaluation cycles by verdict and reason."
      },
      {
        "name": "polytraders_strat_liquiditypulse_spread_bps",
        "type": "histogram",
        "unit": "basis_points",
        "labels": [],
        "meaning": "Distribution of recommended spreads at quote emission."
      },
      {
        "name": "polytraders_strat_liquiditypulse_intents_emitted_total",
        "type": "counter",
        "unit": "count",
        "labels": [
          "spread_tier"
        ],
        "meaning": "Total maker OrderIntents by spread tier (wide/tight)."
      },
      {
        "name": "polytraders_strat_liquiditypulse_eval_latency_ms",
        "type": "histogram",
        "unit": "milliseconds",
        "labels": [],
        "meaning": "Latency from attention signal to OrderIntent emit."
      }
    ],
    "alerts": [
      {
        "name": "LiquidityPulseHighAdverseSelection",
        "condition": "rate(polytraders_strat_liquiditypulse_decisions_total{reason_code='LP_TIGHT_SPREAD'}[5m]) > 0.3",
        "severity": "warn",
        "runbook": "#runbook-lp-spread"
      },
      {
        "name": "LiquidityPulseKillSwitch",
        "condition": "rate(polytraders_strat_liquiditypulse_decisions_total{reason_code='KILL_SWITCH_ACTIVE'}[1m]) > 0",
        "severity": "page",
        "runbook": "#runbook-killswitch"
      },
      {
        "name": "LiquidityPulseStaleFeed",
        "condition": "rate(polytraders_strat_liquiditypulse_decisions_total{reason_code='STALE_MARKET_DATA'}[5m]) > 0.1",
        "severity": "warn",
        "runbook": "#runbook-lp-stale"
      }
    ]
  },
  "state": {
    "store": "redis",
    "shape": "Per market: attention_signal_score, current_spread_bps, total_volume_usd, hours_to_event; keyed by market_id",
    "ttl": "60s per attention snapshot; spread state 30s",
    "recovery": "On cold start, attention signals re-polled from market scanner; spread recomputed from ws_market.",
    "size_estimate": "~200 bytes per tracked market; < 1 MB total"
  },
  "concurrency": {
    "execution_model": "actor-per-market",
    "max_in_flight": 30,
    "idempotency_key": "intent_id",
    "timeout_ms": 300,
    "backpressure": "drop oldest attention signal per market_id when queue > 2",
    "locking": "per-market_id mutex for spread-state"
  },
  "dependencies": {
    "depends_on": [
      {
        "bot_id": "risk.kill_switch",
        "why": "Checked first; blocks all intent emission when active."
      }
    ],
    "emits_to": [
      {
        "bot_id": "risk.portfolio_guard",
        "what": "GTC post-only OrderIntents for risk guardrail evaluation."
      },
      {
        "bot_id": "gov.builder_attribution",
        "what": "builder.code bytes32 on every OrderIntent."
      }
    ],
    "sibling": [],
    "external": [
      {
        "service": "Polymarket CLOB WebSocket (ws_market)",
        "sla": "best-effort",
        "fallback": "Skip quote emission on disconnect."
      },
      {
        "service": "Polymarket Gamma API (market metadata)",
        "sla": "99.9%",
        "fallback": "If metadata unavailable, skip event_lead_time check \u2014 conservative skip."
      }
    ]
  },
  "security_surfaces": {
    "signs_orders": true,
    "private_key_access": "signing-only",
    "abuse_vectors": [
      "Attention signal injection to force quotes on low-quality markets",
      "Front-running of posted GTC quotes by adversaries who monitor emerging markets"
    ],
    "mitigations": [
      "Attention signals sourced from authenticated internal market scanner only",
      "Quote sizes bounded by max_pre_event_position_usd",
      "GTC quotes can be cancelled by user at any time"
    ]
  },
  "failure_injection": [
    {
      "scenario": "GAMMA_METADATA_UNAVAILABLE",
      "how_to_inject": "Take gamma API offline; bot cannot compute hours_to_event",
      "expected_behaviour": "Conservative skip \u2014 no quotes emitted until metadata recovers",
      "recovery": "Automatic when gamma API returns."
    },
    {
      "scenario": "NEAR_RESOLUTION_BLOCK",
      "how_to_inject": "Set hours_to_event=0.5 (< 1h hard)",
      "expected_behaviour": "LP_TOO_CLOSE_TO_RESOLUTION; no OrderIntent",
      "recovery": "Automatic \u2014 bot resumes after market resolves or resets."
    },
    {
      "scenario": "KILL_SWITCH_ON",
      "how_to_inject": "Set killswitch.active=true",
      "expected_behaviour": "No OrderIntents emitted",
      "recovery": "Automatic on manual KillSwitch reset."
    }
  ],
  "runbook": {
    "summary": "Liquidity-Pulse incidents are typically gamma API outages (blocking event lead-time checks) or kill-switch activations. Near-resolution blocks are expected behavior.",
    "oncall_actions": [
      {
        "alert": "LiquidityPulseHighAdverseSelection",
        "first_action": "Review spread recommendations; check if initial_spread_bps needs widening.",
        "escalate_to": "Strategy pod lead."
      },
      {
        "alert": "LiquidityPulseKillSwitch",
        "first_action": "Confirm KillSwitch activation was intentional.",
        "escalate_to": "Risk pod lead immediately."
      },
      {
        "alert": "LiquidityPulseStaleFeed",
        "first_action": "Check ws_market feed health and gamma API status.",
        "escalate_to": "Infra on-call if either down > 5 min."
      }
    ],
    "manual_overrides": [
      {
        "name": "exclude_market",
        "how": "Add market_id to config.excluded_markets",
        "when": "Market is showing anomalous attention patterns or the event lead-time logic is miscalibrated."
      }
    ],
    "healthcheck": "GET /internal/health/liquidity-pulse -> 200 if Gamma API responding; ws_market feed age < 5s; KillSwitch inactive.. Red: Gamma API down or KillSwitch active.."
  },
  "promotion_gates": {
    "to_shadow": [
      {
        "gate": "Unit tests pass including near-resolution block and spread-below-floor block",
        "how_measured": "CI test run",
        "threshold": "100% pass"
      }
    ],
    "to_limited_live": [
      {
        "gate": "p99 eval latency < 300ms over 24h shadow run",
        "how_measured": "polytraders_strat_liquiditypulse_eval_latency_ms histogram",
        "threshold": "p99 < 300ms"
      }
    ],
    "to_general_live": [
      {
        "gate": "E2E: attention signal \u2192 maker GTC quote on Polygon testnet with post_only=true, builder.code, no feeRateBps",
        "how_measured": "E2E test",
        "threshold": "Pass"
      }
    ]
  },
  "wire_examples": {
    "input": [
      {
        "label": "Attention signal \u2014 market gaining volume",
        "source": "internal (market scanner)",
        "payload": {
          "market_id": "0xlp000000000000000000000000000000000000000000000000000000000000001",
          "attention_score": 0.72,
          "total_volume_usd": "850.0",
          "hours_to_event": "36.0",
          "received_at_ms": 1746790800000
        }
      }
    ],
    "output": [
      {
        "label": "OrderIntent \u2014 LP GTC post-only maker YES",
        "payload": {
          "intent_id": "oi_01HLP0000001A",
          "market_id": "0xlp000000000000000000000000000000000000000000000000000000000000001",
          "outcome": "YES",
          "side": "buy",
          "price": "0.490",
          "size_pUSD": "150.00",
          "tif": "GTC",
          "post_only": true,
          "builder": {
            "code": "0x706f6c7974726164657273000000000000000000000000000000000000000000",
            "fee_bps": 10
          },
          "decision": {
            "spread_bps": 200,
            "reasons": [
              "LP_QUOTE_EMITTED"
            ]
          }
        }
      }
    ]
  },
  "reference_implementation": {
    "pseudocode": "FUNCTION onAttentionSignal(market_id, attentionSignal):\n  ks = FETCH internal.killswitch.status\n  IF ks.active: RETURN\n\n  // Resolve event lead time\n  meta = FETCH gamma.GET('/markets/' + market_id)\n  hoursToEvent = (meta.end_date_ms - now_ms()) / 3600000\n  IF hoursToEvent < params.event_lead_time_h_hard:  // 1h\n    EMIT DecisionReport(intent_emitted=false, reason='LP_TOO_CLOSE_TO_RESOLUTION')\n    RETURN\n\n  // Book and volume snapshot\n  book = FETCH ws_market.book(market_id)\n  totalVolume = book.total_traded_volume_usd\n  mid = (book.best_bid + book.best_ask) / 2\n\n  // Spread computation\n  spreadBps = params.initial_spread_bps\n  IF totalVolume >= params.tighten_at_volume_usd:\n    spreadBps = spreadBps * 0.5\n\n  IF spreadBps < params.initial_spread_bps_hard:  // 50 bps\n    EMIT DecisionReport(intent_emitted=false, reason='LP_SPREAD_BELOW_FLOOR')\n    RETURN\n\n  IF spreadBps < params.initial_spread_bps_warn:  // 100 bps\n    WARN('LP_TIGHT_SPREAD')\n\n  // Sizing\n  sizeMultiplier = 0.5 IF hoursToEvent < params.event_lead_time_h_warn ELSE 1.0  // < 6h\n  orderSize = toPusdUnits(params.max_pre_event_position_usd * sizeMultiplier)\n\n  bidPrice = mid - (spreadBps / 20000)\n  askPrice = mid + (spreadBps / 20000)\n\n  EMIT OrderIntent(market=market_id, outcome='YES', side='buy', price=bidPrice,\n                   size_pUSD=orderSize, tif='GTC', post_only=true, builder=internalBuilderCode)\n  EMIT DecisionReport(intent_emitted=true, spread_bps=spreadBps, reason='LP_QUOTE_EMITTED')",
    "sdk_calls": [
      "ws_market.subscribe('book', [market_id])",
      "gamma.GET('/markets/' + market_id)",
      "fetchClobPublic('/markets/' + market_id)",
      "internal.killswitch.status()",
      "buildOrderTypedData(orderParams, {name:'CTFExchange', version:'2', chainId:137})"
    ],
    "complexity": "O(1) per attention signal per market"
  },
  "api_surface": [
    "clob_public",
    "clob_auth",
    "ws_market",
    "gamma",
    "internal"
  ],
  "network": [
    "polygon"
  ],
  "version": {
    "spec": "2.0.0",
    "implementation": "0.1.0",
    "schema": "2",
    "released": null,
    "planned_release": "Q3-2026"
  },
  "migration_history": [
    {
      "date": "2026-04-28",
      "from": "n/a",
      "to": "v2-spec",
      "reason": "Spec drafted post-CLOB-V2 cutover; bot not yet implemented",
      "action_taken": "Designed against V2 schema (pUSD, builder codes, V2 EIP-712 domain)"
    }
  ],
  "polymarket_v2_compat": {
    "clob_version": "v2",
    "collateral": "pUSD",
    "eip712_domain_version": "2",
    "builder_code_aware": true,
    "negrisk_aware": false,
    "multichain_ready": false,
    "sdk_used": "py-clob-client-v2",
    "settlement_contract": "CTFExchangeV2",
    "notes": "Bot not yet implemented; designed against V2 schema (pUSD, builder codes, V2 EIP-712 domain). feeRateBps not present on any signed OrderIntent."
  },
  "reporting": {
    "emits_kinds": [
      "DecisionReport"
    ],
    "topics": [
      "polytraders.reports.decision"
    ],
    "cadence": "every-event",
    "retention_class": "2y",
    "sampling_rule": "emit-every",
    "bus_failure_action": "fail-closed",
    "user_visible": "yes",
    "consumes_kinds": [
      "ObservationReport",
      "RiskVote"
    ]
  },
  "capital_impact": "Direct",
  "v3_status": {
    "phase": 8,
    "phase_name": "Additional strategies",
    "docs": {
      "done": 27,
      "total": 27,
      "state": "done"
    },
    "impl": {
      "done": 0,
      "total": 15,
      "state": "pending"
    },
    "runtime": {
      "done": 0,
      "total": 8,
      "state": "pending"
    },
    "overall": "pending"
  }
}