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

Principles & schemas

The locked rules that survive every rewrite. Read this once, then again before you ship.

Positioning rules

Authority hierarchy

Risk > Security > Execution > Strategy > Discovery > Intelligence > Governance. A higher layer can always block a lower one. Governance never blocks anything; it explains.

The six standard schemas

OrderIntent — Strategy → Risk (Polymarket V2)

type OrderIntent = {
  intent_id: string;          // UUIDv4 — idempotency key for the entire pipeline
  strategy_id: string;        // which strategy emitted it
  market_id: string;          // Polymarket condition_id (bytes32 hex)
  outcome_id: string;         // YES or NO token id
  side: "BUY" | "SELL";
  size_usd: number;           // pUSD notional
  price: number;              // 0.001..0.999 (tick = 0.001)
  order_type: "LIMIT" | "MARKET" | "POST_ONLY" | "GTC" | "GTD" | "FOK" | "IOC";
  time_in_force?: number;     // seconds
  reduce_only?: boolean;
  // V2 builder attribution — native field, NOT HMAC headers
  builder?: { code: string;       // bytes32 builderCode
              fee_bps: number };  // ≤ 100 taker, ≤ 50 maker
  // V2 negative-risk awareness
  negrisk_aware?: boolean;
  emitted_at: string;         // ISO 8601
};

// NOTE: fees are NOT on the signed order in V2. The operator sets fees at
// match time. Only the BUILDER fee rate (capped) is on the order.

RiskVote — every Risk bot

type RiskDecision = "APPROVE" | "RESHAPE_REQUIRED" | "REJECT" | "WARNING_ONLY";
type RiskVote = {
  guard_id: string;
  decision: RiskDecision;
  severity: "INFO" | "WARN" | "P1" | "P0";
  reason_code: string;        // UPPER_SNAKE, stable, machine-readable
  message: string;
  constraints?: {
    max_size_usd?: number;
    max_price?: number;
    min_price?: number;
    passive_only?: boolean;
    close_only?: boolean;
    cooldown_seconds?: number;
    require_manual_review?: boolean;
  };
  inputs_used: string[];
  checked_at: string;
};

ExecutionPlan — Risk → Execution

type ExecutionPlan = {
  plan_id: string;
  intent_id: string;
  effective_size_usd: number;
  effective_price: number;
  order_type: OrderIntent["order_type"];
  passive_only: boolean;
  close_only: boolean;
  builder?: { code: string; fee_bps: number };
  constraints_applied: RiskVote[];
  approved_at: string;
};

SecurityCheck — Security layer

type SecurityCheck = {
  check_id: string;
  scope: "wallet" | "contract" | "session" | "signing";
  decision: "ALLOW" | "DENY" | "REQUIRE_2FA" | "PAUSE";
  reason_code: string;
  evidence: Record<string, unknown>;
  checked_at: string;
};

GovernanceLog — Governance layer

type GovernanceLog = {
  log_id: string;
  kind: "config_change" | "incident" | "manual_override" | "reconciliation" | "audit";
  actor: string;
  target: string;
  before?: unknown;
  after?: unknown;
  reason: string;
  evidence_uri?: string;
  created_at: string;
};

PostTradeExplanation — Governance

type PostTradeExplanation = {
  fill_id: string;
  intent_id: string;
  user_summary: string;       // plain English, no jargon
  guards_consulted: { guard_id: string; decision: string; reason_code: string }[];
  exec_path: string[];        // SmartRouter trail
  builder_attribution?: { code: string; fee_bps: number };
  generated_at: string;
};

Reason-code rules

Default-value guidance

Bot statusDefault posture
PlannedConservative specification only. No live impact.
BetaConservative defaults, low caps, manual review on edge cases.
Limited liveConservative defaults, explicit override process required.
General liveDefaults may relax only with performance + incident data.
AdvancedManual review, capped exposure, full explanation always.

Threshold standards

TypeMeaning
InformationalBot logs but takes no action.
WarningBot reports concern but does not block.
Soft constraintBot downsizes, delays, or changes execution mode.
Hard constraintBot rejects, pauses, or requires manual review.
Locked ruleCannot be changed by user or strategy.

Implementation references

Each link below opens a focused sub-page covering one slice of the implementation surface. Read in order if you are new; jump in if you know what you need.

Do not build

These ten patterns are forbidden. They are the easiest mistakes to make and the most expensive ones to catch in production.

Forbidden patternWhy
Strategy bot submitting orders directlyBypasses the Risk pipeline. Any code path from Strategy to the signer that does not pass through Risk is a P0 review block.
Bot consuming raw Polymarket payloadsInconsistent shape, no freshness stamp, no provenance hash. All consumers read normalised objects from the data-flow layer.
Bot emitting free-text errors onlyBreaks monitoring, dashboards, replay and audit. Every emission carries a reason_code from the registry.
Bot using unversioned configMakes incidents impossible to reproduce. BotConfig.configVersion is mandatory and lives in every emitted envelope.
Bot silently failing openThe most dangerous pattern in trading systems. The documented safe_fallback must fire on every failure mode.
Bot with hard-coded market IDs or contract addressesNot reusable, breaks on every Polymarket migration. They live in BotConfig and are validated against the on-chain registry by Security.
Bot with no shadow-mode pathCannot safely test live. Every bot supports off + shadow + enforced at minimum; many also support advisory and quarantine.
Scoring documentation completeness as readinessA 27/27 docs score means the spec is complete &mdash; not that the bot is implemented, tested under load, or running in shadow. v3 splits readiness into three scores (docs, impl, runtime) so this stops being possible.
Risk evaluating orders before Strategy emits an OrderIntentRisk has no input until Strategy decides. The pipeline order is Discovery &rarr; Intel &rarr; Strategy emits OrderIntent &rarr; Risk &rarr; Execution. Reordering this is the single most common architecture mistake in v2.
Shipping a bot config without a declared parameter search spaceEvery tunable bot must declare a SEARCH_SPACE in its config schema (min, max, type per parameter). Without it the optimizer cannot tune the bot, the docs page cannot render sliders, and human reviewers cannot verify the config falls inside a sane range.

Final instruction

Do not expand the bot library by adding more bot names. Expand it by making each bot implementable. A good bot page should allow a developer to build the first version without asking: what data do I need? what parameters exist? what are the defaults? what should happen if the data is missing? when should it reject? what does it log? what does the user see? how do I know it is ready to ship?