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
HomeBy LayerGovernance6.8 StrategyRegistry

6.8 StrategyRegistry

Governance Governance Service Explain PLANNED Spec started capital · Indirect P7 · Governance & replay pending flagship stub

StrategyRegistry is the single source of truth for which strategy is at which lifecycle stage and under what authority. It stores stage metadata, promotion history, linked artefacts, and live-cap policy.

v3 readiness

Docs27/27
donehow scored
Impl0/15
pendinghow scored
Backtest0/4
pendinghow scored
Runtime0/8
pendinghow scored

A bot is done when all four scores are. What does done mean?

1. Bot Identity

LayerGovernance  Governance
Bot classGovernance Service
AuthorityExplain
StatusPLANNED
ReadinessSpec started
Runs beforeBacktester, ExperimentTracker, ExecRouter — any bot that needs to know a strategy's current stage
Runs afterGovernance pod promotion review
Applies toEvery registered strategy bot at every lifecycle stage
Default modeshadow_only
User-visibleno
Developer ownerPolytraders core

2. Purpose

StrategyRegistry is the single source of truth for which strategy is at which lifecycle stage and under what authority. It stores stage metadata, promotion history, linked artefacts, and live-cap policy.

3. Why This Bot Matters

  • No centralised registry

    Multiple bots may execute strategies at conflicting stages, making audits impossible.

  • Promotion without recorded approval

    Compliance audit finds no evidence trail; promotion may need to be reversed.

No worked examples on this bot yet. Worked examples are optional but strongly recommended — they turn an abstract failure mode into something a developer can verify in a fixture.

4. Required Polymarket Inputs

InputSourceRequired?Use
None — StrategyRegistry is a pure internal governance storeinternalNoN/A

5. Required Internal Inputs

InputSourceRequired?Use
Promotion requests from governance podinternalYesRecord stage transitions and approver identities.
Backtest report artefact referencegov.backtesterYesLink the artefact to the strategy record before shadow promotion.

6. Parameter Guide

ParameterDefaultWarningHardWhat it controls
require_two_person_promotion['to_limited_live', 'to_general_live']NoneNoneList of stage transitions that require two distinct approvers.
min_shadow_days3730Minimum days a strategy must run in shadow before limited-live promotion.

7. Detailed Parameter Instructions

require_two_person_promotion

What it means

List of stage transitions that require two distinct approvers.

Default

{ "require_two_person_promotion": ["to_limited_live", "to_general_live"] }

Why this default matters

Two-person rule prevents a single engineer from promoting to live unilaterally.

Threshold logic

ConditionAction
transition in require_two_person_promotionRequire second approver before writing stage change

Developer check

if stage in p.require_two_person_promotion and approvers.count < 2: raise ConfigError

User-facing English

Critical promotions require approval from two team members.

min_shadow_days

What it means

Minimum days a strategy must run in shadow before limited-live promotion.

Default

{ "min_shadow_days": 3 }

Why this default matters

3 days provides enough data for initial statistical comparison.

Threshold logic

ConditionAction
shadow_days < min_shadow_daysBlock promotion; emit PROMOTION_GATE_FAILED

Developer check

if shadow_days < p.min_shadow_days: raise PromotionError('PROMOTION_GATE_FAILED')

User-facing English

Strategies run in shadow mode for at least 3 days before going live.

8. Default Configuration

{
  "bot_id": "gov.strategyregistry",
  "version": "0.1.0",
  "mode": "shadow_only",
  "defaults": {
    "require_two_person_promotion": [
      "to_limited_live",
      "to_general_live"
    ],
    "min_shadow_days": 3,
    "min_backtest_days": 7,
    "auto_demote_on_drift": true
  }
}

