1. Bot Identity
| Layer | Intelligence Intelligence |
|---|
| Bot class | Signal Service |
|---|
| Authority | Read-only |
|---|
| Status | BETA |
|---|
| Readiness | Limited live |
|---|
| Runs before | Strategy layer, SumToOneArb, LiquidityGuard |
|---|
| Runs after | Gamma API market list loaded; MarketScanner candidates available |
|---|
| Applies to | All live Polymarket markets with active conditions |
|---|
| Default mode | limited_live |
|---|
| User-visible | Advanced details only |
|---|
| Developer owner | Polytraders core — Intelligence pod |
|---|
2. Purpose
CrossMarketGraph builds and maintains a directed graph of semantically equivalent and logically linked Polymarket markets by embedding market titles and rules text, applying cosine-similarity clustering, and supplementing with manual override pairs. Each node is a condition_id; each edge carries a relation_type (SAME_EVENT, COMPLEMENTARY, NEG_RISK_SIBLING, SUPERSEDES) and a confidence score. The graph is the foundation for cross-market correlation signals used by SumToOneArb and liquidity-aware strategies to detect near-duplicate markets and hedge opportunities. CrossMarketGraph is strictly read-only — it never submits or signs orders.
3. Why This Bot Matters
Near-duplicate markets not detected
SumToOneArb cannot identify arbitrage opportunities where two markets resolve the same event; edge goes unexploited and probability discrepancies persist.
Stale graph used during rapid market creation spree
New markets linked to a live event are not added to the graph in time; strategy enters both sides of a newly duplicated market, creating an unintended hedge.
Neg-risk siblings not identified
Strategy holds positions on multiple outcomes of the same neg-risk event without knowing they are structurally linked, over-exposing the book to a single resolution.
Incorrect SUPERSEDES edge causes stale-market entry
A superseded market is incorrectly treated as live; strategy generates an intent for a market that has already been replaced by an updated version.
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.
6. Parameter Guide
| Parameter | Default | Warning | Hard | What it controls |
|---|
| cluster_threshold | 0.85 | 0.75 | 0.65 | Minimum cosine similarity for two market embeddings to be linked with a SAME_EVENT or COMPLEMENTARY edge. |
| rebuild_interval_s | 300 | 60 | 30 | How often in seconds the full graph is rebuilt from the Gamma API market list. |
| max_edges_per_node | 20 | 50 | 100 | Maximum number of outbound edges per condition_id node. Prevents graph explosion in large event clusters. |
7. Detailed Parameter Instructions
cluster_threshold
What it means
Minimum cosine similarity for two market embeddings to be linked with a SAME_EVENT or COMPLEMENTARY edge.
Default
{ "cluster_threshold": 0.85 }
Why this default matters
0.85 captures near-identical phrasings while rejecting loosely related markets; lower thresholds produce noisy edges that confuse downstream arbitrage detection.
Threshold logic
| Condition | Action |
|---|
| threshold ≥ 0.85 | Normal — high-precision edges |
| 0.75–0.85 | WARN — increased false-positive edges; review graph density |
| < 0.65 | Reject — PARAMETER_CHANGE_REQUIRES_APPROVAL |
Developer check
if (p.cluster_threshold < p.hard) throw ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL');
User-facing English
Markets are only linked when their descriptions are highly similar, ensuring only genuine duplicates and complements are grouped.
rebuild_interval_s
What it means
How often in seconds the full graph is rebuilt from the Gamma API market list.
Default
{ "rebuild_interval_s": 300 }
Why this default matters
5-minute rebuilds keep the graph fresh for new markets without hammering the Gamma API embedding pipeline.
Threshold logic
| Condition | Action |
|---|
| interval ≥ 300 s | Normal |
| 60–300 s | WARN — increased API load |
| < 30 s | Reject — PARAMETER_CHANGE_REQUIRES_APPROVAL |
Developer check
if (p.rebuild_interval_s < p.hard) throw ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL');
User-facing English
The market relationship map is refreshed regularly to capture newly launched markets.
max_edges_per_node
What it means
Maximum number of outbound edges per condition_id node. Prevents graph explosion in large event clusters.
Default
{ "max_edges_per_node": 20 }
Why this default matters
20 edges per node covers all realistic linked-market scenarios while bounding memory and downstream traversal cost.
Threshold logic
| Condition | Action |
|---|
| edges ≤ 20 | Normal |
| 20–50 | WARN — dense cluster; verify no false-positive edges |
| > 100 | Hard cap enforced — PARAMETER_CHANGE_REQUIRES_APPROVAL |
Developer check
if (p.max_edges_per_node > p.hard) throw ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL');
User-facing English
Each market is linked to at most a fixed number of related markets to keep analysis tractable.
8. Default Configuration
{
"bot_id": "intel.crossmarketgraph",
"version": "2.1.0",
"mode": "limited_live",
"defaults": {
"cluster_threshold": 0.85,
"rebuild_interval_s": 300,
"max_edges_per_node": 20,
"logical_relation_types": [
"SAME_EVENT",
"COMPLEMENTARY",
"NEG_RISK_SIBLING",
"SUPERSEDES"
]
},
"locked": {
"cluster_threshold": {
"min": 0.65
},
"rebuild_interval_s": {
"min": 30
},
"max_edges_per_node": {
"max": 100
}
}
}
9. Implementation Flow
- On each rebuild cycle (rebuild_interval_s), FETCH full live market list from Gamma API including title, rules_text, condition_id, neg_risk, enable_neg_risk, active, closed.
- For each market, compute embedding vector via local sentence-embedding model over title + ' ' + rules_text[:512].
- Apply manual_pair_overrides first: inject edges with confidence=1.0 and the specified relation_type.
- For each pair of active markets, compute cosine_similarity(embed_a, embed_b).
- If cosine_similarity >= cluster_threshold: add directed edge (condition_id_a -> condition_id_b) with relation_type inferred by heuristic: NEG_RISK_SIBLING if both neg_risk=true and same parent; SUPERSEDES if one is closed and one is the replacement; COMPLEMENTARY if titles match a complement pattern (e.g. 'Yes/No' mirror); SAME_EVENT otherwise.
- Cap outbound edges per node at max_edges_per_node, keeping highest-confidence edges.
- Check KillSwitch. If active, update graph in memory but suppress ObservationReport emissions.
- For each new or changed edge (compared to previous graph snapshot), emit an ObservationReport with: report_id, trace_id, condition_id_a, condition_id_b, relation_type, confidence, edge_direction, graph_version.
- Log per-rebuild summary: nodes_total, edges_total, new_edges, dropped_edges, clusters_found, rebuild_latency_ms.
10. Reference Implementation
On each rebuild cycle, fetches all live markets from Gamma API, computes sentence embeddings, applies cosine-similarity clustering above cluster_threshold, injects manual overrides, caps edges per node, and emits ObservationReports for new or changed edges.
Pseudocode is language-agnostic. FETCH = read input. EMIT = produce output.
// --- Initialisation ---
embed_model = load_local_embedding_model()
last_graph = {} // condition_id -> set of (neighbor_id, relation_type, confidence)
graph_version_counter = 0
FUNCTION rebuildCycle():
// --- 0. KillSwitch gate ---
ks = FETCH internal.killswitch.status
// --- 1. Fetch market list ---
markets = FETCH gamma_api.GET('/markets?active=true&closed=false')
IF markets IS NULL:
LOG WARN 'STALE_DATA — Gamma API unavailable; graph frozen'
RETURN
// --- 2. Embed all markets ---
embeddings = {}
FOR market IN markets:
text = market.question + ' ' + market.rules_text[:512]
embeddings[market.condition_id] = embed_model.encode(text)
// --- 3. Inject manual overrides ---
new_graph = {}
FOR override IN params.manual_pair_overrides:
addEdge(new_graph, override.condition_id_a, override.condition_id_b,
override.relation_type, confidence=1.0)
// --- 4. Cosine similarity clustering ---
cids = LIST(embeddings.keys())
FOR i IN range(len(cids)):
FOR j IN range(i+1, len(cids)):
sim = cosine_similarity(embeddings[cids[i]], embeddings[cids[j]])
IF sim < params.cluster_threshold:
CONTINUE
rel = inferRelationType(markets[cids[i]], markets[cids[j]], sim)
addEdge(new_graph, cids[i], cids[j], rel, confidence=sim)
addEdge(new_graph, cids[j], cids[i], rel, confidence=sim)
// --- 5. Cap edges per node ---
FOR node IN new_graph:
IF len(new_graph[node]) > params.max_edges_per_node:
new_graph[node] = topN(new_graph[node], params.max_edges_per_node)
LOG WARN 'CROSSMARKETGRAPH_DENSE_CLUSTER node=' + node
graph_version_counter += 1
graph_version = 'cmg_v' + today() + '_' + graph_version_counter
// --- 6. Diff against last graph ---
new_edges = diff_new(new_graph, last_graph)
dropped_edges = diff_dropped(last_graph, new_graph)
// --- 7. KillSwitch suppress ---
IF ks.active:
LOG INFO 'KILL_SWITCH_ACTIVE — suppressing ObservationReports'
last_graph = new_graph
RETURN
// --- 8. Emit for new/changed edges ---
FOR (cid_a, cid_b, rel, conf) IN new_edges:
EMIT ObservationReport {
report_id: 'rep_cmg_' + cid_a[:6] + '_' + now_ms(),
trace_id: new_trace_id(),
bot_id: 'intel.crossmarketgraph',
kind: 'ObservationReport',
condition_id_a: cid_a,
condition_id_b: cid_b,
relation_type: rel,
confidence: conf,
edge_direction: 'bidirectional',
graph_version: graph_version,
warnings: [],
emitted_at_ms: now_ms()
}
last_graph = new_graph
FUNCTION inferRelationType(m_a, m_b, sim):
IF m_a.neg_risk AND m_b.neg_risk AND sameParent(m_a, m_b):
RETURN 'NEG_RISK_SIBLING'
IF m_a.closed AND NOT m_b.closed AND sim > 0.95:
RETURN 'SUPERSEDES'
IF isComplementPair(m_a.question, m_b.question):
RETURN 'COMPLEMENTARY'
RETURN 'SAME_EVENT'
SDK calls used
gamma_api.GET('/markets?active=true&closed=false')embed_model.encode(text)cosine_similarity(vec_a, vec_b)
Complexity: O(M²) per rebuild cycle where M = live market count; practical with M ≤ 500 at 5-min cadence
11. Wire Examples
Input — what arrives on the wire
{
"label": "Gamma API market pair (candidate for SAME_EVENT edge)",
"source": "gamma_api",
"payload": [
{
"condition_id": "0xabc1230000000000000000000000000000000000000000000000000000000000",
"question": "Will Candidate A win the 2026 election?",
"active": true,
"neg_risk": false,
"enable_neg_risk": false
},
{
"condition_id": "0xdef4560000000000000000000000000000000000000000000000000000000000",
"question": "Will Candidate A win the 2026 general election?",
"active": true,
"neg_risk": false,
"enable_neg_risk": false
}
]
}
Output — what the bot emits
{
"label": "ObservationReport — SAME_EVENT edge detected",
"payload": {
"report_id": "rep_cmg_0xabc1_1746702000000",
"trace_id": "trc_0xcafe0a0b0c0d0e0f",
"bot_id": "intel.crossmarketgraph",
"kind": "ObservationReport",
"condition_id_a": "0xabc1230000000000000000000000000000000000000000000000000000000000",
"condition_id_b": "0xdef4560000000000000000000000000000000000000000000000000000000000",
"relation_type": "SAME_EVENT",
"confidence": 0.92,
"edge_direction": "bidirectional",
"graph_version": "cmg_v20260428_301",
"warnings": [],
"emitted_at_ms": 1746702000042
}
}
12. Decision Logic
APPROVE
Not applicable — CrossMarketGraph is read-only; it never approves or submits orders.
RESHAPE_REQUIRED
Not applicable.
REJECT
ObservationReport emissions are suppressed only when KillSwitch is active (KILL_SWITCH_ACTIVE). Edges below cluster_threshold are silently excluded.
WARNING_ONLY
CROSSMARKETGRAPH_DENSE_CLUSTER is included as a warning on ObservationReports when a node accumulates > max_edges_per_node * 0.8 edges, signalling a potential event-cluster explosion.
13. Standard Decision Output
This bot returns a ObservationReport object. See ObservationReport schema.
{
"report_id": "rep_cmg_0xabc1_1746702000000",
"trace_id": "trc_0xcafe0a0b0c0d0e0f",
"bot_id": "intel.crossmarketgraph",
"kind": "ObservationReport",
"condition_id_a": "0xabc1230000000000000000000000000000000000000000000000000000000000",
"condition_id_b": "0xdef4560000000000000000000000000000000000000000000000000000000000",
"relation_type": "SAME_EVENT",
"confidence": 0.92,
"edge_direction": "bidirectional",
"graph_version": "cmg_v20260428_301",
"warnings": [],
"emitted_at_ms": 1746702000042
}
14. Reason Codes
| Code | Severity | Meaning | Action | User-facing message |
|---|
CROSSMARKETGRAPH_SAME_EVENT_EDGE | INFO | Two markets linked as SAME_EVENT: titles or rules text highly similar (confidence >= cluster_threshold). | Emit ObservationReport; SumToOneArb and strategies consume edge for arb detection. | |
CROSSMARKETGRAPH_NEG_RISK_SIBLING | INFO | Two neg-risk markets share a parent condition; linked as NEG_RISK_SIBLING. | Emit ObservationReport; strategies aggregate combined neg-risk exposure across siblings. | These markets are outcomes of the same multi-result event. |
CROSSMARKETGRAPH_DENSE_CLUSTER | WARN | A node has > 80% of max_edges_per_node edges; potential event-cluster explosion. | Include in ObservationReport warnings; alert Intelligence pod lead for review. | |
CROSSMARKETGRAPH_SUPERSEDES_EDGE | WARN | A closed market is superseded by a new active market (similarity > 0.95). | Emit ObservationReport with relation_type=SUPERSEDES; downstream strategies prefer the new market. | A newer version of this market is available. |
STALE_DATA | WARN | Gamma API unavailable for > 2× rebuild_interval_s; graph is frozen at last snapshot. | Halt ObservationReport emissions; log STALE_DATA; alert on-call. | |
KILL_SWITCH_ACTIVE | HARD_REJECT | KillSwitch active; ObservationReport emissions suppressed. | Continue computing graph updates but suppress all emissions. | Market relationship updates are paused while trading is suspended. |
PARAMETER_CHANGE_REQUIRES_APPROVAL | HARD_REJECT | A parameter change violates a locked bound (e.g. cluster_threshold < 0.65 or rebuild_interval_s < 30). | Reject config change; do not apply. | |
CROSSMARKETGRAPH_EMBED_FAILURE | WARN | Sentence-embedding model failed to encode one or more markets; those markets excluded from this rebuild. | Log with condition_id; skip affected markets; retry on next cycle. | |
15. Metrics & Logs
Metrics emitted
| Metric | Type | Unit | Labels | Meaning |
|---|
polytraders_intel_crossmarketgraph_nodes_total | gauge | count | | Total condition_id nodes in the current graph snapshot. |
polytraders_intel_crossmarketgraph_edges_total | gauge | count | relation_type | Total directed edges in the graph, broken down by relation_type. |
polytraders_intel_crossmarketgraph_observations_emitted_total | counter | count | relation_type | ObservationReports emitted for new or changed edges per rebuild cycle. |
polytraders_intel_crossmarketgraph_rebuild_latency_ms | histogram | milliseconds | | Wall-clock latency of a full graph rebuild cycle. |
polytraders_intel_crossmarketgraph_dense_clusters_total | counter | count | | Number of nodes that hit max_edges_per_node cap in rebuild cycles. |
polytraders_intel_crossmarketgraph_embed_failures_total | counter | count | | Embedding failures causing markets to be skipped in a rebuild cycle. |
Alerts
| Alert | Condition | Severity | Runbook |
|---|
CrossMarketGraphStaleGraph | time_since_last_successful_rebuild > 2 * rebuild_interval_s | page | #runbook-crossmarketgraph-stale-graph |
CrossMarketGraphDenseClusterSpike | rate(polytraders_intel_crossmarketgraph_dense_clusters_total[10m]) > 5 | warn | #runbook-crossmarketgraph-dense-cluster |
CrossMarketGraphRebuildLatencyHigh | histogram_quantile(0.99, rate(polytraders_intel_crossmarketgraph_rebuild_latency_ms_bucket[10m])) > 30000 | warn | #runbook-crossmarketgraph-latency |
CrossMarketGraphEmbedFailures | rate(polytraders_intel_crossmarketgraph_embed_failures_total[10m]) > 10 | warn | #runbook-crossmarketgraph-embed-failures |
Dashboards
- Grafana — Intelligence / CrossMarketGraph node and edge counts
- Grafana — Intelligence / graph rebuild latency and cluster density
16. Developer Reporting
{
"bot_id": "intel.crossmarketgraph",
"rebuild_cycle": 301,
"rebuild_latency_ms": 4820,
"nodes_total": 318,
"edges_total": 1104,
"new_edges": 7,
"dropped_edges": 2,
"clusters_found": 38,
"manual_overrides_applied": 5,
"killswitch_active": false
}
17. Plain-English Reporting
| Situation | User-facing explanation |
|---|
| Two similar-looking markets shown as linked | These two markets resolve the same underlying event. The system tracks this relationship to avoid taking conflicting positions on what is effectively the same question. |
| Market flagged as a neg-risk sibling | This market is one outcome of a multi-outcome event. The system tracks all outcomes together to manage combined exposure across the whole event. |
| Market flagged as superseded | A newer version of this market is available. The system will prefer the replacement market for new activity. |
18. Failure-Mode Block
| main_failure_mode | Embedding model unavailable causes a full rebuild to fail, leaving the graph frozen at the last successful snapshot. Downstream strategies continue using the stale graph; new markets created since the last rebuild are invisible. |
|---|
| false_positive_risk | Two markets with similar titles but different resolution events (e.g. two different elections with similar question phrasing) incorrectly linked as SAME_EVENT, causing SumToOneArb to attempt cross-market arb on unrelated probabilities. |
|---|
| false_negative_risk | Markets with very different titles but identical resolution (e.g. paraphrased questions from different operators) score below cluster_threshold and are not linked, missing a valid arbitrage pair. |
|---|
| safe_fallback | If Gamma API is unavailable, retain last-known graph and emit STALE_DATA WARN. Do not emit ObservationReports based on graph older than 2× rebuild_interval_s. |
|---|
| required_dependencies | Gamma API live market list, Local sentence-embedding model, KillSwitch active flag readable |
|---|
19. Failure-Injection Recipes
| Scenario | How to inject | Expected behaviour | Recovery |
|---|
GAMMA_API_DOWN | Block TCP to gamma-api.polymarket.com for 700 s (> 2× rebuild_interval_s=300) | | Automatic on next successful Gamma API response; full rebuild triggered immediately |
EMBED_MODEL_FAILURE | Kill local embedding model process mid-rebuild | | Embedding model restarted automatically; next rebuild cycle processes full market list |
DENSE_CLUSTER_EXPLOSION | Inject 150 mock markets with titles starting 'Will X win...' creating a dense cluster | | Automatic; graph stabilises once cluster is capped |
KILL_SWITCH_ON | Set killswitch.active=true; trigger a rebuild cycle with new edges | | Emissions resume on first rebuild after KillSwitch reset; all new edges from suppressed cycles emitted |
LOW_THRESHOLD_CONFIG_REJECTED | Attempt to set cluster_threshold=0.50 | | Operator must submit approved config change through governance workflow |
20. State & Persistence
Cold-start recovery
On cold start, graph is empty. First rebuild cycle populates it. Until first rebuild completes, no ObservationReports are emitted.
21. Concurrency & Idempotency
| Aspect | Specification |
|---|
| Execution model | single-threaded event loop |
| Max in-flight | 1 |
| Idempotency key | graph_version |
| Per-call timeout (ms) | 30000 |
| Backpressure strategy | drop-after-buffer — if rebuild takes longer than rebuild_interval_s, the next scheduled rebuild is skipped until current one completes |
| Locking / mutual exclusion | none — single rebuild loop; reads and emits are serialised |
22. Dependencies
Depends on (must run first)
Emits to (downstream consumers)
External services
| Service | Endpoint | SLA assumed | On failure |
|---|
| Gamma API | https://gamma-api.polymarket.com | 99.9% / 500 ms p99 | |
| Local sentence-embedding model | local process | process-availability | |
23. Security Surfaces
Abuse vectors considered
- Gamma API returning adversarially crafted market titles to manipulate cosine-similarity scores and inject false SAME_EVENT edges
- Manual override list poisoned with a cross-market link that causes downstream arb strategy to take losses
Mitigations
- Embeddings computed on truncated text (512 chars); extreme outliers in similarity space are detectable as anomalies
- Manual overrides require operator-level config change with audit trail
- All ObservationReports are informational only — downstream strategies and risk bots independently validate market state before acting
24. Polymarket V2 Compatibility
| Aspect | Value |
|---|
| CLOB version | v2 |
| Collateral asset | pUSD |
| EIP-712 Exchange domain version | 2 |
| Aware of builderCode field | no |
| Aware of negative-risk markets | yes |
| Multi-chain ready | no |
| SDK used | py-clob-client-v2 |
| Settlement contract | CTFExchangeV2 |
| Notes | CrossMarketGraph reads Gamma API neg_risk and enable_neg_risk fields to classify NEG_RISK_SIBLING edges; liquidity annotations on graph nodes use pUSD denomination from data_api and clob_public V2 responses. |
API surfaces declared
gamma_apidata_apiclob_publicinternal
Networks supported
polygon
25. Versioning & Migration
| Field | Value |
|---|
| spec | 2.0.0 |
| implementation | 2.1.0 |
| schema | 2 |
| released | 2026-04-28 |
Migration history
| Date | From | To | Reason | Action taken |
|---|
| 2026-04-28 | v1 | v2 | CLOB V2 cutover — pUSD denomination and enableNegRisk flag added to Gamma API | Updated Gamma API queries to include enableNegRisk field for NEG_RISK_SIBLING edge classification. Graph node liquidity annotations updated from USDC.e to pUSD denomination. No feeRateBps or signed-order plumbing in this bot. |
26. Acceptance Tests
Unit Tests
| Test | Setup | Expected result |
|---|
| Two markets with cosine_similarity=0.92 linked as SAME_EVENT | Mock two market embeddings with similarity=0.92, cluster_threshold=0.85 | ObservationReport emitted with relation_type=SAME_EVENT, confidence=0.92 |
| Market pair below threshold not linked | Mock cosine_similarity=0.60, cluster_threshold=0.85 | No edge created; no ObservationReport emitted |
| Manual override injected with confidence=1.0 | manual_pair_overrides = [{condition_id_a, condition_id_b, relation_type=COMPLEMENTARY}] | Edge created with confidence=1.0 regardless of embedding similarity |
| max_edges_per_node cap enforced | Node with 25 candidate edges, max_edges_per_node=20 | Only top-20 highest-confidence edges retained; excess edges dropped |
| KillSwitch suppresses ObservationReport emissions | killswitch.active=true; new edge detected | Graph updated in memory; no ObservationReport emitted; KILL_SWITCH_ACTIVE logged |
| NEG_RISK_SIBLING correctly assigned | Two markets with neg_risk=true, same parent condition, similarity=0.91 | ObservationReport with relation_type=NEG_RISK_SIBLING |
Integration Tests
| Test | Expected result |
|---|
| Full rebuild cycle generates correct graph from live Gamma API | Graph node count matches live market count; known linked pairs present as edges |
| New market added to Gamma API appears as graph node on next rebuild cycle | ObservationReport emitted for any new edges involving the new condition_id |
| Gamma API outage leaves graph frozen with STALE_DATA warning | No new ObservationReports emitted; STALE_DATA WARN logged; graph_version unchanged |
Property Tests
| Property | Required behaviour |
|---|
| CrossMarketGraph never submits, signs, or modifies any order | Always true |
| No ObservationReport emitted when KillSwitch is active | Always true |
| All edge confidence values are in [0.0, 1.0] | Always true |
27. Operational Runbook
CrossMarketGraph incidents are usually Gamma API outages or embedding model failures causing the graph to freeze. Since the graph is read-only infrastructure, stale graphs affect only new edge discovery — existing positions are unaffected.
On-call actions
| Alert | First step | Diagnosis | Mitigation | Escalate to |
|---|
CrossMarketGraphStaleGraph | | | | |
CrossMarketGraphDenseClusterSpike | | | | |
CrossMarketGraphRebuildLatencyHigh | | | | |
CrossMarketGraphEmbedFailures | | | | |
Manual overrides
Healthcheck
/internal/health/crossmarketgraph → 200 Last rebuild completed within 2× rebuild_interval_s AND nodes_total > 0 AND no STALE_DATA in last cycle; red if No successful rebuild in > 2× rebuild_interval_s OR embed_failures_total rate > 10/min OR Gamma API unreachable
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 |