@battlegrid/mcp-server 31.2.108 → 31.2.110

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,10 +24,36 @@ Seeing package `31.x` alongside handshake `battlegrid@33.x` — the package **be
24
24
 
25
25
  **What this changes for you:** nothing about how you call anything. Upgrading the package no longer waits on a server deploy, and a server deploy no longer strands you on a package that names the wrong contract — reconnect and the announcement follows. **Contract breaking-change notes are no longer keyed to package versions**, since a contract move is no longer a release here; the v11-and-earlier notes below are kept as history, and the live vocabulary is always discovery.
26
26
 
27
+ ## Contract history — v111.1 (every read fits hosted Claude, and a large one says so)
28
+
29
+ **One refusal is added at v111.1; nothing you send is refused that was accepted.** v111.1 is the contract on top of
30
+ v111. Reconnect the proxy, or restart it, so discovery reads the new schemas and the new resource.
31
+
32
+ ### Refusal vocabulary
33
+
34
+ - **`RESULT_TOO_LARGE`.** A read-only tool whose result would serialize past the server's result-character cap
35
+ (at most 150,000, hosted Claude's tool-result cap) is refused whole, never cut, with details
36
+ `{ limit: "result_chars", actual, maximum }`. `get_market_context` (fewer `modules`), and `get_agent_journal`,
37
+ `list_gate_blocks` and `list_market_grid_sessions` (a smaller `limit`) add `nextAct: "narrow"`; a read with no
38
+ input that asks for less adds none. A tool that writes is never refused this way. The code also joins the draft
39
+ diagnostics' `code` enum.
40
+
41
+ ### Behaviour behind unchanged schemas
42
+
43
+ - **The server instructions are an index within 4,096 characters**, the length Claude reads: the rules every session
44
+ needs, then one routing line per workflow naming its entry tool and skills. The workflow cards move to the
45
+ `battlegrid://guide/workflows` resource, and the grid format stays in `battlegrid://reference/grid-format`.
46
+ - **Ten large reads declare `_meta["anthropic/maxResultSizeChars"]`** equal to the server's cap, so Claude Code keeps
47
+ their results in the conversation rather than moving them to a file.
48
+ - **Input schemas hold each reused or recursive shape once, under named `$defs`**, where they pointed into a sibling
49
+ property; they accept exactly what they accepted. No schema publishes `{ "not": {} }`, and four strategy outputs
50
+ stop publishing `conditionVerdicts`, a property no response carried.
51
+ - **Descriptions name their parameters instead of listing the members of an input enum**; the enum is the list.
52
+
27
53
  ## Contract history — v111 (the draft tools take their arguments at the top level)
28
54
 
29
55
  **Breaking at v111: every draft-lifecycle tool takes its id, `draftVersion` and payload as top-level
30
- arguments.** v111 is the contract on top of v110.12. Reconnect the proxy, or restart it, so discovery
56
+ arguments.** v111 is the contract on top of v110.13. Reconnect the proxy, or restart it, so discovery
31
57
  reads the new schemas.
32
58
 
33
59
  ### Rejected input — something you send is no longer accepted
@@ -3635,8 +3661,9 @@ you reach over MCP:
3635
3661
  > fails CI on a hand edit. Change the skill upstream and let the export lane bring it here.
3636
3662
 
3637
3663
  A client connected to BattleGrid's remote server directly receives its `initialize` instructions:
3638
- the rules that span tools and one routing card per workflow, each naming the `battlegrid-*` skill
3639
- above that holds the full procedure. This proxy does not relay those instructions; the skills
3664
+ the rules that span tools and one routing line per workflow, each naming the `battlegrid-*` skill
3665
+ above that holds the full procedure, with the workflow cards in the `battlegrid://guide/workflows`
3666
+ resource. This proxy does not relay those instructions; the skills
3640
3667
  installed beside it carry the same workflows.
3641
3668
 
3642
3669
  ## License
package/dist/index.d.ts CHANGED
@@ -48,7 +48,7 @@ import { type Implementation, type Prompt, type Resource } from '@modelcontextpr
48
48
  * being asked. Move it for a change to THIS package — a proxy fix, a dependency bump, a docs
49
49
  * correction. Never move it to track the server.
50
50
  */
51
- export declare const PACKAGE_VERSION = "31.2.108";
51
+ export declare const PACKAGE_VERSION = "31.2.110";
52
52
  export declare const DEFAULT_URL = "https://mcp.battlegrid.trade/mcp";
53
53
  export interface EnvConfig {
54
54
  apiKeys: string[];
package/dist/index.js CHANGED
@@ -51,7 +51,7 @@ import { ListToolsRequestSchema, CallToolRequestSchema, ListPromptsRequestSchema
51
51
  * being asked. Move it for a change to THIS package — a proxy fix, a dependency bump, a docs
52
52
  * correction. Never move it to track the server.
53
53
  */
54
- export const PACKAGE_VERSION = '31.2.108';
54
+ export const PACKAGE_VERSION = '31.2.110';
55
55
  export const DEFAULT_URL = 'https://mcp.battlegrid.trade/mcp';
56
56
  const MAX_RETRIES = 3;
57
57
  const RETRY_DELAYS_MS = [2000, 4000, 8000];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@battlegrid/mcp-server",
3
- "version": "31.2.108",
3
+ "version": "31.2.110",
4
4
  "description": "BattleGrid MCP server — play crypto prediction games from AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "generator": "battlegrid-app/server/scripts/export-mcp-skills.mjs",
3
- "contractVersion": "110.10.0",
3
+ "contractVersion": "110.13.0",
4
4
  "files": {
5
5
  "battlegrid-agent-management/SKILL.md": "9dc151c32c3578d06e8895c6752d7a64959bff6a6681a01d62ab65e1ea1590d1",
6
- "battlegrid-agent-management/references/agent-stage-examples.md": "d47555906ce8dedf4c17422f8f5d60187f2d6b3c0af5d9545617a10a5bdb59a1",
7
- "battlegrid-arena-play/SKILL.md": "88534714cdbaa31344e1798b2b3f18836bf543f5610d118d76095d1a0dbea502",
8
- "battlegrid-arena-play/references/entry-stage-examples.md": "3bc62f9faca7b5529d51a9794e162333216acb23f0d7f644d5180b9cbc696fca",
6
+ "battlegrid-agent-management/references/agent-stage-examples.md": "dffcc353d61dfc7b5bb6a2b3077fc6bf8c760a34c287cafb3b59b99306f24195",
7
+ "battlegrid-arena-play/SKILL.md": "2e37970a66b8738ffbc445a23da90651c1f41b56ce4eef551582ab123517ef74",
8
+ "battlegrid-arena-play/references/entry-stage-examples.md": "0223f3743171ff213e943789d27590b2f65648398e85e10cd24938d5eb6af665",
9
9
  "battlegrid-market-analysis/SKILL.md": "fcbe98e30e1edce39bb170c224cdf20181934f62b5f3a26b293787c70eeb6229",
10
- "battlegrid-radar-deployment/SKILL.md": "652325c4923d79b9c9b78026a5493bfaaedf01f600641511438a9c4bf497c0b1",
11
- "battlegrid-radar-deployment/references/arena-stage-examples.md": "f605aaa266a291ef1b6d02a0e8885ad5df2fea88c800be2b6625cd629cd741f2",
12
- "battlegrid-radar-deployment/references/radar-stage-examples.md": "1ddad4a11f021dd65234ee65cc12d7d1561fe9acfd61cb021f4352080d4cecd5",
13
- "battlegrid-strategy-authoring/SKILL.md": "5ce41e11d50658226230cfccb70a5c5f08e52755ef737c528d98872f239b3d4e",
14
- "battlegrid-strategy-authoring/references/strategy-stage-examples.md": "9822cc2bcc8975a3e436c2a960b10e03c95e6e6b4b04bc2206e0ac90688cab66",
10
+ "battlegrid-radar-deployment/SKILL.md": "dfe8f354ac3dd426eedeac1ec080ac518e9c8cbfefdd26036afa61f80c08295c",
11
+ "battlegrid-radar-deployment/references/arena-stage-examples.md": "d27cfed1f4663f267c4a7ecebe4a6e65a450fc74bd14ce8987fb61af5bbf2ca5",
12
+ "battlegrid-radar-deployment/references/radar-stage-examples.md": "e3805f5c1b243135a7f25fb3a8cc6093dd242f8ad67b7e6b242bbdefa58a0735",
13
+ "battlegrid-strategy-authoring/SKILL.md": "39cfa46b1f640e6800edb7e85a8f2c4b6b8786cddf71bb8244d172a44fc11d75",
14
+ "battlegrid-strategy-authoring/references/strategy-stage-examples.md": "f10ecdc91f3660a708eee7a7bacefce2acbb46c9cf7e0ac1454bd54f839f39fd",
15
15
  "battlegrid-strategy-doctor/SKILL.md": "e34e055b0cc9b355bc1adeb5d49d464eaa0756ca3f48dc89ca2ccdda94e1311f",
16
16
  "battlegrid-strategy-examples/SKILL.md": "597ddacdfc00955fcfd5a1afcc40b5ea72a0f658acbbebc8264afeecc46d2306",
17
17
  "battlegrid-strategy-examples/references/playbooks.md": "2309eb7e8324f563c5b1b51e05da931b37c542484135a2be749eff6ef78aa40f",
@@ -21,14 +21,12 @@ platform seed.
21
21
 
22
22
  ```json stage_agent_draft
23
23
  {
24
- "request": {
25
- "draftVersion": 0,
26
- "axes": {
27
- "IDENTITY": { "displayName": "Breakout Scout" },
28
- "BEHAVIOR": { "behavior": { "risk": "MODERATE", "outlook": "REALIST", "conviction": "MEASURED" } },
29
- "MODEL": { "modelId": "<MODEL_ID>" },
30
- "STRATEGY_BINDING": { "strategyId": "<STRATEGY_ID>" }
31
- }
24
+ "draftVersion": 0,
25
+ "axes": {
26
+ "IDENTITY": { "displayName": "Breakout Scout" },
27
+ "BEHAVIOR": { "behavior": { "risk": "MODERATE", "outlook": "REALIST", "conviction": "MEASURED" } },
28
+ "MODEL": { "modelId": "<MODEL_ID>" },
29
+ "STRATEGY_BINDING": { "strategyId": "<STRATEGY_ID>" }
32
30
  }
33
31
  }
34
32
  ```
@@ -39,12 +37,10 @@ BEHAVIOR is sent whole: all three of risk, outlook and conviction, even when onl
39
37
 
40
38
  ```json stage_agent_draft
41
39
  {
42
- "request": {
43
- "agentId": "<AGENT_ID>",
44
- "draftVersion": 4,
45
- "axes": {
46
- "BEHAVIOR": { "behavior": { "risk": "CONSERVATIVE", "outlook": "REALIST", "conviction": "CAUTIOUS" } }
47
- }
40
+ "agentId": "<AGENT_ID>",
41
+ "draftVersion": 4,
42
+ "axes": {
43
+ "BEHAVIOR": { "behavior": { "risk": "CONSERVATIVE", "outlook": "REALIST", "conviction": "CAUTIOUS" } }
48
44
  }
49
45
  }
50
46
  ```
@@ -53,12 +49,10 @@ BEHAVIOR is sent whole: all three of risk, outlook and conviction, even when onl
53
49
 
54
50
  ```json stage_agent_draft
55
51
  {
56
- "request": {
57
- "agentId": "<AGENT_ID>",
58
- "draftVersion": 4,
59
- "axes": {
60
- "STRATEGY_BINDING": { "strategyId": "<STRATEGY_ID>" }
61
- }
52
+ "agentId": "<AGENT_ID>",
53
+ "draftVersion": 4,
54
+ "axes": {
55
+ "STRATEGY_BINDING": { "strategyId": "<STRATEGY_ID>" }
62
56
  }
63
57
  }
64
58
  ```
@@ -48,8 +48,10 @@ the enablement path there.
48
48
 
49
49
  ### 2. Workflow A reads, in order
50
50
 
51
- 1. `list_market_grid_sessions` with status `PENDING` — the sessions still enterable. **The
52
- `sessionId` you use comes from here; never fabricate one.**
51
+ 1. `list_market_grid_sessions` with status `PENDING`. A session accepts entries while it is PENDING
52
+ **and** its `lockAt` is still ahead — the status turns LIVE some time after the lock, so a session
53
+ can still read PENDING once entries have closed. **The `sessionId` you use comes from here; never
54
+ fabricate one.**
53
55
  2. `get_market_grid_session` — the coin pool (note each coin's `id`), the entry fee, the pool and
54
56
  the session's three instants: `startsAt` (the **Opening Bell** — the open of the one candle it
55
57
  scores), `lockAt` (entries close) and `settleAt` (the candle closes). Entries stay open through
@@ -60,13 +62,21 @@ the enablement path there.
60
62
  4. `check_market_grid_submission` — **before composing anything.** If a submission already exists,
61
63
  report it (with its id and time); while the session is still PENDING, a commit of the draft
62
64
  replaces its picks. Never compose a duplicate.
63
- 5. `get_market_grid_entry_draft({ request: { sessionId } })` — what the draft holds now, the player's
65
+ 5. `get_market_grid_entry_draft({ sessionId })` — what the draft holds now, the player's
64
66
  own picks included, with the `draftVersion` and `committedRevision` your stage and commit name.
65
67
  Answer "what does my grid look like" from this read, never from a pick count.
66
68
 
69
+ **Know the window before you spend it.** The first read already carries each session's `lockAt`:
70
+ compare it with the current time — in Commander, every player turn carries the time it was sent — and
71
+ tell the player how long remains before the rest of the reads use it up. A staged grid still needs the
72
+ player's PLACE ENTRY, or your commit, before the lock. A `lockAt` already behind the current time
73
+ means the session is **closed to entries even though it reads PENDING**: say so and point at the next
74
+ session rather than composing for it — a stage or commit there is refused `CONFLICT` as closed to
75
+ entries.
76
+
67
77
  ### 3. Compose — stage into the draft, and the reasoning is yours to get right
68
78
 
69
- `stage_market_grid_entry_draft({ request: { sessionId, draftVersion, axes } })`, naming the
79
+ `stage_market_grid_entry_draft({ sessionId, draftVersion, axes })`, naming the
70
80
  `draftVersion` the read returned. Each cell axis is `{ cell: { coinId, prediction } }` — `coinId` the
71
81
  pool coin's `id` — or `{ cell: null }` to empty it. **Compose on top of what the draft holds**: a cell
72
82
  you do not stage keeps the player's pick, and you never discard their picks to start over unless they
@@ -103,7 +113,7 @@ say that rather than inventing a bar), whether it meets the threshold, and the p
103
113
  `impact` — `ENTER` with the `entryFee` the commit charges, or `REPLACE` for none. One confirmation
104
114
  naming **the session, that fee, and the confidence** — then commit on an explicit pick.
105
115
 
106
- - Direct → `commit_market_grid_entry_draft({ request: { sessionId, draftVersion, expectedRevision } })`,
116
+ - Direct → `commit_market_grid_entry_draft({ sessionId, draftVersion, expectedRevision })`,
107
117
  naming exactly the `draftVersion` and `committedRevision` the last read returned (`null` with no
108
118
  entry). A refusal naming `get_draft` means the draft or the entry moved: read again and confirm
109
119
  again — never retry with a bumped number.
@@ -126,7 +136,8 @@ player's, and the attribution is part of what was scored.
126
136
  ### 5. After settlement
127
137
 
128
138
  - A session moves PENDING → LIVE → RESOLVING → SETTLED. It stays PENDING through the Opening Bell
129
- window and goes LIVE at `lockAt`. Two states sit off that path: CANCELLED
139
+ window and turns LIVE once its lock has passed; entries close at `lockAt` itself, whatever the
140
+ status reads. Two states sit off that path: CANCELLED
130
141
  (entry fees refunded) and SETTLEMENT_QUARANTINED (settlement exhausted its retries and awaits an
131
142
  operator). Either one is the answer — report it as the status.
132
143
  - `get_market_grid_results` — available only once the session is SETTLED. Before that it returns a
@@ -21,23 +21,21 @@ enter, each citing the market context you read.
21
21
 
22
22
  ```json stage_market_grid_entry_draft
23
23
  {
24
- "request": {
25
- "sessionId": "<SESSION_ID>",
26
- "draftVersion": 0,
27
- "axes": {
28
- "CELL_0": { "cell": { "coinId": "<COIN_ID>", "prediction": "UP" } },
29
- "CELL_1": { "cell": { "coinId": "<SECOND_COIN_ID>", "prediction": "DOWN" } },
30
- "CELL_2": { "cell": { "coinId": "<THIRD_COIN_ID>", "prediction": "UP" } },
31
- "RATIONALE": {
32
- "reasoning": "The leader is breaking out on rising volume while the second coin rejects its range high.",
33
- "confidenceScore": 0.7,
34
- "modelName": "your-model-name",
35
- "pickReasoning": [
36
- { "coinId": "<COIN_ID>", "reasoning": "Breaking resistance on rising volume.", "confidence": 0.8 },
37
- { "coinId": "<SECOND_COIN_ID>", "reasoning": "Bearish divergence at the range high.", "confidence": 0.6 },
38
- { "coinId": "<THIRD_COIN_ID>", "reasoning": "Holding its trend above the session open.", "confidence": 0.6 }
39
- ]
40
- }
24
+ "sessionId": "<SESSION_ID>",
25
+ "draftVersion": 0,
26
+ "axes": {
27
+ "CELL_0": { "cell": { "coinId": "<COIN_ID>", "prediction": "UP" } },
28
+ "CELL_1": { "cell": { "coinId": "<SECOND_COIN_ID>", "prediction": "DOWN" } },
29
+ "CELL_2": { "cell": { "coinId": "<THIRD_COIN_ID>", "prediction": "UP" } },
30
+ "RATIONALE": {
31
+ "reasoning": "The leader is breaking out on rising volume while the second coin rejects its range high.",
32
+ "confidenceScore": 0.7,
33
+ "modelName": "your-model-name",
34
+ "pickReasoning": [
35
+ { "coinId": "<COIN_ID>", "reasoning": "Breaking resistance on rising volume.", "confidence": 0.8 },
36
+ { "coinId": "<SECOND_COIN_ID>", "reasoning": "Bearish divergence at the range high.", "confidence": 0.6 },
37
+ { "coinId": "<THIRD_COIN_ID>", "reasoning": "Holding its trend above the session open.", "confidence": 0.6 }
38
+ ]
41
39
  }
42
40
  }
43
41
  }
@@ -51,12 +49,10 @@ that coin changed.
51
49
 
52
50
  ```json stage_market_grid_entry_draft
53
51
  {
54
- "request": {
55
- "sessionId": "<SESSION_ID>",
56
- "draftVersion": 4,
57
- "axes": {
58
- "CELL_1": { "cell": { "coinId": "<SECOND_COIN_ID>", "prediction": "UP" } }
59
- }
52
+ "sessionId": "<SESSION_ID>",
53
+ "draftVersion": 4,
54
+ "axes": {
55
+ "CELL_1": { "cell": { "coinId": "<SECOND_COIN_ID>", "prediction": "UP" } }
60
56
  }
61
57
  }
62
58
  ```
@@ -65,21 +61,19 @@ that coin changed.
65
61
 
66
62
  ```json stage_market_grid_entry_draft
67
63
  {
68
- "request": {
69
- "sessionId": "<SESSION_ID>",
70
- "draftVersion": 5,
71
- "axes": {
72
- "CELL_1": { "cell": { "coinId": "<SECOND_COIN_ID>", "prediction": "UP" } },
73
- "RATIONALE": {
74
- "reasoning": "The second coin reclaimed its range high, so it now runs with the leader.",
75
- "confidenceScore": 0.65,
76
- "modelName": "your-model-name",
77
- "pickReasoning": [
78
- { "coinId": "<COIN_ID>", "reasoning": "Breaking resistance on rising volume.", "confidence": 0.8 },
79
- { "coinId": "<SECOND_COIN_ID>", "reasoning": "Reclaimed the range high on the last close.", "confidence": 0.6 },
80
- { "coinId": "<THIRD_COIN_ID>", "reasoning": "Holding its trend above the session open.", "confidence": 0.6 }
81
- ]
82
- }
64
+ "sessionId": "<SESSION_ID>",
65
+ "draftVersion": 5,
66
+ "axes": {
67
+ "CELL_1": { "cell": { "coinId": "<SECOND_COIN_ID>", "prediction": "UP" } },
68
+ "RATIONALE": {
69
+ "reasoning": "The second coin reclaimed its range high, so it now runs with the leader.",
70
+ "confidenceScore": 0.65,
71
+ "modelName": "your-model-name",
72
+ "pickReasoning": [
73
+ { "coinId": "<COIN_ID>", "reasoning": "Breaking resistance on rising volume.", "confidence": 0.8 },
74
+ { "coinId": "<SECOND_COIN_ID>", "reasoning": "Reclaimed the range high on the last close.", "confidence": 0.6 },
75
+ { "coinId": "<THIRD_COIN_ID>", "reasoning": "Holding its trend above the session open.", "confidence": 0.6 }
76
+ ]
83
77
  }
84
78
  }
85
79
  }
@@ -105,8 +105,8 @@ is test-routing a regime. Never carry a fact from a radar conversation into it,
105
105
  on duty, whether it trades once committed, and for a first deployment the coin cap
106
106
  (`admission.coinCapReached` true means the commit will be refused until a coin is un-deployed).
107
107
  Do not confirm a draft whose diagnostics carry an error: stage a fix.
108
- 3. `preview_radar_resolution` with `request: { kind: "DRAFT", draftVersion }` at the version that read
109
- returned. It composes the draft over the deployed policy **exactly as the commit will write it**,
108
+ 3. `preview_radar_resolution({ coinId, request: { kind: "DRAFT", draftVersion } })` at the version that
109
+ read returned. It composes the draft over the deployed policy **exactly as the commit will write it**,
110
110
  and refuses a draft no longer at that version with `DRAFT_VERSION_MOVED`.
111
111
 
112
112
  To try a slot set without touching the draft, preview `{ kind: "SLOTS", slots }` — it resolves
@@ -134,8 +134,8 @@ choose. Complete stage payloads for every row are in `references/radar-stage-exa
134
134
  and `REGIME_ANCHOR` (the anchor override, or null to inherit the arena's). Pausing is never staged.
135
135
  2. `get_deployment_policy_draft` — its `draftVersion`, `committedRevision`, diff, `diagnostics` and
136
136
  `impact` (the next session's resolution and whether it will play), exactly as for Radar.
137
- 3. `preview_deployment_resolution` with `request: { kind: "DRAFT", draftVersion }` at the version
138
- that read returned.
137
+ 3. `preview_deployment_resolution({ presetId, request: { kind: "DRAFT", draftVersion } })` at the
138
+ version that read returned.
139
139
 
140
140
  A draft that would hold no rule and no catch-all is a withdrawal, which a commit never does — that is
141
141
  `delete_deployment_policy` (step 4).
@@ -239,11 +239,11 @@ the reason — and **names what the change does to the stored policy**, read fro
239
239
 
240
240
  Then:
241
241
 
242
- - **Radar** → `commit_radar_deployment_draft({ request: { coinId, draftVersion, expectedRevision } })`,
242
+ - **Radar** → `commit_radar_deployment_draft({ coinId, draftVersion, expectedRevision })`,
243
243
  naming exactly the `draftVersion` and `committedRevision` your draft read returned — the version
244
244
  your preview resolved. Ask with `ask_user` first and commit only after an explicit confirming pick.
245
245
  The axes it published leave the draft.
246
- - **Arena** → `commit_deployment_policy_draft({ request: { presetId, draftVersion, expectedRevision } })`,
246
+ - **Arena** → `commit_deployment_policy_draft({ presetId, draftVersion, expectedRevision })`,
247
247
  the same way.
248
248
 
249
249
  **On `DRAFT_VERSION_MOVED` or a CONFLICT: re-read, re-preview, re-confirm.** In that order, and all
@@ -256,7 +256,7 @@ ask for again.
256
256
 
257
257
  **Pause a coin's Radar** → `pause_radar_deployment({ coinId })`. No preview and no revision: stopping
258
258
  never waits on a read. The player's draft keeps its content and is re-based onto the paused revision.
259
- **Resume** → preview the deployed policy with `request: { kind: "COMMITTED" }`, tell the player which
259
+ **Resume** → preview the deployed policy with `preview_radar_resolution({ coinId, request: { kind: "COMMITTED" } })`, tell the player which
260
260
  agents will go on duty again, and on their word
261
261
  `resume_radar_deployment({ coinId, expectedPolicyId, expectedRevision })` naming the `policyId` and
262
262
  `revision` that preview returned — so it re-arms the policy the player was shown, or nothing.
@@ -274,8 +274,8 @@ same cancellation and refund as their own Cancel button. Say nothing is cancelle
274
274
 
275
275
  **Discard a draft** only on the player's word. Read it first and tell the player what it holds and
276
276
  when and from where it was last written; then
277
- `discard_radar_deployment_draft({ request: { coinId, draftVersion } })` or
278
- `discard_deployment_policy_draft({ request: { presetId, draftVersion } })` at **the version you read**.
277
+ `discard_radar_deployment_draft({ coinId, draftVersion })` or
278
+ `discard_deployment_policy_draft({ presetId, draftVersion })` at **the version you read**.
279
279
  If the draft moved since, it is refused with `DRAFT_VERSION_MOVED` and nothing is removed — read it
280
280
  again and show them.
281
281
 
@@ -17,13 +17,11 @@ axis you omit keeps the value the draft already has.
17
17
 
18
18
  ```json stage_deployment_policy_draft
19
19
  {
20
- "request": {
21
- "presetId": "<PRESET_ID>",
22
- "draftVersion": 0,
23
- "axes": {
24
- "DEFAULT_SLOT": {
25
- "defaultSlot": { "agentId": "<AGENT_ID>", "minConfidence": null }
26
- }
20
+ "presetId": "<PRESET_ID>",
21
+ "draftVersion": 0,
22
+ "axes": {
23
+ "DEFAULT_SLOT": {
24
+ "defaultSlot": { "agentId": "<AGENT_ID>", "minConfidence": null }
27
25
  }
28
26
  }
29
27
  }
@@ -33,19 +31,17 @@ axis you omit keeps the value the draft already has.
33
31
 
34
32
  ```json stage_deployment_policy_draft
35
33
  {
36
- "request": {
37
- "presetId": "<PRESET_ID>",
38
- "draftVersion": 0,
39
- "axes": {
40
- "RULES": {
41
- "rules": [
42
- {
43
- "agentId": "<AGENT_ID>",
44
- "minConfidence": null,
45
- "conditions": [{ "kind": "regime", "regimes": ["bull_expansion", "bull_ranging"] }]
46
- }
47
- ]
48
- }
34
+ "presetId": "<PRESET_ID>",
35
+ "draftVersion": 0,
36
+ "axes": {
37
+ "RULES": {
38
+ "rules": [
39
+ {
40
+ "agentId": "<AGENT_ID>",
41
+ "minConfidence": null,
42
+ "conditions": [{ "kind": "regime", "regimes": ["bull_expansion", "bull_ranging"] }]
43
+ }
44
+ ]
49
45
  }
50
46
  }
51
47
  }
@@ -58,21 +54,19 @@ session occurrence, never both.
58
54
 
59
55
  ```json stage_deployment_policy_draft
60
56
  {
61
- "request": {
62
- "presetId": "<PRESET_ID>",
63
- "draftVersion": 0,
64
- "axes": {
65
- "RULES": {
66
- "rules": [
67
- {
68
- "agentId": "<AGENT_ID>",
69
- "minConfidence": 0.6,
70
- "conditions": [
71
- { "kind": "session_start", "startTimes": ["14:00:00", "15:00:00"], "days": [1, 2, 3, 4, 5] }
72
- ]
73
- }
74
- ]
75
- }
57
+ "presetId": "<PRESET_ID>",
58
+ "draftVersion": 0,
59
+ "axes": {
60
+ "RULES": {
61
+ "rules": [
62
+ {
63
+ "agentId": "<AGENT_ID>",
64
+ "minConfidence": 0.6,
65
+ "conditions": [
66
+ { "kind": "session_start", "startTimes": ["14:00:00", "15:00:00"], "days": [1, 2, 3, 4, 5] }
67
+ ]
68
+ }
69
+ ]
76
70
  }
77
71
  }
78
72
  }
@@ -82,22 +76,20 @@ session occurrence, never both.
82
76
 
83
77
  ```json stage_deployment_policy_draft
84
78
  {
85
- "request": {
86
- "presetId": "<PRESET_ID>",
87
- "draftVersion": 0,
88
- "axes": {
89
- "RULES": {
90
- "rules": [
91
- {
92
- "agentId": "<AGENT_ID>",
93
- "minConfidence": null,
94
- "conditions": [
95
- { "kind": "regime", "regimes": ["volatile"] },
96
- { "kind": "session_start", "startTimes": ["14:00:00"], "days": [1, 2, 3, 4, 5] }
97
- ]
98
- }
99
- ]
100
- }
79
+ "presetId": "<PRESET_ID>",
80
+ "draftVersion": 0,
81
+ "axes": {
82
+ "RULES": {
83
+ "rules": [
84
+ {
85
+ "agentId": "<AGENT_ID>",
86
+ "minConfidence": null,
87
+ "conditions": [
88
+ { "kind": "regime", "regimes": ["volatile"] },
89
+ { "kind": "session_start", "startTimes": ["14:00:00"], "days": [1, 2, 3, 4, 5] }
90
+ ]
91
+ }
92
+ ]
101
93
  }
102
94
  }
103
95
  }
@@ -110,12 +102,10 @@ come together, or not at all.
110
102
 
111
103
  ```json stage_deployment_policy_draft
112
104
  {
113
- "request": {
114
- "presetId": "<PRESET_ID>",
115
- "draftVersion": 2,
116
- "axes": {
117
- "REGIME_ANCHOR": { "regimeAnchor": { "regimeReferenceCoinId": "<COIN_ID>", "regimeTimeframe": "4h" } }
118
- }
105
+ "presetId": "<PRESET_ID>",
106
+ "draftVersion": 2,
107
+ "axes": {
108
+ "REGIME_ANCHOR": { "regimeAnchor": { "regimeReferenceCoinId": "<COIN_ID>", "regimeTimeframe": "4h" } }
119
109
  }
120
110
  }
121
111
  ```
@@ -126,12 +116,10 @@ The arena's own anchor applies again.
126
116
 
127
117
  ```json stage_deployment_policy_draft
128
118
  {
129
- "request": {
130
- "presetId": "<PRESET_ID>",
131
- "draftVersion": 2,
132
- "axes": {
133
- "REGIME_ANCHOR": { "regimeAnchor": null }
134
- }
119
+ "presetId": "<PRESET_ID>",
120
+ "draftVersion": 2,
121
+ "axes": {
122
+ "REGIME_ANCHOR": { "regimeAnchor": null }
135
123
  }
136
124
  }
137
125
  ```
@@ -21,12 +21,10 @@ on this coin" with no condition named.
21
21
 
22
22
  ```json stage_radar_deployment_draft
23
23
  {
24
- "request": {
25
- "coinId": "<COIN_ID>",
26
- "draftVersion": 0,
27
- "axes": {
28
- "DEFAULT_SLOT": { "defaultSlot": { "agentId": "<AGENT_ID>", "minConviction": null } }
29
- }
24
+ "coinId": "<COIN_ID>",
25
+ "draftVersion": 0,
26
+ "axes": {
27
+ "DEFAULT_SLOT": { "defaultSlot": { "agentId": "<AGENT_ID>", "minConviction": null } }
30
28
  }
31
29
  }
32
30
  ```
@@ -38,21 +36,19 @@ regime condition is the regime-reading floor, and must be a level one of the sel
38
36
 
39
37
  ```json stage_radar_deployment_draft
40
38
  {
41
- "request": {
42
- "coinId": "<COIN_ID>",
43
- "draftVersion": 0,
44
- "axes": {
45
- "RULES": {
46
- "rules": [
47
- {
48
- "agentId": "<AGENT_ID>",
49
- "minConviction": null,
50
- "conditions": [
51
- { "kind": "regime", "regimes": ["bull_expansion", "bull_ranging"], "minConviction": "high" }
52
- ]
53
- }
54
- ]
55
- }
39
+ "coinId": "<COIN_ID>",
40
+ "draftVersion": 0,
41
+ "axes": {
42
+ "RULES": {
43
+ "rules": [
44
+ {
45
+ "agentId": "<AGENT_ID>",
46
+ "minConviction": null,
47
+ "conditions": [
48
+ { "kind": "regime", "regimes": ["bull_expansion", "bull_ranging"], "minConviction": "high" }
49
+ ]
50
+ }
51
+ ]
56
52
  }
57
53
  }
58
54
  }
@@ -64,21 +60,19 @@ Hours are UTC, 0–23. Days run 0 (Sunday) to 6. Each is listed once.
64
60
 
65
61
  ```json stage_radar_deployment_draft
66
62
  {
67
- "request": {
68
- "coinId": "<COIN_ID>",
69
- "draftVersion": 0,
70
- "axes": {
71
- "RULES": {
72
- "rules": [
73
- {
74
- "agentId": "<AGENT_ID>",
75
- "minConviction": null,
76
- "conditions": [
77
- { "kind": "hours", "hours": [13, 14, 15, 16, 17, 18, 19, 20], "days": [1, 2, 3, 4, 5] }
78
- ]
79
- }
80
- ]
81
- }
63
+ "coinId": "<COIN_ID>",
64
+ "draftVersion": 0,
65
+ "axes": {
66
+ "RULES": {
67
+ "rules": [
68
+ {
69
+ "agentId": "<AGENT_ID>",
70
+ "minConviction": null,
71
+ "conditions": [
72
+ { "kind": "hours", "hours": [13, 14, 15, 16, 17, 18, 19, 20], "days": [1, 2, 3, 4, 5] }
73
+ ]
74
+ }
75
+ ]
82
76
  }
83
77
  }
84
78
  }
@@ -88,22 +82,20 @@ Hours are UTC, 0–23. Days run 0 (Sunday) to 6. Each is listed once.
88
82
 
89
83
  ```json stage_radar_deployment_draft
90
84
  {
91
- "request": {
92
- "coinId": "<COIN_ID>",
93
- "draftVersion": 0,
94
- "axes": {
95
- "RULES": {
96
- "rules": [
97
- {
98
- "agentId": "<AGENT_ID>",
99
- "minConviction": 0.6,
100
- "conditions": [
101
- { "kind": "hours", "hours": [13, 14, 15, 16], "days": [1, 2, 3, 4, 5] },
102
- { "kind": "regime", "regimes": ["volatile"] }
103
- ]
104
- }
105
- ]
106
- }
85
+ "coinId": "<COIN_ID>",
86
+ "draftVersion": 0,
87
+ "axes": {
88
+ "RULES": {
89
+ "rules": [
90
+ {
91
+ "agentId": "<AGENT_ID>",
92
+ "minConviction": 0.6,
93
+ "conditions": [
94
+ { "kind": "hours", "hours": [13, 14, 15, 16], "days": [1, 2, 3, 4, 5] },
95
+ { "kind": "regime", "regimes": ["volatile"] }
96
+ ]
97
+ }
98
+ ]
107
99
  }
108
100
  }
109
101
  }
@@ -117,21 +109,19 @@ first agent's regimes.
117
109
 
118
110
  ```json stage_radar_deployment_draft
119
111
  {
120
- "request": {
121
- "coinId": "<COIN_ID>",
122
- "draftVersion": 0,
123
- "axes": {
124
- "RULES": {
125
- "rules": [
126
- {
127
- "agentId": "<AGENT_ID>",
128
- "minConviction": null,
129
- "conditions": [{ "kind": "regime", "regimes": ["bear_expansion", "bear_ranging"] }]
130
- }
131
- ]
132
- },
133
- "DEFAULT_SLOT": { "defaultSlot": { "agentId": "<OTHER_AGENT_ID>", "minConviction": null } }
134
- }
112
+ "coinId": "<COIN_ID>",
113
+ "draftVersion": 0,
114
+ "axes": {
115
+ "RULES": {
116
+ "rules": [
117
+ {
118
+ "agentId": "<AGENT_ID>",
119
+ "minConviction": null,
120
+ "conditions": [{ "kind": "regime", "regimes": ["bear_expansion", "bear_ranging"] }]
121
+ }
122
+ ]
123
+ },
124
+ "DEFAULT_SLOT": { "defaultSlot": { "agentId": "<OTHER_AGENT_ID>", "minConviction": null } }
135
125
  }
136
126
  }
137
127
  ```
@@ -144,12 +134,10 @@ returned.
144
134
 
145
135
  ```json stage_radar_deployment_draft
146
136
  {
147
- "request": {
148
- "coinId": "<COIN_ID>",
149
- "draftVersion": 3,
150
- "axes": {
151
- "DEFAULT_SLOT": { "defaultSlot": null }
152
- }
137
+ "coinId": "<COIN_ID>",
138
+ "draftVersion": 3,
139
+ "axes": {
140
+ "DEFAULT_SLOT": { "defaultSlot": null }
153
141
  }
154
142
  }
155
143
  ```
@@ -185,13 +185,13 @@ skill stays the authority on the flow.
185
185
 
186
186
  ### 4. Stage, and iterate on the diagnostics
187
187
 
188
- **Every change goes through the strategy's draft.** `stage_strategy_draft` takes, inside its
189
- `request`, the `strategyId`, the `draftVersion` your last read returned (0 when there was none) and
190
- the `axes` you propose. It writes those axes into the player's draft — attributed to you, landing in
191
- their builder as unsaved changes — and commits nothing. Each stage returns the draft's new
192
- `version`: that is the `draftVersion` your next stage names. Stage each change once, and never fire
193
- two stages in parallel against one draft. Complete stage payloads showing the envelope are in
194
- `references/strategy-stage-examples.md`.
188
+ **Every change goes through the strategy's draft.**
189
+ `stage_strategy_draft({ strategyId, draftVersion, axes })` takes the `strategyId`, the `draftVersion`
190
+ your last read returned (0 when there was none) and the `axes` you propose. It writes those axes into
191
+ the player's draft — attributed to you, landing in their builder as unsaved changes — and commits
192
+ nothing. Each stage returns the draft's new `version`: that is the `draftVersion` your next stage
193
+ names. Stage each change once, and never fire two stages in parallel against one draft. Complete
194
+ stage payloads are in `references/strategy-stage-examples.md`.
195
195
 
196
196
  **A new strategy is a create draft.** Omit `strategyId` and send `draftVersion: 0` on the first
197
197
  stage; the response carries the id minted for it, which every later call names. A create needs
@@ -1,10 +1,11 @@
1
1
  # Strategy stage examples
2
2
 
3
- `strategyId` and `draftVersion` sit beside `axes`, inside `request` — never inside `axes`. Every example below is
4
- checked in CI against the live `stage_strategy_draft` schema; a create example is also checked for the axes a new
5
- strategy needs. Its shape is current.
3
+ Each example is the tool's whole input: `strategyId` and `draftVersion` sit at the top level beside `axes`, never
4
+ inside `axes`. Every example below is checked in CI against the live
5
+ `stage_strategy_draft` schema; a create example is also checked for the axes a new strategy needs. Its shape is
6
+ current.
6
7
 
7
- These examples show the envelope and the small axes. A full composition (report sections, conditions, trade
8
+ These examples show the input's shape and the small axes. A full composition (report sections, conditions, trade
8
9
  levels) is in `strategy-examples`' playbooks, which have their own compile gate.
9
10
 
10
11
  Every `<UPPER_SNAKE>` value is a placeholder: `<STRATEGY_ID>` is the id a read returned. Never send a placeholder as
@@ -19,16 +20,14 @@ and TIMEFRAME_PROFILE before it can be created.
19
20
 
20
21
  ```json stage_strategy_draft
21
22
  {
22
- "request": {
23
- "draftVersion": 0,
24
- "axes": {
25
- "IDENTITY": {
26
- "name": "Squeeze Breakout",
27
- "description": "Enters when a volatility squeeze resolves upward on rising volume.",
28
- "tagline": "Buys the release of a tight range"
29
- },
30
- "TIMEFRAME_PROFILE": { "timeframe": "1h" }
31
- }
23
+ "draftVersion": 0,
24
+ "axes": {
25
+ "IDENTITY": {
26
+ "name": "Squeeze Breakout",
27
+ "description": "Enters when a volatility squeeze resolves upward on rising volume.",
28
+ "tagline": "Buys the release of a tight range"
29
+ },
30
+ "TIMEFRAME_PROFILE": { "timeframe": "1h" }
32
31
  }
33
32
  }
34
33
  ```
@@ -40,16 +39,14 @@ a coin must clear before any condition is read; the other three are the stop-los
40
39
 
41
40
  ```json stage_strategy_draft
42
41
  {
43
- "request": {
44
- "strategyId": "<STRATEGY_ID>",
45
- "draftVersion": 2,
46
- "axes": {
47
- "TRADE_LEVEL_POLICY": {
48
- "minStopLossAtrMultiple": 1,
49
- "maxStopLossAtrMultiple": 2,
50
- "minRiskRewardRatio": 1.5,
51
- "minAtrPct": 0.8
52
- }
42
+ "strategyId": "<STRATEGY_ID>",
43
+ "draftVersion": 2,
44
+ "axes": {
45
+ "TRADE_LEVEL_POLICY": {
46
+ "minStopLossAtrMultiple": 1,
47
+ "maxStopLossAtrMultiple": 2,
48
+ "minRiskRewardRatio": 1.5,
49
+ "minAtrPct": 0.8
53
50
  }
54
51
  }
55
52
  }