2.15 OrderAmendCancelManager
Owns every amend and cancel operation against the CLOB for orders Polytraders has placed. Strategies do not cancel directly — they emit an OrderAdjustment intent which this bot validates, sequences, and submits via the EIP-712 v2 envelope. Maintains a strict monotonic intent sequence per order so cancels can never race amends.
v3 readiness
A bot is done when all four scores are. What does done mean?
1. Bot Identity
| Layer | Execution Execution |
|---|---|
| Bot class | ExecutionUtility |
| Authority | AmendCancel |
| Status | PLANNED |
| Readiness | Spec ready |
| Runs before | — |
| Runs after | exec.order_lifecycle_manager |
| Applies to | Continuous |
| Default mode | shadow |
| User-visible | Yes |
| Developer owner | Execution pod |
Operational profile
| Ownership | Execution pod · on-call exec-oncall · #polytraders-exec · escalates to Head of Execution · P1 |
|---|---|
| Latency budget | p50: 25ms · p99: 250ms |
| Modes supported | offshadowadvisoryenforcedquarantine |
| Data freshness | max_market_data_age_ms=5000 · max_orderbook_age_ms=5000 · on stale → Reject the adjustment with EXEC_AMEND_STALE_VIEW. |
| Human override | yes · by Execution on-call · logs EXEC_AMEND_OVERRIDE · time-bound: Per incident · scope: Single order_id · second approval required |
2. Purpose
Owns every amend and cancel operation against the CLOB for orders Polytraders has placed. Strategies do not cancel directly — they emit an OrderAdjustment intent which this bot validates, sequences, and submits via the EIP-712 v2 envelope. Maintains a strict monotonic intent sequence per order so cancels can never race amends.
3. Why This Bot Matters
Race conditions on cancel/amend
Without a single sequencer, two strategies can race each other to amend the same order, producing inconsistent CLOB state.
Phantom cancels
A cancel that fails silently leaves an order resting that strategy code believes has been killed; mismatched state causes self-trades and over-positioning.
Amend bypasses risk
An 'amend size from 100 to 500' looks like a cancel-and-place but bypasses Risk if not routed through this bot.
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
| Input | Source | Required? | Use |
|---|---|---|---|
| CLOB v2 amend/cancel endpoints | CLOB | Yes | The actual targets for the action. |
| Order ack/reject events | WebSocket | Yes | Confirm or fail each operation. |
5. Required Internal Inputs
| Input | Source | Required? | Use |
|---|---|---|---|
| OrderAdjustment intent | Strategy or runbook | Yes | The request to modify or cancel an order. |
| OrderLifecycleManager state | exec.order_lifecycle_manager | Yes | Source of truth for order status before and after. |
| RiskVote pipeline | Risk pod | Yes | Amends with non-zero new_size must pass Risk like any other OrderIntent. |
6. Parameter Guide
| Parameter | Default | Warning | Hard | What it controls |
|---|---|---|---|---|
| amend_timeout_ms | 1500 | 1500ms | 3000ms | Maximum wait for an amend ack before retrying or escalating. |
| cancel_timeout_ms | 1500 | — | — | Maximum wait for a cancel ack before retrying or escalating. |
| max_inflight_per_order | 1 | 1 | 2 | Maximum concurrent amend/cancel operations per single order_id. |
7. Detailed Parameter Instructions
amend_timeout_ms
What it means
Maximum wait for an amend ack before retrying or escalating.
Default
{ "amend_timeout_ms": 1500 }
Why this default matters
1.5s covers normal CLOB latency; longer timeouts hide real outages.
Threshold logic
| Condition | Action |
|---|---|
| ≤ 1500ms | Normal |
| > 1500ms | TIMEOUT — retry once, then escalate |
Developer check
if (now - sent > p.amend_timeout_ms) retry_or_escalate();
User-facing English
We could not change this order in time and rolled it back.
cancel_timeout_ms
What it means
Maximum wait for a cancel ack before retrying or escalating.
Default
{ "cancel_timeout_ms": 1500 }
Why this default matters
Same reasoning as amend timeout.
Threshold logic
| Condition | Action |
|---|---|
| ≤ 1500ms | Normal |
| > 1500ms | TIMEOUT — retry once, then escalate |
Developer check
if (now - sent > p.cancel_timeout_ms) retry_or_escalate();
User-facing English
We could not cancel this order in time.
max_inflight_per_order
What it means
Maximum concurrent amend/cancel operations per single order_id.
Default
{ "max_inflight_per_order": 1 }
Why this default matters
1 enforces strict serialisation per order — required to keep state consistent.
Threshold logic
| Condition | Action |
|---|---|
| 1 | Default — strict serialisation |
Developer check
if (inflight[order_id] >= p.max_inflight_per_order) reject_intent('EXEC_AMEND_INFLIGHT');
User-facing English
(Internal.)
8. Default Configuration
{
"amend_timeout_ms": 1500,
"cancel_timeout_ms": 1500,
"max_inflight_per_order": 1
}9. Implementation Flow
— not yet authored —
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.
validate(adjustment)
if op == 'amend' and new_size > current.size:
pass_through_risk(delta_intent)
seq = next_seq(order_id)
result = clob.send(adjustment, seq, eip712_v2_envelope())
wait_ack_or_timeout(p.amend_timeout_ms)
reconcile_with_lifecycle()
emit_report()11. Wire Examples
Input — what arrives on the wire
{
"intent_id": "adj_001",
"order_id": "ord_xyz",
"op": "amend",
"new_size_usd": 50
}
Output — what the bot emits
{
"intent_id": "adj_001",
"order_id": "ord_xyz",
"outcome": "ACK",
"seq_id": 7,
"reason_code": "EXEC_AMEND_OK"
}12. Decision Logic
APPROVE
Sequence operations strictly per order_id.
RESHAPE_REQUIRED
This bot does not reshape orders.
REJECT
Reject if max_inflight_per_order is exceeded. Reject amends that would increase size without Risk approval. Surface every ack/timeout/reject as a structured ReportEnvelope.
WARNING_ONLY
No warn-only path defined.
13. Standard Decision Output
This bot returns a RiskVote object. See RiskVote schema.
{
"intent_id": "adj_001",
"order_id": "ord_xyz",
"op": "amend",
"new_size_usd": 50,
"outcome": "ACK",
"seq_id": 7,
"reason_code": "EXEC_AMEND_OK"
}14. Reason Codes
| Code | Severity | Meaning | Action | User-facing message |
|---|---|---|---|---|
EXEC_AMEND_OK | P2 | Exec Amend Ok | See decision output and developer log for context. | This change to your order was applied successfully. |
EXEC_CANCEL_OK | P2 | Exec Cancel Ok | See decision output and developer log for context. | This change to your order was applied successfully. |
EXEC_AMEND_INFLIGHT | P2 | Exec Amend Inflight | See decision output and developer log for context. | This change to your order was applied successfully. |
EXEC_AMEND_UNKNOWN | P2 | Exec Amend Unknown | See decision output and developer log for context. | This change to your order was applied successfully. |
EXEC_AMEND_TIMEOUT | P2 | Exec Amend Timeout | See decision output and developer log for context. | This change to your order was applied successfully. |
EXEC_CANCEL_TIMEOUT | P2 | Exec Cancel Timeout | See decision output and developer log for context. | This change to your order was applied successfully. |
15. Metrics & Logs
Metrics emitted
| Metric | Type | Unit | Labels | Meaning |
|---|---|---|---|---|
amend_ops_total | counter | event | bot_id | Amend ops total. |
cancel_ops_total | counter | event | bot_id | Cancel ops total. |
amend_timeout_total | counter | event | bot_id | Amend timeout total. |
cancel_timeout_total | counter | event | bot_id | Cancel timeout total. |
ack_latency_ms_histogram | counter | event | bot_id | Ack latency ms histogram. |
Dashboards
- 2.15 overview dashboard
16. Developer Reporting
"Per operation: order_id, op, seq_id, sent_ts_ms, acked_ts_ms, outcome, reason_code."17. Plain-English Reporting
| Situation | User-facing explanation |
|---|---|
| When this bot acts | This change to your order was applied successfully. |
| When this bot acts | We could not change this order in time and rolled it back. |
18. Failure-Mode Block
| main_failure_mode | An ack arriving after the timeout window: bot has already retried; CLOB has two operations applied. |
|---|---|
| false_positive_risk | Reporting cancel-failure when the cancel actually succeeded; mitigation: reconcile against OrderLifecycleManager before retrying. |
| false_negative_risk | Strategy code bypassing the bot via direct CLOB calls; mitigation: outbound CLOB writes are restricted at the network layer to this bot's identity only. |
| safe_fallback | On unrecoverable inconsistency, mark the order as QUARANTINED and escalate to the Execution on-call. Never silently retry past max_retries. |
| required_dependencies | — |
19. Failure-Injection Recipes
| Scenario | How to inject | Expected behaviour | Recovery |
|---|---|---|---|
Drop ack from CLOB and assert single retry then escalation | Drop ack from CLOB and assert single retry then escalation. | Bot detects within its latency budget and emits the corresponding reason code. | Remove the injected fault; bot returns to healthy state within one debounce window. |
Race two amends on the same order and assert second is rejected with INFLIGHT | Race two amends on the same order and assert second is rejected with INFLIGHT. | Bot detects within its latency budget and emits the corresponding reason code. | Remove the injected fault; bot returns to healthy state within one debounce window. |
20. State & Persistence
Per-order seq_id counter (durable). In-flight operation map (in-memory).
State stores
| Name | Kind | Key | Value shape | TTL | Durability |
|---|---|---|---|---|---|
order_amend_cancel_manager_state | in-memory + fast KV mirror | bot_id | Per-order seq_id counter (durable). In-flight operation map (in-memory). | 24h | crash-safe via KV mirror |
Cold-start recovery
Cold-start hydrates from fast KV; missing keys default to safe fallback.
On restart
All in-flight decisions are re-evaluated; no bot decision is trusted across restart without re-emit.
21. Concurrency & Idempotency
| Aspect | Specification |
|---|---|
| Execution model | Strict per-order serialisation. Concurrent across distinct order_ids. |
| Max in-flight | 32 |
| Idempotency key | order_intent_id |
| Replay-safe | True |
| Deduplication | By idempotency_key within a 60s window. |
| Ordering guarantees | Per-market_id FIFO; cross-market unordered. |
| Per-call timeout (ms) | 250 |
| Backpressure strategy | Bounded queue; oldest-dropped with metric increment when full. |
| Locking / mutual exclusion | Per-market_id mutex; no global locks. |
22. Dependencies
Depends on (must run first)
| Bot | Why | Contract |
|---|---|---|
| exec.order_lifecycle_manager |
Requires (graph.requires)
| Consumes | OrderAdjustment OrderLifecycleState |
|---|---|
| Emits | ReportEnvelope(kind=ExecutionReport) |
| Blocks orders | no |
23. Security Surfaces
Only this bot's identity has CLOB write permission for amend/cancel.
Signing surface
Reads pending signed orders; never signs on user behalf.
Abuse vectors considered
- EIP-712 v2 signature required for every operation.
Mitigations
- Rate-limit per source
- Audit-log every override
- Require role-based authz on admin paths
24. Polymarket V2 Compatibility
| Aspect | Value |
|---|---|
| CLOB version | V2 |
| Collateral asset | pUSD |
| EIP-712 Exchange domain version | 2 |
| Aware of builderCode field | yes |
| Aware of negative-risk markets | yes |
| Multi-chain ready | yes |
| SDK used | Polymarket CLOB V2 SDK |
| Settlement contract | CTFExchangeV2 |
| Notes | Native CLOB v2 amend/cancel endpoints; EIP-712 v2 envelope with builderCode. |
25. Versioning & Migration
| Field | Value |
|---|---|
| current | 0.1.0 |
| contract_version | 1.0.0 |
| last_breaking_change | none |
| deprecation_window_days | 30 |
26. Acceptance Tests
Unit Tests
| Test | Setup | Expected result |
|---|---|---|
| Cancel of an unknown order_id returns EXEC_AMEND_UNKNOWN. | Synthetic fixture per template. | Behaviour matches the rule described in the test name. |
| Concurrent amend on the same order_id returns EXEC_AMEND_INFLIGHT for the second one. | Synthetic fixture per template. | Behaviour matches the rule described in the test name. |
Integration Tests
| Test | Expected result |
|---|---|
| Replay 1000 amend/cancel ops through a fixture CLOB; assert every op produces exactly one ReportEnvelope. | End-to-end behaviour matches the spec without manual intervention. |
Property Tests
| Property | Required behaviour |
|---|---|
| seq_id is strictly increasing per (order_id). | Always true across all generated inputs. |
27. Operational Runbook
If timeouts spike: inspect CLOB v2 latency; enable verbose ack-trace logging; consider widening timeouts only as a temporary measure.
On-call actions
| Alert | First step | Diagnosis | Mitigation | Escalate to |
|---|---|---|---|---|
2.15_anomaly | Open the bot's reporting page and confirm the alert is real (not a metric hiccup). | Inspect developer log entries for the affected market_id over the last 30 minutes. | Force-clear via Admin UI if the rule is clearly stale; otherwise leave engaged and notify owner. | Execution pod |
Manual overrides
polytraders bot pause 2.15— Disables the bot's enforcement layer; downstream consumers fall back to safe defaults.
Healthcheck
GET /healthz/order_amend_cancel_manager → 200 if last successful evaluation < 60s ago.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
| Gate | How measured | Threshold |
|---|---|---|
| Stub | against fixture CLOB. | Documented threshold met for the full window. |
Promote to Limited live
| Gate | How measured | Threshold |
|---|---|---|
| Shadow | 14 days mirrored against live state. | Documented threshold met for the full window. |
| Advisory | 7 days. | Documented threshold met for the full window. |
Promote to General live
| Gate | How measured | Threshold |
|---|---|---|
| Enforced | every cancel/amend in the system routes through this bot. | Documented threshold met for the full window. |
29. Developer Checklist
Ready-to-ship score: 27/27 sections complete · 100%
| Requirement | Status |
|---|---|
| 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 |