Polytraders Dev Guide
internal
Phase 1 · 9/109 wired

RiskGate

There is exactly one code path that signs and submits an order. Every intent goes through it — from a user bot, from an AI suggestion, from a manual click, from one of our own strategies. No exceptions, no fast path, no admin bypass.

The invariant. If you can find a second way to reach the venue, that is a P0 bug, not a shortcut. The value of a guardrail chain is exactly zero if it can be routed around, and a chain with one bypass is worse than no chain because it is trusted without being trustworthy.

Why this is a page and not a convention

The bot interface already says a bot "must not submit orders directly". That is a convention, and a convention is a reasonable control for code we write and review. It is not a control for code a stranger uploads. RiskGate turns the convention into structure: user code physically cannot hold a signer, so the rule holds whether or not the author intended to follow it.

The path

proposal  (user bot | AI suggestion | manual | our strategy)
    │
    ├─ 1. ADMISSION      scope, schema, freshness, bot state
    │                    reject ⇒ RISK_ADMISSION_*
    │
    ├─ 2. HARD GUARDRAILS run in order, any REJECT ends it
    │      killswitch          → RISK_KILLSWITCH_TRIPPED
    │      compliancegate      → RISK_GEOFENCE_BLOCK
    │      markethaltguard     → RISK_MARKET_HALTED
    │      stalebookguard      → RISK_BOOK_STALE_15S
    │      selftradewashguard  → RISK_SELF_TRADE
    │      contractaddrguard   → SEC_CONTRACT_MISMATCH
    │
    ├─ 3. ENVELOPE CHECKS user-tunable above the platform floor
    │      exposureguard       → RISK_EXPOSURE_CAP
    │      drawdownguard       → RISK_DRAWDOWN_LIMIT
    │      correlationshock    → RISK_CORRELATED_EXPOSURE
    │      liquidityguard      → RISK_INSUFFICIENT_DEPTH
    │      feeandgasguard      → RISK_FEE_UNECONOMIC
    │
    ├─ 4. SHAPING         may downsize or re-price, never flip direction
    │      smartrouter, antitoxicfill, pricebandvalidator,
    │      queuewarden, fee_slippage_estimator
    │
    ├─ 5. ATOMIC RESERVE  reserve exposure INCLUDING pending + partials
    │                    reject ⇒ RISK_RESERVE_CONFLICT
    │
    ├─ 6. SIGN            scoped session key, method whitelist
    │                    refusal ⇒ SEC_SIGNATURE_REFUSED
    │
    └─ 7. SUBMIT + RECONCILE
                         mismatch ⇒ freeze, GOV_RECONCILE_MISMATCH

What the user may and may not change

StageUser controlRationale
AdmissionNoneStructural. A malformed proposal is not a preference.
Hard guardrailsNone. Cannot disable, reorder, or threshold.These encode legal, venue, and integrity constraints, not risk appetite.
Envelope checksMay tighten below the platform floor. May not loosen above it.Risk appetite is genuinely the user's, bounded by what the platform can survive.
ShapingMay express a preference (passive vs. aggressive) within bounds.Execution style is a legitimate choice; it cannot change intent.
Atomic reserveNoneCorrectness, not policy.
SignGrants and revokes scope. Cannot widen the method whitelist.See the signing model.
ReconcileNoneA user who could disable reconciliation could hide a loss from themselves.

Three caps, not one

A frequent design error is a single per-order cap. Three independent caps are required, and a proposal must satisfy all three:

Pending orders count. Exposure that only counts filled positions is not exposure. risk.portfolioguard currently checks open positions only; making the reserve atomic over filled + pending + partial is a prerequisite for running any second strategy, let alone somebody else's.

Correlation is a first-class cap

Prediction markets correlate in ways that are not obvious from market ids. Two markets on the same game, on the same team's season, on the same election, or resolving from the same oracle are one bet wearing several hats. The chain therefore evaluates a correlation cluster, not a market, using intel.crossmarketgraph and risk.correlationshockguard.

The user's max_correlated_exposure_pct applies to the cluster. A user who does not understand this will otherwise believe they hold six diversified positions while holding one position six times.

Reject, reshape, quarantine

OutcomeMeaningRetryUser sees
REJECTNot permitted now.Yes, on the next tick if conditions change.Reason code plus a plain-English line.
RESHAPEPermitted smaller or at a different price.Proceeds as reshaped; original is recorded.Both the original and the shaped order.
QUARANTINEThis bot is not permitted to propose at all.No. Requires explicit user re-enable.A prominent state on the bot page and a notification.
FREEZEReconciliation mismatch. The whole account stops.No. Requires operator investigation.An incident, not a warning.

Every outcome carries a code from the reason-code registry. Free text is not an acceptable substitute: the user's log, the notification, the audit trail, and the analytics all key off the code.

Failing closed

If a guardrail cannot reach the data it needs to make a decision, the answer is REJECT. Not "allow because the check is unavailable". This is the single most common way trading systems lose money in ways nobody predicted, and it usually enters the codebase as a reasonable-looking try/catch with a permissive default.

// WRONG — fails open. Ships as a "resilience" improvement.
try { vote = await exposureGuard.check(intent); }
catch { vote = ALLOW; }

// RIGHT — fails closed, and says why.
try { vote = await exposureGuard.check(intent); }
catch (e) { vote = REJECT("RISK_GUARD_UNAVAILABLE", { guard: "exposure", err: e }); }

the four invariants · these are not negotiable

  1. 1

    The platform never holds user funds.

    Keys stay in the user's wallet. There is no platform-controlled omnibus account, no internal ledger of custodied balances, and no code path that can move a user's assets without a signature the user authorised. If a feature needs custody to work, it does not ship.

  2. 2

    A user bot never reaches the venue directly.

    User-authored logic produces a proposal. It never holds a venue client, an API key, or a signer. Exactly one component signs and submits, and it is ours.

  3. 3

    Guardrails cannot be configured away.

    The user tunes thresholds inside bounds we set. The user cannot remove a guardrail from the chain, reorder the chain, or lower a hard cap below the platform floor.

  4. 4

    AI never holds Trade authority.

    Model output is advisory. An AI suggestion enters the same RiskGate as any bot intent and is subject to the same rejects. There is no path from a model response to a signed order that skips the chain.

If a design requires breaking one of these, the design is wrong. Escalate before writing code — do not work around it. See RiskGate and the signing model.