6.1 BuilderAttribution
BuilderAttribution tags every outgoing order with the Polytraders builder code before submission, logs each fill against the builder code, and reconciles the local fill log against the Polymarket builder-code report every 24 hours. If a discrepancy is detected — missing attribution, volume drift, or order counts that do not match — it quarantines the affected records and raises an alert. BuilderAttribution never submits, modifies, or cancels orders. Its authority is to explain and audit only.
v3 readiness
A bot is done when all four scores are. What does done mean?
1. Bot Identity
| Layer | Governance Governance |
|---|---|
| Bot class | Governance Service |
| Authority | Explain |
| Status | LIVE |
| Readiness | General live |
| Runs before | Nothing — runs post-trade on every fill event |
| Runs after | Order submission and fill confirmation |
| Applies to | Every filled or partially filled order, and every daily reconciliation window |
| Default mode | general_live |
| User-visible | Advanced details only |
| Developer owner | Polytraders core — Governance pod |
2. Purpose
BuilderAttribution tags every outgoing order with the Polytraders builder code before submission, logs each fill against the builder code, and reconciles the local fill log against the Polymarket builder-code report every 24 hours. If a discrepancy is detected — missing attribution, volume drift, or order counts that do not match — it quarantines the affected records and raises an alert. BuilderAttribution never submits, modifies, or cancels orders. Its authority is to explain and audit only.
3. Why This Bot Matters
Builder code missing from an outgoing order
Volume attributed to the builder is undercounted in the Polymarket report, which affects fee rebates, builder-tier status, and audit trails for compliance.
Daily reconciliation not performed
Attribution drift compounds silently over time. Without regular reconciliation, discrepancies may only be discovered during a formal audit when they are much harder to investigate.
Quarantine not applied on drift
Unreconciled records remain in the live ledger and may be double-counted or misreported in downstream reports if not flagged and isolated.
Attribution log retention not enforced
Without a defined retention policy, old attribution records may be purged before they are needed for a historical audit or fee dispute.
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 |
|---|---|---|---|
| Per-fill attribution data from every submitted order | CLOB | Yes | Capture the builder_code field on each fill confirmation and store it in the attribution log. |
| Polymarket builder-code volume report (rolling 24 hours) | Data API | Yes | Reconcile the local fill log against Polymarket's official attribution report each reconcile window. |
| Order submission acknowledgements | CLOB | Yes | Confirm that the builder_code was accepted and echoed back in each order acknowledgement; flag any order where it is absent. |
5. Required Internal Inputs
| Input | Source | Required? | Use |
|---|---|---|---|
| Outgoing order stream before submission | StrategyRegistry | Yes | Intercept each order in-flight to attach the builder_code to the payload before it is signed and submitted. |
| KillSwitch active flag | KillSwitch | No | Continue logging and reconciliation even when KillSwitch is active — attribution must track all events including rejected ones. |
6. Parameter Guide
| Parameter | Default | Warning | Hard | What it controls |
|---|---|---|---|---|
| builder_code | polytraders | — | — | The canonical builder code string that must be present on every outgoing order. This value is locked and can only be changed via a signed admin action. |
| reconcile_window_h | 24 | 48 | 72 | How often in hours the local fill log is reconciled against the Polymarket builder-code report. |
| quarantine_on_drift | True | None | None | When true (locked), any fill records that do not match the Polymarket report are moved to a quarantine partition and flagged for manual review before inclusion in any downstream report. |
| alert_on_missing_code | True | None | None | When true (locked), every order that arrives at the attribution layer without a builder_code field triggers an immediate alert to the monitoring stack. |
7. Detailed Parameter Instructions
builder_code
What it means
The canonical builder code string that must be present on every outgoing order. This value is locked and can only be changed via a signed admin action.
Default
{ "builder_code": "polytraders" }
Why this default matters
The builder code is the immutable identifier that Polymarket uses to attribute volume and fee rebates. Any change to it must be coordinated with Polymarket and logged formally.
Threshold logic
| Condition | Action |
|---|---|
| order.builder_code === builder_code | APPROVE — log and continue |
| order.builder_code is absent | Attach builder_code and emit MISSING_CODE alert |
| order.builder_code !== builder_code | Reject attachment and raise PARAMETER_CHANGE_REQUIRES_APPROVAL alert |
Developer check
if (!order.builder_code) { order.builder_code = p.builder_code; alerting.emit('MISSING_CODE'); }
User-facing English
Every order is tagged with an identifier that tracks your trading volume on Polymarket. This supports fee reconciliation and audit.
reconcile_window_h
What it means
How often in hours the local fill log is reconciled against the Polymarket builder-code report.
Default
{ "reconcile_window_h": 24 }
Why this default matters
A 24-hour window aligns with Polymarket's rolling report cadence. Reconciling more frequently is supported but reconciling less often than 72 hours risks missing drift until it compounds.
Threshold logic
| Condition | Action |
|---|---|
| reconcile_window_h ≤ 24 | Reconcile at configured frequency |
| 24–72 h | WARN — drift detection is delayed |
| > 72 h | Reject config change — PARAMETER_CHANGE_REQUIRES_APPROVAL |
Developer check
if (p.reconcile_window_h > p.hard) throw new ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL');
User-facing English
Your trading activity is checked daily against the exchange's records to make sure everything is correctly attributed.
quarantine_on_drift
What it means
When true (locked), any fill records that do not match the Polymarket report are moved to a quarantine partition and flagged for manual review before inclusion in any downstream report.
Default
{ "quarantine_on_drift": true }
Why this default matters
Unreconciled records in the live ledger can corrupt downstream reports. Quarantining immediately on detection isolates the problem without data loss.
Threshold logic
| Condition | Action |
|---|---|
| quarantine_on_drift=true AND drift detected | Move affected records to quarantine partition and emit reconciliation alert |
| quarantine_on_drift=false | Not permitted — parameter is locked to true |
Developer check
if (p.quarantine_on_drift && reconciliationDrift) quarantine.move(driftedRecords);
User-facing English
If any inconsistency is found during the daily check, the affected records are set aside for review rather than being included in reports.
alert_on_missing_code
What it means
When true (locked), every order that arrives at the attribution layer without a builder_code field triggers an immediate alert to the monitoring stack.
Default
{ "alert_on_missing_code": true }
Why this default matters
A missing builder code on any order is an anomaly that should never happen in normal operation. Alerting on every occurrence ensures it is investigated immediately rather than discovered in the next reconciliation.
Threshold logic
| Condition | Action |
|---|---|
| alert_on_missing_code=true AND builder_code absent | Attach code and emit MISSING_CODE alert |
| alert_on_missing_code=false | Not permitted — parameter is locked to true |
Developer check
if (p.alert_on_missing_code && !order.builder_code) alerting.emit('MISSING_BUILDER_CODE', { order_id: order.id });
User-facing English
An alert is raised any time an order is detected without the required tracking code, so it can be investigated promptly.
8. Default Configuration
{
"bot_id": "gov.builder_attribution",
"version": "1.0.0",
"mode": "general_live",
"defaults": {
"builder_code": "polytraders",
"reconcile_window_h": 24,
"quarantine_on_drift": true,
"alert_on_missing_code": true
},
"locked": {
"builder_code": {
"change_requires_signed_admin_action": true
},
"quarantine_on_drift": {
"immutable": true
},
"alert_on_missing_code": {
"immutable": true
},
"reconcile_window_h": {
"max": 72
}
}
}9. Implementation Flow
- Intercept every outgoing order from StrategyRegistry before it reaches the signing step; verify builder_code is present and correct.
- If builder_code is absent, attach the configured builder_code value and emit an alert to the monitoring stack (alert_on_missing_code).
- After each fill confirmation from the CLOB, extract the fill metadata (order_id, market_id, size_usd, price, side, timestamp, builder_code echoed by exchange).
- Append the fill record to the local attribution log with all metadata fields and a log_sequence_number for ordering.
- Every reconcile_window_h hours, fetch the Polymarket builder-code volume report from Data API for the matching time window.
- Compare local fill log totals (volume, order count, unique market count) against the Polymarket report for the same window.
- If discrepancy is detected: compute the drift delta, tag affected records with a quarantine flag, and move them to the quarantine partition (quarantine_on_drift).
- Emit a reconciliation report to the governance audit trail (GovernanceLog) whether the reconciliation passes or flags drift.
- Retain all attribution log records for a minimum of 90 days; quarantined records are retained indefinitely until manually reviewed and resolved.
- Produce a PostTradeExplanation entry for each reconciliation cycle summarising: total volume attributed, match status, drift delta if any, and quarantine record count.
10. Reference Implementation
Intercepts every outgoing order to verify the builderCode bytes32 field is present, logs each fill to the attribution ledger, and runs a 24-hour reconciliation against the Data API builder-code volume report. Quarantines drift records and emits a GovernanceLog on every cycle.
Pseudocode is language-agnostic. FETCH = read input. EMIT = produce output. Translate to TS/Python/Go/Rust.
// ---- PRE-SUBMISSION HOOK: called on every outgoing order ----
FUNCTION attachAndVerifyBuilderCode(order):
// In V2, builderCode is a bytes32 field on the order (not HMAC)
IF order.builder IS NULL OR order.builder == ZERO_BYTES32:
order.builder = config.builder_code_bytes32
alerting.emit('BUILDER_CODE_MISSING', { order_id: order.id })
IF order.builder != config.builder_code_bytes32:
alerting.emit('BUILDER_CODE_MISMATCH', { order_id: order.id, found: order.builder })
raise PARAMETER_CHANGE_REQUIRES_APPROVAL
RETURN order
// ---- POST-FILL HOOK: called on every fill confirmation ----
FUNCTION logFill(fillEvent):
// fillEvent.builder is echoed back by CTFExchangeV2 from the on-order builderCode
IF fillEvent.builder != config.builder_code_bytes32:
alerting.emit('BUILDER_CODE_MISSING', { fill_id: fillEvent.fill_id })
record = {
fill_id: fillEvent.fill_id,
order_id: fillEvent.order_id,
market_id: fillEvent.market_id,
side: fillEvent.side,
size_pusd: toUsdcUnits(fillEvent.size_usd),
price: fillEvent.price,
builder_code: fillEvent.builder,
// V2 fee: builder_fee = notional * bps / 10000
builder_fee_pusd: toUsdcUnits(fillEvent.size_usd * fillEvent.builder_fee_bps / 10000),
fill_confirmed_at: fillEvent.timestamp,
log_seq: postgres.nextval('attribution_log_seq')
}
postgres.INSERT('attribution_log', record)
EMIT GovernanceLog(event_type='FILL_LOGGED', fill_id=fillEvent.fill_id)
// ---- RECONCILIATION: runs every reconcile_window_h hours ----
FUNCTION reconcile(windowStart, windowEnd):
localRows = postgres.SELECT('attribution_log',
WHERE fill_confirmed_at BETWEEN windowStart AND windowEnd)
localVolume = SUM(r.size_pusd FOR r IN localRows)
localCount = COUNT(localRows)
report = FETCH data_api.GET(
'/builder-code-report?code=' + config.builder_code
+ '&from=' + windowStart + '&to=' + windowEnd
)
IF report IS NULL:
alerting.emit('RECONCILIATION_SKIP', { reason: 'data_api_unavailable' })
RETURN
drift_usd = abs(localVolume - report.volume_pusd)
drift_pct = drift_usd / max(localVolume, 1)
IF drift_pct > 0.01: // > 1% drift
driftRows = identify_drift_rows(localRows, report)
postgres.UPDATE('attribution_log', driftRows, { quarantined: true })
alerting.emit('RECONCILIATION_DRIFT_OBSERVED', { drift_usd, drift_pct })
EMIT GovernanceLog(event_type='RECONCILIATION_DRIFT',
drift_usd=drift_usd, quarantine_count=len(driftRows))
ELSE:
EMIT GovernanceLog(event_type='RECONCILIATION_COMPLETE',
drift_detected=False, local_volume=localVolume,
polymarket_volume=report.volume_pusd)
// Retain all records >= 90 days; quarantined records retained indefinitely
Helpers used
| Helper | Signature | Purpose |
|---|---|---|
| toUsdcUnits | toUsdcUnits(rawUsd: float) -> int | Converts a raw pUSD float to the 6-decimal integer unit used by CTFExchangeV2; ensures fill_log precision matches on-chain values. |
| fetchClobPublic | fetchClobPublic(path: str) -> JSON | Used to verify fill confirmations against CLOB order status for reconciliation. |
| platformFee | platformFee(notional: float, prob: float, feeRate: float) -> float | Estimates the platform fee component; logged alongside builder_fee_pusd for fee breakdown reporting. |
| buildOrderTypedData | buildOrderTypedData(order, domain) -> TypedData | Not called by BuilderAttribution; referenced to confirm that builderCode bytes32 is populated by SmartRouter before this bot sees the order. |
SDK calls used
data_api.GET('/builder-code-report?code=...&from=...&to=...')clob_auth.GET('/fills?order_id=...&limit=100')postgres.INSERT('attribution_log', record)postgres.SELECT('attribution_log', WHERE fill_confirmed_at BETWEEN ... AND ...)alerting.emit('RECONCILIATION_DRIFT_OBSERVED', metadata)
Complexity: O(F) per reconciliation window where F = fill count; O(1) per fill log event
11. Wire Examples
Input — what arrives on the wire
Fill confirmation from CTFExchangeV2 — clob_auth
{
"fill_id": "fill_00a1b2c3d4e5f6a7",
"order_id": "ord_00123",
"market_id": "0x9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c",
"side": "BUY",
"size_usd": 250.0,
"price": 0.62,
"builder": "0x706f6c7974726164657273000000000000000000000000000000000000000000",
"builder_fee_bps": 25,
"fill_confirmed_at": "2026-05-09T11:45:00Z"
}
Data API builder-code volume report — data_api
{
"builder_code": "polytraders",
"window_start": "2026-05-08T00:00:00Z",
"window_end": "2026-05-09T00:00:00Z",
"volume_pusd": 48320.5,
"order_count": 217,
"fill_count": 217
}
Output — what the bot emits
GovernanceLog — RECONCILIATION_COMPLETE (no drift)
{
"attribution_id": "gov.builder_attribution",
"event_type": "RECONCILIATION_COMPLETE",
"window_start": "2026-05-08T00:00:00Z",
"window_end": "2026-05-09T00:00:00Z",
"local_volume_pusd": 48320.5,
"polymarket_volume_pusd": 48320.5,
"local_order_count": 217,
"polymarket_order_count": 217,
"drift_detected": false,
"quarantine_count": 0,
"builder_code": "polytraders",
"retention_days": 90,
"reconciled_at": "2026-05-09T00:05:12Z"
}
GovernanceLog — RECONCILIATION_DRIFT (quarantine triggered)
{
"attribution_id": "gov.builder_attribution",
"event_type": "RECONCILIATION_DRIFT",
"window_start": "2026-05-08T00:00:00Z",
"window_end": "2026-05-09T00:00:00Z",
"local_volume_pusd": 48420.5,
"polymarket_volume_pusd": 48320.5,
"drift_usd": 100.0,
"drift_pct": 0.00207,
"drift_detected": true,
"quarantine_count": 2,
"reconciled_at": "2026-05-09T00:06:00Z"
}
Reproduce locally
curl 'https://data-api.polymarket.com/builder-code-report?code=polytraders&from=2026-05-08T00:00:00Z&to=2026-05-09T00:00:00Z'12. Decision Logic
APPROVE
Not applicable — BuilderAttribution does not approve or reject orders. It observes, tags, logs, and reconciles.
RESHAPE_REQUIRED
Not applicable — BuilderAttribution does not reshape orders.
REJECT
Not applicable as a trading decision. BuilderAttribution emits no RiskVote. The only action that resembles a reject is quarantining drift records.
WARNING_ONLY
Missing builder_code on an inbound order triggers an alert but does not block the order — BuilderAttribution attaches the code and flags the anomaly. Reconciliation drift triggers quarantine and alert but does not halt trading.
13. Standard Decision Output
This bot returns a GovernanceLog object. See GovernanceLog schema.
{
"attribution_id": "gov.builder_attribution",
"event_type": "RECONCILIATION_COMPLETE",
"window_start": "2026-05-08T00:00:00Z",
"window_end": "2026-05-09T00:00:00Z",
"local_volume_usd": 48320.5,
"polymarket_volume_usd": 48320.5,
"local_order_count": 217,
"polymarket_order_count": 217,
"drift_detected": false,
"quarantine_count": 0,
"builder_code": "polytraders",
"retention_days": 90,
"reconciled_at": "2026-05-09T00:05:12Z"
}14. Reason Codes
| Code | Severity | Meaning | Action | User-facing message |
|---|---|---|---|---|
BUILDER_CODE_MISSING | WARN | An outgoing order arrived at the attribution layer without the builderCode bytes32 field set, or a fill confirmation echoed back a zero builder code. | Attach the configured builderCode and emit WARN alert. | An order was detected without the required tracking code. It was added automatically and the anomaly was flagged. |
BUILDER_FEE_RATE_CAPPED | WARN | The observed builder_fee_bps on a fill exceeds the V2 cap (taker: 100 bps, maker: 50 bps). | Log the anomaly; quarantine the fill record for manual review. | |
RECONCILIATION_DRIFT_OBSERVED | WARN | Local fill volume or count diverges from the Polymarket builder-code report by > 1%. | Quarantine drift records; emit reconciliation drift alert. | A difference was found between our records and the exchange's report. The affected records have been set aside for review. |
PARAMETER_CHANGE_REQUIRES_APPROVAL | HARD_REJECT | reconcile_window_h exceeds the 72h hard maximum, or builder_code was changed without a signed admin action. | Reject the config change and emit an alert. | |
BUILDER_ATTRIBUTION_CODE_MISMATCH | WARN | An order's builder bytes32 field does not match the configured builderCode value. | Reject the order from proceeding to signing; emit WARN alert. | |
BUILDER_ATTRIBUTION_QUARANTINE_BLOCKED | WARN | An automated process attempted to clear quarantine records without a manual review flag. | Reject the clear operation; retain records; emit alert. | Affected records are held for review and cannot be cleared automatically. |
BUILDER_ATTRIBUTION_REPORT_UNAVAILABLE | WARN | Data API builder-code report is unavailable at reconciliation time. | Skip this reconciliation cycle; emit alert; retry on next scheduled window. |
15. Metrics & Logs
Metrics emitted
| Metric | Type | Unit | Labels | Meaning |
|---|---|---|---|---|
polytraders_gov_builderattribution_fills_logged_total | counter | count | market_id | Total fill events logged to the attribution ledger. |
polytraders_gov_builderattribution_volume_pusd_total | counter | usd | Cumulative pUSD volume attributed to the builder code. | |
polytraders_gov_builderattribution_drift_usd | gauge | usd | Absolute drift between local and Polymarket volume at the last reconciliation. | |
polytraders_gov_builderattribution_quarantine_count | gauge | count | Number of fill records currently in the quarantine partition. | |
polytraders_gov_builderattribution_missing_code_total | counter | count | Total orders seen without a builder code; should be 0 in normal operation. | |
polytraders_gov_builderattribution_reconcile_latency_ms | histogram | seconds | Wall-clock latency of a full reconciliation cycle. |
Alerts
| Alert | Condition | Severity | Runbook |
|---|---|---|---|
BuilderAttributionMissingCode | rate(polytraders_gov_builderattribution_missing_code_total[5m]) > 0 | P1 | #runbook-builderattribution-missing-code |
BuilderAttributionDriftDetected | polytraders_gov_builderattribution_drift_usd > 0 | P1 | #runbook-builderattribution-drift |
BuilderAttributionQuarantineGrowing | delta(polytraders_gov_builderattribution_quarantine_count[1h]) > 0 | P2 | #runbook-builderattribution-quarantine |
BuilderAttributionReportUnavailable | rate(polytraders_gov_builderattribution_fills_logged_total[30m]) == 0 | P2 | #runbook-builderattribution-report |
Dashboards
- Grafana — Governance / BuilderAttribution reconciliation
- Grafana — Fee accounting / builder code volume and drift
Log levels
| Level | What gets logged |
|---|---|
| DEBUG | Per-fill record details including builder_fee_bps and fill_confirmed_at. |
| INFO | Fill logged; reconciliation cycle completed (pass or drift). |
| WARN | Missing builder code on order; reconciliation drift detected; quarantine records added. |
| ERROR | Data API report unavailable at reconciliation time; Postgres write failure. |
16. Developer Reporting
{
"attribution_id": "gov.builder_attribution",
"event_type": "FILL_LOGGED",
"order_id": "ord_00123",
"market_id": "CLOB:0xabc123",
"side": "BUY",
"size_usd": 250.0,
"price": 0.62,
"builder_code_present": true,
"builder_code_echoed": "polytraders",
"log_sequence_number": 4821,
"fill_confirmed_at": "2026-05-09T11:45:00Z"
}17. Plain-English Reporting
| Situation | User-facing explanation |
|---|---|
| Daily reconciliation completed with no discrepancies | The system checked today's trading records against the exchange's report. All orders, volumes, and attribution codes matched exactly. |
| Reconciliation flagged a discrepancy | A difference was found between our records and the exchange's report. The affected records have been set aside for review. No trading is interrupted, but the discrepancy needs to be resolved. |
| Order arrived without attribution code | An order was detected without the required tracking code. The code was added automatically and the anomaly was flagged for investigation. |
| Historical attribution records requested | Attribution logs are retained for at least 90 days. Older records and any records held in the review queue are retained indefinitely until cleared. |
18. Failure-Mode Block
| main_failure_mode | A fill is processed and attributed but the Polymarket report is unavailable at reconciliation time, causing the local log to be marked as unverified until the next successful fetch. |
|---|---|
| false_positive_risk | Quarantining records due to a temporary data format change in the Polymarket report, when the underlying volume is correctly attributed but the comparison field changed. |
| false_negative_risk | Missing a genuine drift because the reconciliation time window does not fully overlap with the Polymarket report window, leaving a gap that does not appear in either comparison. |
| safe_fallback | If the Polymarket builder-code report is unavailable at reconciliation time, skip the comparison for that cycle, emit an alert, and retry at the next scheduled window. Never clear quarantine records automatically — require manual review. |
| required_dependencies | CLOB fill confirmation stream, Data API Polymarket builder-code report, StrategyRegistry outgoing order stream, Governance audit log storage (90-day retention) |
19. Failure-Injection Recipes
| Scenario | How to inject | Expected behaviour | Recovery |
|---|---|---|---|
MISSING_BUILDER_CODE | Submit order with order.builder = ZERO_BYTES32 | BuilderAttribution attaches configured builderCode; BUILDER_CODE_MISSING alert emitted | Automatic; code is attached. |
DATA_API_REPORT_UNAVAILABLE | Block TCP to data-api.polymarket.com during reconciliation window | Reconciliation cycle skipped; BUILDER_ATTRIBUTION_REPORT_UNAVAILABLE alert; records retained | Next cycle reconciles full backlog once Data API is reachable. |
RECONCILIATION_DRIFT | Manually insert an extra fill record into attribution_log with size_pusd=10000 | RECONCILIATION_DRIFT_OBSERVED alert; drift records quarantined | Manual review and removal of synthetic record; reconciliation passes on next cycle. |
QUARANTINE_AUTO_CLEAR_BLOCKED | Call postgres.DELETE on quarantine records without setting manual_review_flag=true | Delete rejected by application guard; BUILDER_ATTRIBUTION_QUARANTINE_BLOCKED alert | Manual review must be completed before clearing. |
BUILDER_CODE_MISMATCH | Set order.builder to a different bytes32 value | BUILDER_CODE_MISMATCH alert; PARAMETER_CHANGE_REQUIRES_APPROVAL raised; order blocked from signing | Correct builder code must be set. |
20. State & Persistence
Maintains a durable Postgres attribution ledger with all fill records, plus a quarantine partition for drift records. Reconciliation state is persisted per window.
State stores
| Name | Kind | Key | Value shape | TTL | Durability |
|---|---|---|---|---|---|
attribution_log | postgres | fill_id | { fill_id, order_id, market_id, side, size_pusd, price, builder_code, builder_fee_pusd, fill_confirmed_at, quarantined: bool, log_seq: int } | none | strong |
reconciliation_state | postgres | window_start + window_end | { local_volume, polymarket_volume, drift_usd, drift_pct, status, reconciled_at } | none | strong |
Cold-start recovery
On cold start, Postgres attribution_log is read immediately. No in-memory state needs rebuilding.
On restart
All state is in Postgres and available immediately. The next fill event triggers a fresh log write.
21. Concurrency & Idempotency
| Aspect | Specification |
|---|---|
| Execution model | single-threaded event loop (fill hook) + scheduled reconciliation goroutine |
| Max in-flight | 500 |
| Idempotency key | fill_id |
| Replay-safe | True |
| Deduplication | by fill_id — duplicate fill events are ignored |
| Ordering guarantees | log_seq is monotonically increasing per postgres.nextval() |
| Per-call timeout (ms) | 500 |
| Backpressure strategy | shed |
| Locking / mutual exclusion | none (Postgres serializable isolation) |
22. Dependencies
Depends on (must run first)
| Bot | Why | Contract |
|---|---|---|
| exec.smart_router | SmartRouter populates the builderCode bytes32 field on each order before BuilderAttribution sees it. | order.builder must equal config.builder_code_bytes32 before signing. |
Sibling bots (same OrderIntent)
| Bot | Why | Contract |
|---|---|---|
| sec.contract_address_guard | ContractAddressGuard logs every security check to BuilderAttribution's governance audit trail. | GovernanceLog entry emitted for each SecurityCheck decision. |
Used by (auto-aggregated)
External services
| Service | Endpoint | SLA assumed | On failure |
|---|---|---|---|
| Data API (builder-code report) | https://data-api.polymarket.com | 99.9% / 500ms p99 | Skip reconciliation cycle; emit alert; retry on next window. |
| CLOB Auth API (fills) | https://clob.polymarket.com | 99.95% / 200ms p99 | Fill log entry deferred until fill confirmation is received. |
23. Security Surfaces
BuilderAttribution reads fill data and writes to the governance ledger. It never signs orders or holds private keys.
Signing surface
This bot does NOT sign anything.
Abuse vectors considered
- Clearing quarantine records automatically without manual review to hide attribution drift
- Substituting a different builder code bytes32 on orders to redirect fee attribution
- Modifying builder_code parameter without a signed admin action
Mitigations
- quarantine_on_drift is locked immutable; auto-clear is rejected
- builder_code parameter requires signed admin action and is audit-logged
- Each fill record is immutable once written; log_seq is monotonically increasing
- alert_on_missing_code is locked immutable; every missing code alert is raised regardless
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 | no |
| Multi-chain ready | no |
| SDK used | @polymarket/clob-client-v2 ^2.x |
| Settlement contract | CTFExchangeV2 on Polygon |
| Notes | V2 builder attribution uses a native builderCode bytes32 field on every order (replaced V1 HMAC-based builder). Both maker and taker orders can carry different builder codes in V2. Builder fee formula: builder_fee = notional * bps / 10000. Taker max 100 bps, maker max 50 bps, 1 bp granularity. Fee is taker-only currently; fill records include builder_fee_pusd for auditability. |
API surfaces declared
Networks supported
25. Versioning & Migration
| Field | Value |
|---|---|
| spec | 2.0.0 |
| implementation | 2.1.3 |
| schema | 2 |
| released | 2026-04-28 |
Migration history
| Date | From | To | Reason | Action taken |
|---|---|---|---|---|
| 2026-04-28 | v1 (USDC.e + HMAC builder) | v2 (pUSD + builderCode field) | Polymarket V2 cutover | Replaced HMAC builder logic with on-order builderCode bytes32 field. Attribution log schema updated to include builder_fee_bps and builder_fee_pusd columns. Reconciliation report format updated to match Data API V2 builder-code report schema. All fill amounts now denominated in pUSD. |
26. Acceptance Tests
Unit Tests
| Test | Setup | Expected result |
|---|---|---|
| Attach builder_code when absent on outgoing order | order.builder_code=undefined, builder_code='polytraders' | order.builder_code='polytraders' attached; MISSING_CODE alert emitted |
| Log fill record with all metadata after fill confirmation | Fill event: order_id=ord_001, size_usd=300, price=0.55, side=BUY | Fill record in attribution log with correct fields and log_sequence_number |
| Reconciliation passes when local and report totals match | local_volume=5000, polymarket_volume=5000, local_count=20, report_count=20 | GovernanceLog event_type=RECONCILIATION_COMPLETE, drift_detected=false |
| Quarantine records when drift detected | local_volume=5100, polymarket_volume=5000 (drift=100) | Drift records moved to quarantine, quarantine_count > 0, alert emitted |
| Reject reconcile_window_h above hard maximum | reconcile_window_h=80, hard=72 | ConfigError PARAMETER_CHANGE_REQUIRES_APPROVAL |
| Retain quarantine records when auto-clear attempted | Automated process attempts to clear quarantine without manual review flag | Quarantine records remain; alert emitted |
Integration Tests
| Test | Expected result |
|---|---|
| End-to-end: order tagged, filled, logged, and reconciled against Polymarket report | Full attribution lifecycle completes with matching GovernanceLog entry |
| Polymarket report unavailability causes skip-and-retry without data loss | Reconciliation cycle skipped, alert emitted, records retained; next cycle reconciles full backlog |
| Missing builder_code on 5 consecutive orders triggers escalated alert | Individual MISSING_CODE alerts plus an escalated pattern alert after 5 consecutive missing codes |
Property Tests
| Property | Required behaviour |
|---|---|
| Every fill event is logged before any downstream report uses it | Always true — fill logging is synchronous with fill confirmation |
| Quarantine records are never automatically cleared without a manual review flag | Always true |
| All attribution log records are retained for at least 90 days | Always true — retention enforcement is mandatory |
27. Operational Runbook
BuilderAttribution incidents involve missing builder codes, reconciliation drift, or quarantine growth. Every RECONCILIATION_DRIFT event is a P1 requiring investigation before the next daily report.
On-call actions
| Alert | First step | Diagnosis | Mitigation | Escalate to |
|---|---|---|---|---|
BuilderAttributionMissingCode | Identify which strategy or SmartRouter instance is emitting orders without builderCode. | If a single strategy is the source, it may be using an old SDK version that does not set builder bytes32. | Pause the affected strategy and require SDK upgrade. BuilderAttribution will attach the code in the interim, but the root cause must be fixed. | Governance pod lead + Exec pod lead immediately. |
BuilderAttributionDriftDetected | Review reconciliation drift details in the GovernanceLog. | Check whether the drift corresponds to a Data API report format change or a genuine attribution discrepancy. | Do NOT clear quarantine records until the root cause is confirmed. Engage Polymarket support if drift is large. | Governance pod lead immediately. |
BuilderAttributionQuarantineGrowing | Check how many records are in quarantine and when they were added. | If quarantine is growing steadily, drift may be systematic (e.g., a fill reporting format change). | Investigate the fill data format. Do not reduce the drift detection threshold. | Governance pod lead after 30 minutes. |
Manual overrides
polytraders gov clear-quarantine --fill-ids <ids> --reviewed-by <operator>— Clears specific quarantine records after manual review. Requires governance pod lead sign-off and is audit-logged.polytraders gov rerun-reconciliation --window-start <ts> --window-end <ts>— Re-runs a specific reconciliation window without clearing existing records. Used to check if drift resolves after a Data API format fix.
Healthcheck
GET /health → 200 if Postgres attribution_log is reachable, last fill was logged < 300s ago during active trading, and quarantine_count has not increased in the last 24h.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 |
|---|---|---|
| Unit tests pass for fill logging, builder code attach, and reconciliation logic | CI test run | 100% pass |
| Postgres write integration test verified | Integration test | Pass |
Promote to Limited live
| Gate | How measured | Threshold |
|---|---|---|
| Reconciliation cycle completes within 30s for a 24h window of 1000 fill records | polytraders_gov_builderattribution_reconcile_latency_ms histogram | < 30s |
| Missing-code alert fires within 1s of order without builderCode | Unit test + integration test | Pass |
Promote to General live
| Gate | How measured | Threshold |
|---|---|---|
| End-to-end: fill tagged, logged, reconciled, GovernanceLog entry matches Data API report | E2E test in staging | Pass |
| Quarantine auto-clear rejection verified | Failure injection test | Pass |
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 |