9. Implementation Flow

  1. On startup, load the strategy registry table from Postgres; index by slug.
  2. When a promotion request arrives, validate artefacts and approver count against promotion gates.
  3. Write stage change to registry with timestamp, approver IDs, and linked artefact references.
  4. Emit OperationsReport(event_type=STRATEGY_PROMOTED) to polytraders.reports.operations.
  5. On drift signal from ExperimentTracker, auto-demote to previous stage if auto_demote_on_drift=true.
  6. Provide read API for other bots to query current strategy stage and live-cap.

10. Reference Implementation

Pseudocode is language-agnostic. FETCH = read input. EMIT = produce output. IF/THEN/ELSE = decision. Translate directly to TypeScript, Python, Go, or Rust.

// ---- STARTUP ----
FUNCTION init():
  registry = postgres.loadAll('strategy_registry')
  indexBySlug(registry)

// ---- PROMOTION REQUEST ----
FUNCTION handlePromotionRequest(req):
  entry = registry.get(req.slug)
  IF entry IS NULL: RAISE 'STRATEGY_NOT_FOUND'
  IF NOT artefactsPresent(entry, req.to_stage): RAISE 'PROMOTION_GATE_FAILED'
  IF req.to_stage IN config.require_two_person_promotion:
    IF len(req.approvers) < 2: RAISE 'PROMOTION_GATE_FAILED'
  IF entry.stage == 'shadow' AND entry.shadow_days < config.min_shadow_days:
    RAISE 'PROMOTION_GATE_FAILED'
  entry.stage = req.to_stage
  entry.updated_at = now()
  postgres.upsert('strategy_registry', entry)
  EMIT OperationsReport(event_type='STRATEGY_PROMOTED', slug=req.slug,
    from_stage=entry.prev_stage, to_stage=req.to_stage,
    approvers=req.approvers)

// ---- DRIFT AUTO-DEMOTE ----
FUNCTION onDriftSignal(slug):
  IF config.auto_demote_on_drift:
    entry = registry.get(slug)
    entry.stage = entry.prev_stage
    postgres.upsert('strategy_registry', entry)
    EMIT OperationsReport(event_type='STRATEGY_DEMOTED', slug=slug)
  ELSE:
    EMIT OperationsReport(event_type='STRATEGY_DRIFT_DETECTED', slug=slug)

SDK calls used

  • postgres.loadAll('strategy_registry')
  • postgres.upsert('strategy_registry', entry)
  • alerting.emit('PROMOTION_GATE_FAILED', metadata)

Complexity: O(1) per promotion request; O(N) on startup where N = registered strategies

11. Wire Examples

Input — what arrives on the wire

{
  "label": "Promotion request",
  "source": "governance_pod",
  "payload": {
    "slug": "sports-model",
    "from_stage": "shadow",
    "to_stage": "limited_live",
    "approvers": [
      "alice@polytraders",
      "bob@polytraders"
    ],
    "artefacts": {
      "shadow_report": "sh_01HX9Y"
    }
  }
}

Output — what the bot emits

{
  "label": "OperationsReport — STRATEGY_PROMOTED",
  "payload": {
    "report_id": "ops_strategyregistry_01HX9Z",
    "bot_id": "gov.strategyregistry",
    "event_type": "STRATEGY_PROMOTED",
    "slug": "sports-model",
    "to_stage": "limited_live",
    "report_kind": "OperationsReport",
    "topic": "polytraders.reports.operations"
  }
}

12. Decision Logic

APPROVE

Not applicable — StrategyRegistry records decisions made by governance pod humans.

RESHAPE_REQUIRED

Not applicable.

REJECT

Rejects promotion if gates are not met; emits PROMOTION_GATE_FAILED.

WARNING_ONLY

Emits STRATEGY_DRIFT_DETECTED if auto-demote criteria met but auto_demote is disabled.

13. Standard Decision Output

This bot returns a OperationsReport object. See OperationsReport schema.

