{
  "schema_version": "1.0.0",
  "bot_id": "2.8",
  "bot_name": "PartialFillHandler",
  "slug": "partialfillhandler",
  "layer": "Execution",
  "layer_key": "exec",
  "bot_class": "Execution Utility",
  "authority": [
    "Reshape"
  ],
  "status": "planned",
  "readiness": "Spec started",
  "flagship": false,
  "is_reference": false,
  "public_export": false,
  "identity": {
    "layer": "Execution",
    "bot_class": "Execution Utility",
    "authority": "Reshape",
    "runs_before": "CancelReplaceOptimizer (if remainder requires a new order)",
    "runs_after": "OrderLifecycleManager (PARTIAL event received)",
    "applies_to": "Every PARTIAL fill event with a non-zero remainder",
    "default_mode": "shadow_only",
    "user_visible": "yes",
    "developer_owner": "Polytraders core \u2014 Execution pod"
  },
  "purpose": "PartialFillHandler decides what to do with the unfilled remainder after a partial fill: hold and wait, cancel the remainder, or chase the market by submitting a new order. It respects the strategy's declared partial-fill policy and current book state.",
  "why_it_matters": [
    {
      "failure": "Remainder left resting indefinitely",
      "consequence": "Capital locked in a GTC order that will never fill at the original price if the market has moved; position budget exhausted."
    },
    {
      "failure": "Remainder always cancelled",
      "consequence": "Aggressive cancel policy causes the strategy to underfill its intended position size, leading to execution shortfall."
    },
    {
      "failure": "Chase price too aggressive",
      "consequence": "Chasing too many ticks above the original price to fill the remainder results in a worse blended fill price than if the order had been left resting."
    }
  ],
  "polymarket_inputs": [
    {
      "input": "CLOB V2 top-of-book snapshot",
      "source": "clob_public",
      "required": true,
      "use": "Determine current best bid/ask to decide whether book is thin and whether chasing is viable."
    },
    {
      "input": "Recent fill rate on market",
      "source": "ws_market",
      "required": false,
      "use": "Estimate time-to-fill for remainder if left resting."
    }
  ],
  "internal_inputs": [
    {
      "input": "PARTIAL ExecutionReport from OrderLifecycleManager",
      "source": "exec.orderlifecyclemanager",
      "required": true,
      "use": "Get remaining_usd, original price, market_id, and strategy partial-fill policy."
    },
    {
      "input": "KillSwitch active flag",
      "source": "risk.kill_switch",
      "required": true,
      "use": "Cancel remainder immediately if KillSwitch active; emit no new order."
    }
  ],
  "raw_params": [
    "default_policy \u00b7 enum",
    "min_remainder_size \u00b7 int",
    "chase_max_ticks \u00b7 int",
    "cancel_on_book_thin \u00b7 bool"
  ],
  "parameters": [
    {
      "name": "default_policy",
      "default": "hold",
      "warning": "\u2014",
      "hard": "\u2014",
      "controls": "Default policy for handling the unfilled remainder: hold (leave resting), cancel (remove from book), or chase (submit new order at adjusted price).",
      "why_default_matters": "Hold is safest: it preserves queue position and fills if the market returns to the original price level.",
      "threshold_logic": [
        {
          "condition": "policy=hold",
          "action": "Leave remainder order resting on book"
        },
        {
          "condition": "policy=cancel",
          "action": "Cancel remainder; emit ExecutionReport(CANCELLED_REMAINDER)"
        },
        {
          "condition": "policy=chase AND remaining_ticks <= chase_max_ticks",
          "action": "Cancel remainder; submit new order at current best price"
        }
      ],
      "dev_check": "if params.default_policy == 'chase': submitChaseOrder(remainder, book)",
      "user_facing": "The unfilled portion of your order was left in the market to continue looking for a match."
    },
    {
      "name": "min_remainder_size",
      "default": 5,
      "warning": 2,
      "hard": 1,
      "controls": "Minimum remainder size in pUSD below which the remainder is automatically cancelled rather than left resting.",
      "why_default_matters": "Remainders below $5 pUSD are economically dust-like; the transaction cost of a fill exceeds the position value.",
      "threshold_logic": [
        {
          "condition": "remaining_usd >= 5",
          "action": "Apply default_policy normally"
        },
        {
          "condition": "1 <= remaining_usd < 5",
          "action": "WARN \u2014 PARTIAL_FILL_DUST_REMAINDER; forward to DustAndRoundingCleaner"
        },
        {
          "condition": "remaining_usd < 1 (hard)",
          "action": "Auto-cancel; PARTIAL_FILL_DUST_AUTO_CANCEL"
        }
      ],
      "dev_check": "if remaining_usd < params.min_remainder_size: cancelRemainder(order)",
      "user_facing": "The remaining part of your order was too small to be worth keeping open, so it was cancelled."
    },
    {
      "name": "chase_max_ticks",
      "default": 3,
      "warning": 5,
      "hard": 10,
      "controls": "Maximum number of ticks above the original price at which a chase order may be submitted. Prevents chasing a rapidly moving market.",
      "why_default_matters": "Chasing more than 3 ticks means paying significantly more for the remainder than the original intent price.",
      "threshold_logic": [
        {
          "condition": "required_ticks <= 3",
          "action": "Chase permitted; submit new order"
        },
        {
          "condition": "3 < required_ticks <= 5",
          "action": "WARN \u2014 PARTIAL_FILL_CHASE_WIDE; proceed if strategy allows"
        },
        {
          "condition": "required_ticks > 10 (hard)",
          "action": "Cancel remainder; PARTIAL_FILL_CHASE_ABORTED"
        }
      ],
      "dev_check": "if ticksToFill > params.chase_max_ticks: cancelRemainder(order)",
      "user_facing": "The remaining portion of your order could not be filled at a reasonable price and was cancelled."
    },
    {
      "name": "cancel_on_book_thin",
      "default": true,
      "warning": "\u2014",
      "hard": "\u2014",
      "controls": "If True, automatically cancel the remainder when the visible book depth is less than the remainder size (thin book condition).",
      "why_default_matters": "A thin book indicates the remainder will not fill soon; leaving a resting order in a thin book risks a fill when the book refills at an adverse price.",
      "threshold_logic": [
        {
          "condition": "book_depth >= remaining_usd",
          "action": "Proceed with default_policy"
        },
        {
          "condition": "book_depth < remaining_usd AND cancel_on_book_thin=true",
          "action": "Cancel remainder; PARTIAL_FILL_BOOK_THIN_CANCEL"
        }
      ],
      "dev_check": "if bookDepth < remaining_usd and params.cancel_on_book_thin: cancelRemainder(order)",
      "user_facing": "The order book became too thin to fill the remaining portion of your order, which was cancelled."
    }
  ],
  "default_config": {
    "bot_id": "exec.partialfillhandler",
    "version": "0.1.0",
    "mode": "shadow_only",
    "defaults": {
      "default_policy": "hold",
      "min_remainder_size": 5,
      "chase_max_ticks": 3,
      "cancel_on_book_thin": true
    },
    "locked": {
      "min_remainder_size": {
        "min": 1
      },
      "chase_max_ticks": {
        "max": 10
      }
    }
  },
  "implementation_flow": [
    "Receive PARTIAL ExecutionReport from OrderLifecycleManager with remaining_usd, original_price, market_id.",
    "Check KillSwitch; if active, cancel remainder via clob_auth and return.",
    "If remaining_usd < min_remainder_size: forward to DustAndRoundingCleaner; cancel remainder.",
    "Fetch CLOB V2 top-of-book from clob_public; compute book_depth on order side.",
    "If cancel_on_book_thin and book_depth < remaining_usd: cancel remainder; emit PARTIAL_FILL_BOOK_THIN_CANCEL.",
    "Apply default_policy: hold \u2192 leave remainder; cancel \u2192 cancel remainder; chase \u2192 compute ticks to fill.",
    "If chase: if ticks_to_fill > chase_max_ticks, cancel; else cancel remainder and submit new order at current best price via CancelReplaceOptimizer.",
    "Emit ExecutionReport with verdict, policy applied, remaining_usd, and reason_code."
  ],
  "decision_logic": {
    "approve": "Remainder above min_remainder_size, book not thin, policy=hold. Leave remainder resting.",
    "reshape_required": "Chase policy: cancel remainder and submit new order at adjusted price (ticks within chase_max_ticks).",
    "reject": "Remainder below min_remainder_size, book thin, ticks exceed chase_max_ticks, or KillSwitch active.",
    "warning_only": "Chase ticks between warning and hard threshold; WARN emitted but chase proceeds if strategy allows."
  },
  "decision_output_schema": "ExecutionReport",
  "decision_output_example": {
    "report_id": "rep_3c4d5e6f7a8b9c0d",
    "trace_id": "trc_2b3c4d5e6f7a8b9c",
    "bot_id": "exec.partialfillhandler",
    "order_id": "0xcccc3333dddd4444eeee5555ffff6666aaaa7777bbbb8888cccc9999dddd0000",
    "market_id": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
    "filled_usd": 200,
    "remaining_usd": 250,
    "policy_applied": "hold",
    "verdict": "HOLD_REMAINDER",
    "collateral": "pUSD",
    "builder_code": "0x706f6c7974726164657273000000000000000000000000000000000000000000",
    "evaluated_at_ms": 1746770100000
  },
  "developer_log": {
    "order_id": "0xcccc3333dddd4444eeee5555ffff6666aaaa7777bbbb8888cccc9999dddd0000",
    "remaining_usd": 250,
    "book_depth_usd": 800,
    "ticks_to_fill": 1,
    "policy_applied": "hold",
    "cancel_on_book_thin": true,
    "verdict": "HOLD_REMAINDER"
  },
  "user_explanations": [
    {
      "situation": "Remainder held",
      "message": "Part of your order was filled. The rest is still open in the market, waiting for a match."
    },
    {
      "situation": "Remainder cancelled \u2014 dust",
      "message": "The remaining portion of your order was too small to be worth keeping, so it was removed from the market."
    },
    {
      "situation": "Remainder cancelled \u2014 book thin",
      "message": "The market did not have enough volume to fill the remainder, so the order was removed to avoid an unfavourable fill later."
    }
  ],
  "failure_modes": {
    "main_failure_mode": "Chase policy submits a new order at a tick-adjusted price while the original remainder order is still being cancelled, briefly creating a duplicate open order.",
    "false_positive_risk": "cancel_on_book_thin fires on a momentarily thin book snapshot, cancelling a remainder that would have filled seconds later when the book refreshed.",
    "false_negative_risk": "hold policy leaves a large remainder resting when the book has moved significantly past the original price, locking capital indefinitely.",
    "safe_fallback": "If clob_public is unavailable for book depth check, apply hold policy conservatively and emit WARN; do not auto-cancel without book data.",
    "required_dependencies": [
      "clob_public top-of-book snapshot",
      "PARTIAL ExecutionReport from OrderLifecycleManager",
      "KillSwitch active flag"
    ]
  },
  "acceptance_tests": {
    "unit": [
      {
        "test": "Hold policy: remainder left resting when book is deep",
        "setup": "book_depth=800, remaining_usd=250, policy=hold",
        "expected": "HOLD_REMAINDER; no cancel issued"
      },
      {
        "test": "Auto-cancel when remaining_usd < min_remainder_size",
        "setup": "remaining_usd=3, min_remainder_size=5",
        "expected": "PARTIAL_FILL_DUST_AUTO_CANCEL; cancel issued"
      },
      {
        "test": "Book-thin cancel when book_depth < remaining_usd",
        "setup": "book_depth=100, remaining_usd=200, cancel_on_book_thin=true",
        "expected": "PARTIAL_FILL_BOOK_THIN_CANCEL; cancel issued"
      }
    ],
    "integration": [
      {
        "test": "Chase policy: remainder cancelled and new order submitted within chase_max_ticks",
        "expected": "New order submitted at current_best_ask; CancelReplaceOptimizer invoked"
      },
      {
        "test": "KillSwitch active: remainder cancelled immediately on KillSwitch signal",
        "expected": "Cancel issued; KILL_SWITCH_ACTIVE emitted; no new order"
      }
    ],
    "property": [
      {
        "property": "Remainder size in ExecutionReport always equals original_size - filled_usd",
        "required": "Always true"
      },
      {
        "property": "Chase order price never exceeds original_price + chase_max_ticks * tick_size",
        "required": "Always true"
      }
    ]
  },
  "checklist_overrides": {},
  "legacy_goal": "Decide what to do with the unfilled remainder of an order.",
  "legacy_pm_signals": [
    "Remaining size vs. original intent",
    "Book state at moment of partial",
    "Strategy's declared partial-fill policy"
  ],
  "legacy_external_feeds": [],
  "reporting_groups": [
    "execution"
  ],
  "network": [
    "polygon"
  ],
  "api_surface": [
    "clob_auth",
    "clob_public",
    "ws_market",
    "internal"
  ],
  "version": {
    "spec": "2.0.0",
    "implementation": "0.1.0",
    "schema": "2",
    "released": null,
    "planned_release": "Q4-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": "Chase orders carry the same builder_code bytes32 as the original order for continuous attribution. Remainder sizes are denominated in pUSD; minimum sizes respect CTFExchangeV2 minimum order constraints."
  },
  "reference_implementation": {
    "pseudocode": "FUNCTION handlePartial(execReport):\n  ks = FETCH internal.killswitch.status\n  IF ks.active:\n    clob_auth.DELETE('/order/' + execReport.order_id)\n    EMIT ExecutionReport(KILL_SWITCH_ACTIVE)\n    RETURN\n\n  remaining = execReport.remaining_usd\n  IF remaining < params.min_remainder_size:\n    clob_auth.DELETE('/order/' + execReport.order_id)\n    EMIT ExecutionReport(PARTIAL_FILL_DUST_AUTO_CANCEL)\n    RETURN\n\n  book = FETCH clob_public.GET('/book?market=' + execReport.market_id)\n  bookDepth = SUM(level.size FOR level IN book.side(execReport.side)[:5])\n\n  IF params.cancel_on_book_thin AND bookDepth < remaining:\n    clob_auth.DELETE('/order/' + execReport.order_id)\n    EMIT ExecutionReport(PARTIAL_FILL_BOOK_THIN_CANCEL)\n    RETURN\n\n  policy = execReport.strategy.partial_fill_policy OR params.default_policy\n\n  IF policy == 'hold':\n    EMIT ExecutionReport(HOLD_REMAINDER)\n  ELIF policy == 'cancel':\n    clob_auth.DELETE('/order/' + execReport.order_id)\n    EMIT ExecutionReport(CANCELLED_REMAINDER)\n  ELIF policy == 'chase':\n    bestPrice = book.best_ask IF execReport.side == 'BUY' ELSE book.best_bid\n    ticksAway = abs(bestPrice - execReport.original_price) / market.tick_size\n    IF ticksAway > params.chase_max_ticks:\n      clob_auth.DELETE('/order/' + execReport.order_id)\n      EMIT ExecutionReport(PARTIAL_FILL_CHASE_ABORTED)\n    ELSE:\n      clob_auth.DELETE('/order/' + execReport.order_id)\n      newOrder = buildOrderTypedData({price: bestPrice, size: remaining,\n                   builder: execReport.builder_code})\n      clob_auth.POST('/order', sign(newOrder))\n      EMIT ExecutionReport(CHASE_ORDER_SUBMITTED)",
    "sdk_calls": [
      "clob_public.GET('/book?market=' + market_id)",
      "clob_auth.DELETE('/order/' + order_id)",
      "clob_auth.POST('/order', signed_chase_order)",
      "buildOrderTypedData({price, size, builder_code})"
    ],
    "complexity": "O(1) per partial fill event"
  },
  "wire_examples": {
    "input": [
      {
        "label": "PARTIAL ExecutionReport from OrderLifecycleManager",
        "source": "exec.orderlifecyclemanager",
        "payload": {
          "order_id": "0xcccc3333dddd4444eeee5555ffff6666aaaa7777bbbb8888cccc9999dddd0000",
          "status": "PARTIAL",
          "filled_usd": 200,
          "remaining_usd": 250,
          "original_price": 0.62,
          "side": "BUY",
          "collateral": "pUSD",
          "builder_code": "0x706f6c7974726164657273000000000000000000000000000000000000000000"
        }
      }
    ],
    "output": [
      {
        "label": "ExecutionReport \u2014 HOLD_REMAINDER",
        "payload": {
          "report_id": "rep_3c4d5e6f7a8b9c0d",
          "bot_id": "exec.partialfillhandler",
          "verdict": "HOLD_REMAINDER",
          "remaining_usd": 250,
          "policy_applied": "hold",
          "collateral": "pUSD",
          "evaluated_at_ms": 1746770100000
        }
      }
    ]
  },
  "reason_codes": [
    {
      "code": "HOLD_REMAINDER",
      "severity": "INFO",
      "meaning": "Remainder left resting on book per hold policy.",
      "action": "No action; emit ExecutionReport.",
      "user_message": "Your order is still open, waiting to be filled."
    },
    {
      "code": "PARTIAL_FILL_DUST_AUTO_CANCEL",
      "severity": "HARD_REJECT",
      "meaning": "Remainder below min_remainder_size; auto-cancelled.",
      "action": "Cancel order; forward to DustAndRoundingCleaner.",
      "user_message": "The tiny remaining portion of your order was cancelled."
    },
    {
      "code": "PARTIAL_FILL_BOOK_THIN_CANCEL",
      "severity": "WARN",
      "meaning": "Book depth < remaining_usd and cancel_on_book_thin=true.",
      "action": "Cancel remainder.",
      "user_message": "The market was too thin to fill your remaining order; it was cancelled."
    },
    {
      "code": "PARTIAL_FILL_CHASE_ABORTED",
      "severity": "WARN",
      "meaning": "Chase ticks exceeded chase_max_ticks; remainder cancelled instead.",
      "action": "Cancel remainder; do not chase.",
      "user_message": "The remaining order could not be filled at a reasonable price and was cancelled."
    },
    {
      "code": "KILL_SWITCH_ACTIVE",
      "severity": "HARD_REJECT",
      "meaning": "KillSwitch active; remainder cancelled immediately.",
      "action": "Cancel remainder; halt.",
      "user_message": "Trading is currently paused."
    }
  ],
  "metrics": {
    "emitted": [
      {
        "name": "polytraders_exec_partialfillhandler_decisions_total",
        "type": "counter",
        "unit": "count",
        "labels": [
          "verdict"
        ],
        "meaning": "Total partial fill decisions by verdict (HOLD/CANCEL/CHASE/DUST)."
      },
      {
        "name": "polytraders_exec_partialfillhandler_remainder_usd",
        "type": "histogram",
        "unit": "pUSD",
        "labels": [],
        "meaning": "Distribution of remainder sizes at time of partial fill decision."
      },
      {
        "name": "polytraders_exec_partialfillhandler_chase_ticks",
        "type": "histogram",
        "unit": "count",
        "labels": [],
        "meaning": "Distribution of ticks-to-fill on chase decisions; values > chase_max_ticks trigger aborts."
      }
    ],
    "alerts": [
      {
        "name": "PFHHighDustRate",
        "condition": "rate(polytraders_exec_partialfillhandler_decisions_total{verdict='PARTIAL_FILL_DUST_AUTO_CANCEL'}[5m]) > 0.2",
        "severity": "P2",
        "runbook": "#runbook-pfh-dust"
      },
      {
        "name": "PFHChaseAbortRate",
        "condition": "rate(polytraders_exec_partialfillhandler_decisions_total{verdict='PARTIAL_FILL_CHASE_ABORTED'}[5m]) > 0.1",
        "severity": "P2",
        "runbook": "#runbook-pfh-chase"
      }
    ]
  },
  "state": {
    "store": "in-memory per order",
    "shape": "Per order: {order_id, remaining_usd, policy, decision_ts_ms}",
    "ttl": "Cleared on terminal state (FILLED/CANCELLED)",
    "recovery": "State rebuilt from OrderLifecycleManager on restart via PARTIAL events.",
    "size_estimate": "~150 bytes per active partial; ~15 KB for 100 concurrent partials"
  },
  "concurrency": {
    "execution_model": "per-order goroutine",
    "max_in_flight": 50,
    "idempotency_key": "order_id + event_ts_ms",
    "timeout_ms": 300,
    "backpressure": "shed excess if > 50 partials in flight",
    "locking": "per-order_id mutex to prevent double-cancel on rapid partial events"
  },
  "dependencies": {
    "depends_on": [
      {
        "bot_id": "exec.orderlifecyclemanager",
        "why": "Source of PARTIAL ExecutionReport with remaining_usd and original_price.",
        "contract": "Activates only on PARTIAL status events."
      },
      {
        "bot_id": "risk.kill_switch",
        "why": "KillSwitch forces immediate remainder cancel.",
        "contract": "No remainder survives active KillSwitch."
      }
    ],
    "emits_to": [
      {
        "bot_id": "exec.cancelreplaceoptimizer",
        "why": "Chase policy delegates to CancelReplaceOptimizer for optimal cancel+replace sequencing.",
        "contract": "CancelReplaceOptimizer receives cancel+new_order instruction."
      },
      {
        "bot_id": "exec.dustandroundingcleaner",
        "why": "Dust remainders forwarded for sweep handling.",
        "contract": "Dust remainder passed with original order_id."
      }
    ],
    "sibling": [],
    "external": [
      {
        "service": "CLOB V2 auth API",
        "endpoint": "https://clob.polymarket.com",
        "sla": "99.95% / 200ms p99",
        "failure_mode": "If cancel fails, retry up to 2 times; emit WARN on persistent failure."
      },
      {
        "service": "CLOB V2 public API",
        "endpoint": "https://clob.polymarket.com",
        "sla": "99.9% / 200ms p99",
        "failure_mode": "If book unavailable, apply hold policy conservatively."
      }
    ]
  },
  "security_surfaces": {
    "signs_orders": true,
    "private_key_access": "signing-only",
    "abuse_vectors": [
      "Injecting a PARTIAL event with inflated remaining_usd to trigger an oversized chase order",
      "Forcing book-thin cancel by poisoning the book depth snapshot"
    ],
    "mitigations": [
      "PARTIAL ExecutionReport validated against OrderLifecycleManager HMAC",
      "Chase order size capped at original remaining_usd; cannot exceed intent size"
    ]
  },
  "failure_injection": [
    {
      "scenario": "BOOK_THIN_ON_PARTIAL",
      "how_to_inject": "Drain order book to < 10 pUSD depth on target market side",
      "expected_behaviour": "cancel_on_book_thin fires; PARTIAL_FILL_BOOK_THIN_CANCEL emitted; remainder cancelled",
      "recovery": "Automatic on next partial; book depth re-evaluated"
    },
    {
      "scenario": "CHASE_TICKS_EXCEEDED",
      "how_to_inject": "Move market 15 ticks from original price before partial fill, policy=chase",
      "expected_behaviour": "ticksAway=15 > chase_max_ticks=3; PARTIAL_FILL_CHASE_ABORTED; remainder cancelled",
      "recovery": "Automatic"
    },
    {
      "scenario": "KILL_SWITCH_ON_PARTIAL",
      "how_to_inject": "Activate KillSwitch during active partial fill",
      "expected_behaviour": "Remainder immediately cancelled; KILL_SWITCH_ACTIVE emitted; no chase attempted",
      "recovery": "Manual KillSwitch reset"
    }
  ],
  "runbook": {
    "summary": "PartialFillHandler incidents are usually high dust-cancel rates (strategy sizing too small) or chase-abort spikes (market moving too fast for chase policy).",
    "oncall_actions": [
      {
        "alert": "PFHHighDustRate",
        "first_step": "Check strategy min order sizes; if too small, increase min_remainder_size or adjust strategy minimum.",
        "diagnosis": "",
        "mitigation": "",
        "escalation": "Strategy pod lead"
      },
      {
        "alert": "PFHChaseAbortRate",
        "first_step": "Check market volatility; if high, consider switching affected strategies to hold or cancel policy.",
        "diagnosis": "",
        "mitigation": "",
        "escalation": "Exec pod lead"
      }
    ],
    "manual_overrides": [
      {
        "name": "force_cancel_remainder",
        "how": "polytraders bot cancel-remainder exec.partialfillhandler --order <order_id>",
        "when": "Manual remainder cancellation needed when auto-policy is stuck.",
        "command": "polytraders bot cancel-remainder exec.partialfillhandler --order <order_id>",
        "effect": "Manual remainder cancellation needed when auto-policy is stuck."
      }
    ],
    "healthcheck": "GET /internal/health/partialfillhandler \u2192 green if clob_auth reachable, clob_public reachable, dust_cancel_rate < 0.2/min, chase_abort_rate < 0.1/min; red if clob_auth unreachable, dust_cancel_rate > 1/min, chase_abort_rate > 0.5/min"
  },
  "promotion_gates": {
    "to_shadow": [
      {
        "gate": "All unit tests pass including dust and book-thin scenarios",
        "how_measured": "CI test run",
        "threshold": "100% pass"
      }
    ],
    "to_limited_live": [
      {
        "gate": "Chase order price invariant verified: no chase order exceeds original_price + chase_max_ticks * tick_size",
        "how_measured": "Property test over 48h shadow run",
        "threshold": "Zero violations"
      }
    ],
    "to_general_live": [
      {
        "gate": "Dust cancel rate < 5% of all partial fills over 7-day limited-live",
        "how_measured": "polytraders_exec_partialfillhandler_decisions_total",
        "threshold": "< 5%"
      }
    ]
  },
  "reporting": {
    "emits_kinds": [
      "ExecutionReport"
    ],
    "topics": [
      "polytraders.reports.execution"
    ],
    "partition_key": "trace_id",
    "cadence": "every-event",
    "retention_class": "7y",
    "sampling_rule": "emit-every",
    "bus_failure_action": "wal-then-retry",
    "user_visible": "yes",
    "consumes_kinds": [
      "DecisionReport"
    ]
  },
  "capital_impact": "Direct",
  "mode_support": [
    "quarantine"
  ],
  "v3_status": {
    "phase": 5,
    "phase_name": "Execution rails",
    "docs": {
      "done": 27,
      "total": 27,
      "state": "done"
    },
    "impl": {
      "done": 0,
      "total": 15,
      "state": "pending"
    },
    "runtime": {
      "done": 0,
      "total": 8,
      "state": "pending"
    },
    "overall": "pending"
  }
}