{
  "report_id": "ops_strategyregistry_01HX9Z",
  "bot_id": "gov.strategyregistry",
  "event_type": "STRATEGY_PROMOTED",
  "slug": "sports-model",
  "from_stage": "shadow",
  "to_stage": "limited_live",
  "approvers": [
    "alice@polytraders",
    "bob@polytraders"
  ],
  "artefacts": {
    "backtest_report": "bt_01HX8Z",
    "shadow_report": "sh_01HX9Y"
  },
  "report_kind": "OperationsReport",
  "topic": "polytraders.reports.operations",
  "retained_until": "2027-05-09"
}

14. Reason Codes

CodeSeverityMeaningActionUser-facing message
STRATEGY_PROMOTEDINFOA strategy was successfully promoted to the next stage.Log and emit OperationsReport.
STRATEGY_DEMOTEDWARNA strategy was demoted due to drift.Record demotion; emit OperationsReport.
PROMOTION_GATE_FAILEDHARD_REJECTA promotion request did not meet the required gates.Reject promotion; emit alert.
STRATEGY_DRIFT_DETECTEDWARNDrift signal received; auto-demote disabled.Emit WARN; no stage change.
KILL_SWITCH_ACTIVEWARNKillSwitch active; promotion requests are deferred.Defer request; emit WARN.

15. Metrics & Logs

Metrics emitted

MetricTypeUnitLabelsMeaning
polytraders_gov_strategyregistry_promotions_totalcountercountslug, to_stageTotal successful stage promotions.
polytraders_gov_strategyregistry_demotions_totalcountercountslugTotal auto-demotions triggered by drift.
polytraders_gov_strategyregistry_gate_failures_totalcountercountslug, gateTotal promotion gate failures.
polytraders_gov_strategyregistry_registry_sizegaugecountCurrent number of registered strategies.

Alerts

AlertConditionSeverityRunbook
StrategyRegistryGateFailurerate(polytraders_gov_strategyregistry_gate_failures_total[10m]) > 0P2#runbook-strategyregistry-gate
StrategyRegistryDBUnreachableabsent(polytraders_gov_strategyregistry_registry_size)P1#runbook-strategyregistry-db

16. Developer Reporting

{
  "bot_id": "gov.strategyregistry",
  "event_type": "REGISTRY_QUERY",
  "slug": "sports-model",
  "stage": "limited_live",
  "queried_at_ms": 1746792060000
}

17. Plain-English Reporting

SituationUser-facing explanation
Strategy promoted to limited liveThe strategy passed its shadow-mode review and has been approved for limited live operation.
Promotion blockedThe strategy has not met all required checks for this stage.

18. Failure-Mode Block

main_failure_modePostgres registry store is unavailable; bots cannot query stage metadata.
false_positive_riskAuto-demotion triggered by a transient drift spike rather than a genuine regression.
false_negative_riskPromotion gate artefacts are present but stale; gate passes on outdated data.
safe_fallbackIf registry is unavailable, bots default to the last known stage cached in memory.
required_dependenciesPostgres registry store, gov.backtester artefact store, gov.experimenttracker drift signal

19. Failure-Injection Recipes

ScenarioHow to injectExpected behaviourRecovery
DB_UNAVAILABLEKill Postgres connection during promotion requestWrites flush when Postgres recovers.
GATE_FAILURESubmit promotion with shadow_days=0Fix artefacts and resubmit.
DRIFT_AUTO_DEMOTESend drift signal for a limited_live strategyRe-run shadow period and re-promote.

20. State & Persistence

Cold-start recovery

On restart, reload registry from Postgres immediately.

21. Concurrency & Idempotency

AspectSpecification
Execution modelsingle-threaded event loop with serialised write lock per slug
Max in-flight10
Idempotency keyslug + to_stage + timestamp
Per-call timeout (ms)2000
Backpressure strategyqueue
Locking / mutual exclusionPostgres row-level lock per slug on write

22. Dependencies

Depends on (must run first)

BotWhyContract
gov.backtesterBacktest artefact references required for promotion gates.Artefact ID must be present and valid.

Emits to (downstream consumers)

BotWhyContract
internal.governance_audit

Sibling bots (same OrderIntent)

BotWhyContract
gov.experimenttrackerExperimentTracker sends drift signals that can trigger auto-demotion.Drift signal carries slug.

External services

ServiceEndpointSLA assumedOn failure
Internal Postgrespostgres://internal99.9%Serve cached stage from memory; queue writes until Postgres is reachable.

23. Security Surfaces

Abuse vectors considered

  • Submitting a promotion request with forged approver identity
  • Bypassing two-person rule by replaying a previous approval token

Mitigations

  • Approver identities are verified via internal auth; promotion events are immutably audit-logged
  • Idempotency key prevents replay of a previous approval

24. Polymarket V2 Compatibility

AspectValue
CLOB versionv2
Collateral assetpUSD
EIP-712 Exchange domain version2
Aware of builderCode fieldno
Aware of negative-risk marketsno
Multi-chain readyno
SDK usedpy-clob-client-v2
Settlement contractCTFExchangeV2
NotesStrategyRegistry is a pure internal governance store; no direct CLOB calls. Spec designed against V2 pUSD denomination.

API surfaces declared

internal

Networks supported

polygon

25. Versioning & Migration

FieldValue
spec2.0.0
implementation0.1.0
schema2
releasedNone
planned_releaseQ3-2026

Migration history

DateFromToReasonAction taken
2026-04-28n/av2-specSpec drafted post-CLOB-V2 cutover; bot not yet implementedDesigned against V2 schema (pUSD, builder codes, V2 EIP-712 domain)

26. Acceptance Tests

Unit Tests

TestSetupExpected result
Promotion blocked when min_shadow_days not metshadow_days=1, min_shadow_days=3PROMOTION_GATE_FAILED
Two-person rule enforced for to_general_liveapprovers=['alice']PROMOTION_GATE_FAILED

Integration Tests

TestExpected result
Full promotion lifecycle: research → backtest → shadow → limited_live emits correct OperationsReport chain4 OperationsReport records, each with correct stage transition

Property Tests

PropertyRequired behaviour
Every stage transition is recorded with approver IDs and artefact referencesAlways true

27. Operational Runbook

StrategyRegistry incidents involve DB unavailability or unexpected demotions. Every PROMOTION_GATE_FAILED is informational unless it blocks a scheduled launch.

On-call actions

AlertFirst stepDiagnosisMitigationEscalate to
StrategyRegistryDBUnreachable
StrategyRegistryGateFailure

Manual overrides

Healthcheck

/internal/health/strategyregistry → green if Postgres reachable; registry loaded; last write < 1h ago; red if Postgres unreachable or registry empty

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

GateHow measuredThreshold
Unit tests for gate validation passCI100% pass

Promote to Limited live

GateHow measuredThreshold
Postgres write integration test passesIntegration testPass

Promote to General live

GateHow measuredThreshold
One successful end-to-end promotion lifecycle recorded in stagingE2E testPass

29. Developer Checklist

Ready-to-ship score: 27/27 sections complete · 100%

RequirementStatus
Purpose defined✓ done
Required inputs listed✓ done
Parameters defined✓ done
Defaults defined✓ done
Warning thresholds defined✓ done
Hard thresholds defined✓ done
Safe fallback defined✓ done
Structured output defined✓ done
Developer log defined✓ done
Plain-English explanation✓ done
Unit tests defined✓ done
Integration tests defined✓ done
Property tests defined✓ done
Failure-mode block complete✓ done
Reference implementation pseudocode✓ done
Wire examples (input + output)✓ done
Reason codes listed✓ done
Metrics & logs defined✓ done
State & persistence defined✓ done
Concurrency & idempotency defined✓ done
Dependencies declared✓ done
Security surfaces declared✓ done
Polymarket V2 compatibility declared✓ done
Version & migration history declared✓ done
Operational runbook defined✓ done
Promotion gates defined✓ done
Failure-injection recipes defined✓ done