@battlegrid/mcp-server 31.2.74 → 31.2.76
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 +37 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/EXPORT.json +10 -10
- package/skills/battlegrid-agent-management/SKILL.md +10 -2
- package/skills/battlegrid-arena-play/SKILL.md +11 -4
- package/skills/battlegrid-market-analysis/SKILL.md +9 -4
- package/skills/battlegrid-radar-deployment/SKILL.md +74 -41
- package/skills/battlegrid-strategy-authoring/SKILL.md +22 -8
- package/skills/battlegrid-strategy-examples/SKILL.md +5 -5
- package/skills/battlegrid-strategy-examples/references/playbooks.md +6 -6
- package/skills/battlegrid-trade-analysis/SKILL.md +19 -4
- package/skills/battlegrid-trade-proposal/SKILL.md +4 -0
package/README.md
CHANGED
|
@@ -24,6 +24,38 @@ 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 — v93 (every value you read names the bar it came from)
|
|
28
|
+
|
|
29
|
+
**Breaking at v93: a timeless metric refuses an `offset`, and a value with no reading on its bar reads absent
|
|
30
|
+
instead of an older bar's.** v93 is the contract on top of v92. A column reads the bar it names, or nothing.
|
|
31
|
+
|
|
32
|
+
### Rejected input — something you send is no longer accepted
|
|
33
|
+
|
|
34
|
+
- A `value` column over a timeless metric — one `get_strategy_column_contract` serves with `timeframeMode`
|
|
35
|
+
`"timeless"`: funding, the regime, the previous-session levels and the other bundle reads — with `offset` above
|
|
36
|
+
`0` is refused at construction (`VALIDATION_ERROR`, authoring code `REPORT_COLUMN_CONSTRUCTION_FAILED`) by every
|
|
37
|
+
tool that builds a report column, the strategy and agent draft tools and `preview_strategy_report` among them. It
|
|
38
|
+
used to be accepted and ignored. Drop the offset: a timeless metric has no earlier bar.
|
|
39
|
+
|
|
40
|
+
### Changed values — the same fields, read at a named bar
|
|
41
|
+
|
|
42
|
+
- A **trajectory**, **zone**, **state** or **cross** value whose current bar holds no reading is now absent,
|
|
43
|
+
instead of the newest older bar's value. A trajectory's slots keep a missing bar as an empty slot, in place.
|
|
44
|
+
- A window — a trajectory's, `efficiency`'s, `maxShare`'s — counts the newest bars, present or not; a window of
|
|
45
|
+
one bar has no trend (it read `flat`).
|
|
46
|
+
- A candle **label** column at `offset N` reads bar t−N's label; it used to read the latest.
|
|
47
|
+
- On a decided bar, a condition over a **published change** (`chg5m` … `chg24h`) or **`oiRegime`** reads
|
|
48
|
+
unresolved, and a condition over a **higher-timeframe column** reads unresolved during that bar's close lag.
|
|
49
|
+
|
|
50
|
+
### Behaviour behind unchanged schemas
|
|
51
|
+
|
|
52
|
+
- An Arena deployment that routes on the regime reads **`WARMING`** while its regime bar is landing — the regime
|
|
53
|
+
for the bar the clock just closed is not published yet — and plays nothing, its default slot included. Generating,
|
|
54
|
+
submitting or updating a grid for an agent on such a deployment is refused with `SERVICE_UNAVAILABLE` in those
|
|
55
|
+
seconds; retry.
|
|
56
|
+
|
|
57
|
+
Something read at v92 reads absent at v93, and an input v92 accepted is refused — hence the MAJOR.
|
|
58
|
+
|
|
27
59
|
## Contract history — v92 (every section you read is the JSON the agent reads)
|
|
28
60
|
|
|
29
61
|
**Breaking at v92: the section fields are reshaped, the report preview's default narrows, and its size is measured
|
|
@@ -2912,6 +2944,11 @@ you reach over MCP:
|
|
|
2912
2944
|
> request; `skills/EXPORT.json` records a hash per file and `src/__tests__/skill-provenance.test.ts`
|
|
2913
2945
|
> fails CI on a hand edit. Change the skill upstream and let the export lane bring it here.
|
|
2914
2946
|
|
|
2947
|
+
A client connected to BattleGrid's remote server directly receives its `initialize` instructions:
|
|
2948
|
+
the rules that span tools and one routing card per workflow, each naming the `battlegrid-*` skill
|
|
2949
|
+
above that holds the full procedure. This proxy does not relay those instructions; the skills
|
|
2950
|
+
installed beside it carry the same workflows.
|
|
2951
|
+
|
|
2915
2952
|
## License
|
|
2916
2953
|
|
|
2917
2954
|
[MIT](LICENSE)
|
package/dist/index.d.ts
CHANGED
|
@@ -49,7 +49,7 @@ import { type Implementation, type Prompt, type Resource } from '@modelcontextpr
|
|
|
49
49
|
* being asked. Move it for a change to THIS package — a proxy fix, a dependency bump, a docs
|
|
50
50
|
* correction. Never move it to track the server.
|
|
51
51
|
*/
|
|
52
|
-
export declare const PACKAGE_VERSION = "31.2.
|
|
52
|
+
export declare const PACKAGE_VERSION = "31.2.76";
|
|
53
53
|
export declare const DEFAULT_URL = "https://mcp.battlegrid.trade/mcp";
|
|
54
54
|
export interface EnvConfig {
|
|
55
55
|
apiKeys: string[];
|
package/dist/index.js
CHANGED
|
@@ -52,7 +52,7 @@ import { ListToolsRequestSchema, CallToolRequestSchema, ListPromptsRequestSchema
|
|
|
52
52
|
* being asked. Move it for a change to THIS package — a proxy fix, a dependency bump, a docs
|
|
53
53
|
* correction. Never move it to track the server.
|
|
54
54
|
*/
|
|
55
|
-
export const PACKAGE_VERSION = '31.2.
|
|
55
|
+
export const PACKAGE_VERSION = '31.2.76';
|
|
56
56
|
export const DEFAULT_URL = 'https://mcp.battlegrid.trade/mcp';
|
|
57
57
|
const MAX_RETRIES = 3;
|
|
58
58
|
const RETRY_DELAYS_MS = [2000, 4000, 8000];
|
package/package.json
CHANGED
package/skills/EXPORT.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"generator": "battlegrid-app/server/scripts/export-mcp-skills.mjs",
|
|
3
|
-
"contractVersion": "
|
|
3
|
+
"contractVersion": "92.0.0",
|
|
4
4
|
"files": {
|
|
5
|
-
"battlegrid-agent-management/SKILL.md": "
|
|
6
|
-
"battlegrid-arena-play/SKILL.md": "
|
|
7
|
-
"battlegrid-market-analysis/SKILL.md": "
|
|
8
|
-
"battlegrid-radar-deployment/SKILL.md": "
|
|
9
|
-
"battlegrid-strategy-authoring/SKILL.md": "
|
|
5
|
+
"battlegrid-agent-management/SKILL.md": "e5ffab64e6a369d5c783aed2b1c7c513b01b870063fd859c9cc4d9fc45d30aac",
|
|
6
|
+
"battlegrid-arena-play/SKILL.md": "01b2192c19b93b2315ff1a2b512ee0bcb7fd809c7d77fbbd93307fe2f45924a3",
|
|
7
|
+
"battlegrid-market-analysis/SKILL.md": "875bda71dd766ad06ac8e508679bcd3400a600cf74d2eac6c922dbe23175f325",
|
|
8
|
+
"battlegrid-radar-deployment/SKILL.md": "aaa4d13d32d470582d4bab0dc71594d4adf6b665bf45ee3384ee794dd8f82ba4",
|
|
9
|
+
"battlegrid-strategy-authoring/SKILL.md": "d4c5c87d9306193be8be77b1ade4938bbbc8805d66bc5267c00c2a8db156a92e",
|
|
10
10
|
"battlegrid-strategy-doctor/SKILL.md": "14f20bff9e2b5a59d11634fe3615b1298d672d5e2eba06d3dc8698b571b3bee3",
|
|
11
|
-
"battlegrid-strategy-examples/SKILL.md": "
|
|
12
|
-
"battlegrid-strategy-examples/references/playbooks.md": "
|
|
11
|
+
"battlegrid-strategy-examples/SKILL.md": "d49ed36a864d1ead53c942979639d331b2bf375b50fffd745548a0acde39d641",
|
|
12
|
+
"battlegrid-strategy-examples/references/playbooks.md": "9e89b5cc8d80fc27bc331862fdc2403c26b36131b132614782c8425df74bcd28",
|
|
13
13
|
"battlegrid-strategy-examples/references/recipes.md": "61382acdd295fa159f055b787ba501f1c015f383f59a6714a973057f10de611f",
|
|
14
14
|
"battlegrid-strategy-examples/references/tradingview-ports.md": "2b13adbc137178955edcca31b6ab40c01c745a932a0750b91db8820c736700bb",
|
|
15
|
-
"battlegrid-trade-analysis/SKILL.md": "
|
|
16
|
-
"battlegrid-trade-proposal/SKILL.md": "
|
|
15
|
+
"battlegrid-trade-analysis/SKILL.md": "a1e666ca03bd641413096ed14806f101354f4e913e005faad6026a486143af0c",
|
|
16
|
+
"battlegrid-trade-proposal/SKILL.md": "d207a30065c17e13efaf5391805e5603e6956633cba5d0a1ff60e276518d9696"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -84,7 +84,8 @@ omit `agentId` and send `draftVersion: 0` on the first call, then reuse the id i
|
|
|
84
84
|
`{ strategyId }`, all four required to create, plus TRADING_CONFIG with every agent-owned field —
|
|
85
85
|
or no TRADING_CONFIG at all, to take the platform seed. The build then survives a refresh, lists in
|
|
86
86
|
the Agents Hub as *not yet created*, and opens on the create screen, where **the player's own
|
|
87
|
-
Create creates it**. Staging creates nothing and spends no slot.
|
|
87
|
+
Create creates it**. Staging creates nothing and spends no slot. The avatar is minted by the server
|
|
88
|
+
at creation — there is no avatar to stage.
|
|
88
89
|
|
|
89
90
|
**Then read it, confirm it, and commit it.** `get_agent_draft` serves the draft, its
|
|
90
91
|
`draftVersion`, a `committedRevision` of `null` and the diagnostics: a missing or invalid axis is
|
|
@@ -110,6 +111,11 @@ Profile → Wallet tab path instead, because no control renders there. **Create
|
|
|
110
111
|
way**: the consent gates entering a game, never commissioning one. A `true` flag is consent alone
|
|
111
112
|
and not readiness — the pipeline's own refusal at the fee is the authority.
|
|
112
113
|
|
|
114
|
+
**When the mandate is trading, the agent needs a trading wallet.** `get_account_state` reports
|
|
115
|
+
`tradingWalletProvisioned`; the wallet is provisioned in the web app, where its key is signed
|
|
116
|
+
locally in the browser, and no tool provisions it. Without one the agent can be created but cannot
|
|
117
|
+
place an order — say so with the create, never after the first refused trade.
|
|
118
|
+
|
|
113
119
|
### 3. Stage, read, confirm, commit — every change goes through the draft
|
|
114
120
|
|
|
115
121
|
Before proposing any change to an existing agent, `get_agent_draft`. **A draft means the player is
|
|
@@ -242,7 +248,9 @@ keys). The commit holds the configuration to the same risk rules the agent form'
|
|
|
242
248
|
the P&L. It carries a schema-level `confirm: true`, so present the position, its unrealized
|
|
243
249
|
P&L and its protections, and confirm before calling. An exchange rejection comes back as a typed
|
|
244
250
|
trading error — report it; a success means the close order was *accepted*.
|
|
245
|
-
- **`override_agent_protection`** moves the effective stop
|
|
251
|
+
- **`override_agent_protection`** moves the effective stop — the stop-loss only; take-profit is not
|
|
252
|
+
overridable here. It names the stop it replaces by `effectiveStopLossOrderId`, which
|
|
253
|
+
`get_position_audit_history` serves. Its confirm must say, in words, that
|
|
246
254
|
the change **moves the stop outside the platform's protective ratchet** — that is exactly what
|
|
247
255
|
the tool is for — and name the direction: whether the new level sits further from or closer to
|
|
248
256
|
price than the one the platform is holding. Present the current protection first, then the
|
|
@@ -59,7 +59,11 @@ the enablement path there.
|
|
|
59
59
|
A direct submission carries `grid`, `reasoning`, `confidenceScore`, `modelName` and
|
|
60
60
|
`pickReasoning`, and all of them are required.
|
|
61
61
|
|
|
62
|
-
- **Exactly one cell is captain
|
|
62
|
+
- **Exactly one cell is captain.** The session's preset sets what that is worth: a correct captain's
|
|
63
|
+
points are multiplied by its `captainMultiplier`, and a wrong captain's penalty by its
|
|
64
|
+
`captainWrongPenaltyMultiplier` — both published by `list_game_presets`, and different per preset.
|
|
65
|
+
Read them rather than assuming a number, and captain the pick you are most confident in among
|
|
66
|
+
those with a move worth amplifying.
|
|
63
67
|
- **`pickReasoning` carries one entry per grid cell — every cell, no coin twice.** Compose it
|
|
64
68
|
correctly because it is yours to compose, not because something downstream will catch it: the
|
|
65
69
|
boundary refuses an incomplete payload before the fee moves, and leaning on that check means
|
|
@@ -98,12 +102,15 @@ reasoning as the player's, and the attribution is part of what was scored.
|
|
|
98
102
|
|
|
99
103
|
### 5. After settlement
|
|
100
104
|
|
|
105
|
+
- A session moves PENDING → LIVE → RESOLVING → SETTLED. Two states sit off that path: CANCELLED
|
|
106
|
+
(entry fees refunded) and SETTLEMENT_QUARANTINED (settlement exhausted its retries and awaits an
|
|
107
|
+
operator). Either one is the answer — report it as the status.
|
|
101
108
|
- `get_market_grid_results` — available only once the session is SETTLED. Before that it returns a
|
|
102
109
|
typed CONFLICT naming the current status: **report it and stop**. Do not poll it in a loop; the
|
|
103
110
|
op budget is finite and a settling session is not a failure.
|
|
104
|
-
- `get_mcp_reasoning_journal` on request — the
|
|
105
|
-
submit. Compare the outcome against what was actually reasoned, and say
|
|
106
|
-
wrong.
|
|
111
|
+
- `get_mcp_reasoning_journal` on request — the player's own submission: the reasoning, confidence
|
|
112
|
+
and picks as recorded at submit. Compare the outcome against what was actually reasoned, and say
|
|
113
|
+
where the reasoning was wrong. An agent's record is a different journal, `get_agent_journal`.
|
|
107
114
|
|
|
108
115
|
## Refusals, and what each one means
|
|
109
116
|
|
|
@@ -20,7 +20,10 @@ Run these in order. Skip a step only when the player's question makes it irrelev
|
|
|
20
20
|
|
|
21
21
|
1. **Regime.** `get_regime_snapshot` for the current read. `get_regime_history` when the player
|
|
22
22
|
asks how we got here, or when the snapshot alone would hide a fresh flip — a regime that
|
|
23
|
-
turned in the last few periods is a different fact from one that has held for weeks.
|
|
23
|
+
turned in the last few periods is a different fact from one that has held for weeks. Read the
|
|
24
|
+
snapshot's evidence before its label: a label the hysteresis buffer is **holding** is the
|
|
25
|
+
previous bar's, not this bar's, and conviction names which rule matched, not how comfortably —
|
|
26
|
+
the margins to each gate say how close the read is to turning.
|
|
24
27
|
2. **Market context.** `get_market_context` — this carries the breadth, funding and open-interest
|
|
25
28
|
picture. Funding and OI are the two figures most often skipped and most often decisive: crowded
|
|
26
29
|
positioning is the difference between "trend" and "trend about to be squeezed". Report both.
|
|
@@ -28,9 +31,11 @@ Run these in order. Skip a step only when the player's question makes it irrelev
|
|
|
28
31
|
"strength in majors". A laggard list is as informative as a leader list and is usually omitted.
|
|
29
32
|
3b. **Many coins on the same indicators — one call, not one per coin.** When the answer needs the
|
|
30
33
|
indicator modules ACROSS a set of coins (comparing RSI, funding or volatility over the leaders,
|
|
31
|
-
over a category, over the session pool), use `preview_strategy_report`: one
|
|
32
|
-
coins as rows,
|
|
33
|
-
|
|
34
|
+
over a category, over the session pool), use `preview_strategy_report`: one section JSON per
|
|
35
|
+
module with coins as rows, each column described once instead of per coin, and the exact size of
|
|
36
|
+
the response it served (`budgetUsage.resultChars`). The default `detail: "concise"` is the read;
|
|
37
|
+
`"detailed"` adds only the authoring contract a strategy builder needs. Ask
|
|
38
|
+
`list_strategy_categories` for the section catalogue and pass the sections you want,
|
|
34
39
|
each as `{ "kind": "platform", "sectionKey": "includeRsi" }`, inside
|
|
35
40
|
`source: { "kind": "FIELDS", "timeframe": …, "sections": [ … ] }` — no authoring vocabulary is
|
|
36
41
|
needed. Use `{ "mode": "ranked", "limit": N }` as the coin selection when you have no explicit
|
|
@@ -16,6 +16,11 @@ Radar (per coin) and Arena deployment (per preset) are **separate bounded contex
|
|
|
16
16
|
no slot shape, no condition union and no resolution type. Never carry a fact from one to the other,
|
|
17
17
|
and never describe them as one thing with two modes.
|
|
18
18
|
|
|
19
|
+
**Deployments are the autonomous trading switches.** An agent has no trading mode of its own: it
|
|
20
|
+
trades a coin on its own only where a Radar policy puts it on duty, and a proposal the player
|
|
21
|
+
approves needs no deployment. An Arena deployment enters an agent into a preset's sessions and grants
|
|
22
|
+
**no** trade permission — to have an agent trade a coin on its own, deploy it on Radar.
|
|
23
|
+
|
|
19
24
|
## The five failures this flow exists to prevent
|
|
20
25
|
|
|
21
26
|
1. **A write with no fresh preview.** *Cue: any `commit_radar_deployment_draft`,
|
|
@@ -69,6 +74,19 @@ Then read what exists:
|
|
|
69
74
|
If the question is *why did my radar agent not fire*, do not start from the journal — **go to step
|
|
70
75
|
5**, which reads state first and pattern second.
|
|
71
76
|
|
|
77
|
+
**In a conversation the radar builder hosts** — your context names the radar builder and a coin id —
|
|
78
|
+
the player's builder is open on that coin whether or not a draft exists yet. Stage every change into
|
|
79
|
+
that coin's draft, naming that `coinId`; it lands in their builder as a proposal. Their own Save
|
|
80
|
+
commits it; commit it yourself only when they explicitly confirm through `ask_user`, after the
|
|
81
|
+
preview this flow requires. The builder's state — its rules, the default agent, who is on duty now —
|
|
82
|
+
arrives as the turn's attached scope. An axis their form rewrote after your proposal is their answer:
|
|
83
|
+
propose it again only on their word.
|
|
84
|
+
|
|
85
|
+
**In a conversation the Arena deploy editor hosts** — your context names the Arena deploy editor and a
|
|
86
|
+
preset id — the same, for that arena's deployment draft, naming that `presetId`. Its scope carries the
|
|
87
|
+
rules, the default agent and what the next session resolves to, marked `simulated` while the player
|
|
88
|
+
is test-routing a regime. Never carry a fact from a radar conversation into it, or the reverse.
|
|
89
|
+
|
|
72
90
|
### 2. Stage the change, then preview exactly what would be written
|
|
73
91
|
|
|
74
92
|
**Radar** — the change goes into the player's draft of the coin, never straight to the policy:
|
|
@@ -82,11 +100,18 @@ If the question is *why did my radar agent not fire*, do not start from the jour
|
|
|
82
100
|
`agentRegimeTimeframe`. Staging writes nothing live and shows the change in the player's builder as
|
|
83
101
|
a proposal. A refusal naming axes means the player changed them after your read: read again and
|
|
84
102
|
propose against what they now have.
|
|
85
|
-
2. `
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
103
|
+
2. `get_radar_deployment_draft` — the draft as it now stands: its `draftVersion`, the
|
|
104
|
+
`committedRevision` it would be published over (null for a coin with no policy yet), the diff
|
|
105
|
+
against the deployed policy, the `diagnostics` a commit would refuse, and the `impact` — who goes
|
|
106
|
+
on duty, whether it trades once committed, and for a first deployment the coin cap
|
|
107
|
+
(`admission.coinCapReached` true means the commit will be refused until a coin is un-deployed).
|
|
108
|
+
Do not confirm a draft whose diagnostics carry an error: stage a fix.
|
|
109
|
+
3. `preview_radar_resolution` with `request: { kind: "DRAFT", draftVersion }` at the version that read
|
|
110
|
+
returned. It composes the draft over the deployed policy **exactly as the commit will write it**,
|
|
111
|
+
and refuses a draft no longer at that version with `DRAFT_VERSION_MOVED`.
|
|
112
|
+
|
|
113
|
+
To try a slot set without touching the draft, preview `{ kind: "SLOTS", slots }` — it resolves
|
|
114
|
+
explicit slots and nothing can commit it.
|
|
90
115
|
|
|
91
116
|
**Arena** — the same shape, keyed on `presetId`:
|
|
92
117
|
|
|
@@ -94,8 +119,10 @@ nothing and cannot be committed.
|
|
|
94
119
|
draft) and only the axes you are changing, each WHOLE: `RULES` (the complete ordered rule list —
|
|
95
120
|
first is highest priority; a rule's regime condition names a set), `DEFAULT_SLOT` (the catch-all, or null for none)
|
|
96
121
|
and `REGIME_ANCHOR` (the anchor override, or null to inherit the arena's). Pausing is never staged.
|
|
97
|
-
2. `
|
|
98
|
-
|
|
122
|
+
2. `get_deployment_policy_draft` — its `draftVersion`, `committedRevision`, diff, `diagnostics` and
|
|
123
|
+
`impact` (the next session's resolution and whether it will play), exactly as for Radar.
|
|
124
|
+
3. `preview_deployment_resolution` with `request: { kind: "DRAFT", draftVersion }` at the version
|
|
125
|
+
that read returned.
|
|
99
126
|
|
|
100
127
|
A draft that would hold no rule and no catch-all is a withdrawal, which a commit never does — that is
|
|
101
128
|
`delete_deployment_policy` (step 4).
|
|
@@ -110,7 +137,8 @@ and priority that put it on duty, its regime reading at its own `regimeTimeframe
|
|
|
110
137
|
qualification verdict and its close clock — and `readings`, one entry per on-duty agent in the same
|
|
111
138
|
order: what that agent reads on the coin right now (below). For **Arena**: which agent goes on duty,
|
|
112
139
|
which slot matched and at what priority, the regime and conviction used, and the qualification
|
|
113
|
-
verdict
|
|
140
|
+
verdict, under the resolution's `status` as served — RESOLVED (an agent plays the next session),
|
|
141
|
+
IDLE (the rules ran and none matched), WARMING, NO_SESSION or PAUSED. **Render `section` as the server sends it — never re-derive it, and never pick, rank or drop
|
|
114
142
|
rows yourself.** A non-null reason does not mean idle (`ON_DUTY_BUT_POSITION_BLOCKED` carries a reason
|
|
115
143
|
and is not idle), so deciding the headline yourself gets it wrong. `enabledAfterCommit` says whether
|
|
116
144
|
the policy will play once committed — a paused policy stays paused, and a first Arena deployment
|
|
@@ -123,8 +151,8 @@ resolve.
|
|
|
123
151
|
**A Radar preview refuses an agent the scan cannot read on the coin.** Every slot agent, on duty now
|
|
124
152
|
or not, must have every condition the radar acts on — its required conditions, the ones carrying a
|
|
125
153
|
verdict, its exit rules, and every condition they reference — readable by the radar scan on this
|
|
126
|
-
coin. When one is not, the preview itself is refused,
|
|
127
|
-
|
|
154
|
+
coin. When one is not, the preview itself is refused, and the draft read reports the same refusal in
|
|
155
|
+
its diagnostics: `CONDITION_UNREADABLE_BY_RADAR_SCAN`, whose `details.context.reachReason` says why
|
|
128
156
|
(`INSTRUMENT` — the market-data profile of the coin, or of a benchmark section's own instrument, carries
|
|
129
157
|
no such data, or the market-data service publishes no profile for it at all: the refusal names the kind
|
|
130
158
|
of data the profile lacks, or says there is none; `AGENT_TIMEFRAME` — the agent has no such rung;
|
|
@@ -175,28 +203,32 @@ the reason — and **names what the change does to the stored policy**, read fro
|
|
|
175
203
|
|
|
176
204
|
Then:
|
|
177
205
|
|
|
178
|
-
- **Radar** → `commit_radar_deployment_draft({ coinId,
|
|
179
|
-
`
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
206
|
+
- **Radar** → `commit_radar_deployment_draft({ request: { coinId, draftVersion, expectedRevision } })`,
|
|
207
|
+
naming exactly the `draftVersion` and `committedRevision` your draft read returned — the version
|
|
208
|
+
your preview resolved. Ask with `ask_user` first and commit only after an explicit confirming pick.
|
|
209
|
+
The axes it published leave the draft.
|
|
210
|
+
- **Arena** → `commit_deployment_policy_draft({ request: { presetId, draftVersion, expectedRevision } })`,
|
|
211
|
+
the same way.
|
|
183
212
|
|
|
184
|
-
**On a
|
|
185
|
-
the
|
|
186
|
-
stale. A
|
|
187
|
-
|
|
213
|
+
**On `DRAFT_VERSION_MOVED` or a CONFLICT: re-read, re-preview, re-confirm.** In that order, and all
|
|
214
|
+
three. The draft or the deployment changed under you, so the state your preview resolved and the
|
|
215
|
+
radius you stated are both stale. A retry with a bumped number commits something the player was not
|
|
216
|
+
shown — the server refuses a version or revision you did not read, and the confirmation is yours to
|
|
217
|
+
ask for again.
|
|
188
218
|
|
|
189
219
|
### 4. Pause, resume, discard, delete
|
|
190
220
|
|
|
191
221
|
**Pause a coin's Radar** → `pause_radar_deployment({ coinId })`. No preview and no revision: stopping
|
|
192
|
-
never waits on a read. The player's draft
|
|
193
|
-
`request: { kind: "COMMITTED" }`, tell the player which
|
|
194
|
-
|
|
195
|
-
|
|
222
|
+
never waits on a read. The player's draft keeps its content and is re-based onto the paused revision.
|
|
223
|
+
**Resume** → preview the deployed policy with `request: { kind: "COMMITTED" }`, tell the player which
|
|
224
|
+
agents will go on duty again, and on their word
|
|
225
|
+
`resume_radar_deployment({ coinId, expectedPolicyId, expectedRevision })` naming the `policyId` and
|
|
226
|
+
`revision` that preview returned — so it re-arms the policy the player was shown, or nothing.
|
|
196
227
|
|
|
197
228
|
**Pause an arena** → `pause_deployment_policy({ presetId })`, and **resume** it the Radar way: preview
|
|
198
|
-
`{ kind: "COMMITTED" }`, then `resume_deployment_policy({ presetId,
|
|
199
|
-
the player's word. Both touch only the pause, never the rules
|
|
229
|
+
`{ kind: "COMMITTED" }`, then `resume_deployment_policy({ presetId, expectedPolicyId, expectedRevision })`
|
|
230
|
+
with the pair it returned, on the player's word. Both touch only the pause, never the rules; the
|
|
231
|
+
player's draft keeps its content.
|
|
200
232
|
|
|
201
233
|
**Entries already made stand.** A pause or a delete of an arena returns `openEntries` — the sessions
|
|
202
234
|
the player's agent already entered that have not locked, each with its lock time and entry fee. They
|
|
@@ -204,21 +236,23 @@ play out unless the player cancels them. Name each one, ask whether to cancel it
|
|
|
204
236
|
`cancel_market_grid_submission({ sessionId, confirm: true })` only for the entries they pick — the
|
|
205
237
|
same cancellation and refund as their own Cancel button. Say nothing is cancelled when they decline.
|
|
206
238
|
|
|
207
|
-
**Discard a draft** only on the player's word.
|
|
208
|
-
|
|
209
|
-
`
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
239
|
+
**Discard a draft** only on the player's word. Read it first and tell the player what it holds and
|
|
240
|
+
when and from where it was last written; then
|
|
241
|
+
`discard_radar_deployment_draft({ request: { coinId, draftVersion } })` or
|
|
242
|
+
`discard_deployment_policy_draft({ request: { presetId, draftVersion } })` at **the version you read**.
|
|
243
|
+
If the draft moved since, it is refused with `DRAFT_VERSION_MOVED` and nothing is removed — read it
|
|
244
|
+
again and show them.
|
|
213
245
|
|
|
214
246
|
**Deletes** — `delete_radar_deployment` / `delete_deployment_policy` remove the **entire** policy —
|
|
215
247
|
every slot and condition — and revoke the standing authority. Un-deploying **also ends the player's
|
|
216
248
|
draft** of the coin or the arena. There is no preview here, and correctly so: there is no resolution
|
|
217
249
|
to preview once the policy is gone. The evidence is **the deployment's own read**, which supplies the
|
|
218
|
-
`expectedRevision`
|
|
250
|
+
`expectedPolicyId` and `expectedRevision` both deletes carry — a policy removed and redeployed since
|
|
251
|
+
your read is refused rather than removed.
|
|
219
252
|
|
|
220
253
|
State what stops, from that read: which agents were on duty (every row of `resolvesNow.onDuty`) or
|
|
221
|
-
eligible, what the policy was firing on, and that the slots are not recoverable
|
|
254
|
+
eligible, what the policy was firing on, and that the slots are not recoverable — and delete only after
|
|
255
|
+
an explicit confirming pick.
|
|
222
256
|
|
|
223
257
|
**If the player wants to stop trading without losing the slots, that is not a delete** — it is
|
|
224
258
|
`pause_radar_deployment` for Radar and `pause_deployment_policy` for Arena. Offer that
|
|
@@ -306,15 +340,14 @@ Three negatives, all checkable:
|
|
|
306
340
|
last decision a row names, `get_radar_close_decisions` for any other — and quote it as stored;
|
|
307
341
|
never recompute it.
|
|
308
342
|
|
|
309
|
-
## Preview-before-commit:
|
|
343
|
+
## Preview-before-commit: your discipline, fenced by the server
|
|
310
344
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
refused by the server — but the player's confirmation is still yours to ask for, against the preview.
|
|
345
|
+
The preview card and the confirming pick are yours to show and ask for, every time. What the server
|
|
346
|
+
enforces is the fence under them: a commit names the draft version and committed revision its read
|
|
347
|
+
returned, and a resume or a delete names the deployment and revision it read. A draft that moved after
|
|
348
|
+
your preview is refused with `DRAFT_VERSION_MOVED`; a deployment whose revision moved, or that was
|
|
349
|
+
withdrawn and redeployed, is refused as a CONFLICT. So a commit never publishes a draft version your
|
|
350
|
+
preview did not resolve — provided you previewed the version you commit.
|
|
318
351
|
|
|
319
352
|
## When a write's outcome is unknown
|
|
320
353
|
|
|
@@ -104,7 +104,9 @@ anywhere; if the two ever disagree, you have created the exact ambiguity this st
|
|
|
104
104
|
`get_strategy_signal_definition` for each signal you intend to use.
|
|
105
105
|
|
|
106
106
|
Compose sections, columns, conditions and rules **only** from vocabulary returned in this
|
|
107
|
-
conversation. A field you remember from another strategy is not discovery.
|
|
107
|
+
conversation. A field you remember from another strategy is not discovery. A signal's availability
|
|
108
|
+
at a timeframe is structural: it says the signal can be computed there, not that live data is
|
|
109
|
+
flowing or that it will trigger.
|
|
108
110
|
|
|
109
111
|
**Read the answer, not just the call.** Each of these returns one field that decides a composition
|
|
110
112
|
question you would otherwise guess — and a refusal you would otherwise earn:
|
|
@@ -144,7 +146,8 @@ teaches what to compose; this skill stays the authority on the flow.
|
|
|
144
146
|
|
|
145
147
|
`derive_strategy_rule_view` belongs here, at composition time, and only here: it reports report
|
|
146
148
|
membership and registry-default allocations for sections and rows you are about to stage. It reads
|
|
147
|
-
no draft and no strategy, so it can never stand in for the review in step 5.
|
|
149
|
+
no draft and no strategy, so it can never stand in for the review in step 5. Its suggestions and
|
|
150
|
+
reset-to-default choices change only what you stage next — no tool applies one on its own.
|
|
148
151
|
|
|
149
152
|
`simulate_aggregate_score` does **not** belong here. It is a review tool (step 5), and running it
|
|
150
153
|
now answers a question about rows you have not staged, not about the draft the player will be
|
|
@@ -224,7 +227,13 @@ Once the stage's diagnostics carry nothing you cannot explain, read the draft wi
|
|
|
224
227
|
the commit's own: the player is approving all of it, not only what you proposed.
|
|
225
228
|
- **Whether it can fire.** `preview_strategy_report` with
|
|
226
229
|
`source: { "kind": "DRAFT", strategyId, draftVersion }`, at the version the read returned,
|
|
227
|
-
renders the draft against live market composed exactly as its commit would compose it.
|
|
230
|
+
renders the draft against live market composed exactly as its commit would compose it. Its default
|
|
231
|
+
`detail: "concise"` is exactly what the agent will read — the sections, each surface's conditions
|
|
232
|
+
register with every coin's verdict, and the verdict tally; ask for `"detailed"` only when you need
|
|
233
|
+
each coin's full evaluation or the addressable headers (`authoring`). A preview is bounded by a
|
|
234
|
+
deadline and a result-character cap, both served by discovery as `previewExecutionLimits`
|
|
235
|
+
(`deadlineMs`, `maxResultChars`); one over either is refused whole, never truncated — narrow the
|
|
236
|
+
cohort and preview again. Support it
|
|
228
237
|
with `get_coin_signal_preview` on the locked universe's main coin(s). The preview's
|
|
229
238
|
`coinSelection` is its cohort, never strategy state: no strategy has one and `get_strategy` will
|
|
230
239
|
not return one, so choose it — a short explicit list of the tickers the change is about for a
|
|
@@ -246,8 +255,9 @@ revise rather than presenting it as healthy.
|
|
|
246
255
|
- `operation` — CREATE, UPDATE or RESTORE. A RESTORE is a draft over an archived strategy: say
|
|
247
256
|
that committing it also restores the strategy and moves its bound agents, by count, from
|
|
248
257
|
ORPHANED to BOUND.
|
|
249
|
-
- `boundAgentCount`, `openPositionCount` and `timeframeChanged`. A change
|
|
250
|
-
|
|
258
|
+
- `boundAgentCount`, `openPositionCount` and `timeframeChanged`. A committed change reaches every
|
|
259
|
+
bound agent the moment it commits, while a position already open keeps the exit rules it opened
|
|
260
|
+
under — say so.
|
|
251
261
|
- `admission` — for a create draft or an archived strategy, the quota and whether the name is
|
|
252
262
|
free. It is advisory: the commit decides.
|
|
253
263
|
- `capital` — each bound agent the drafted stop band would leave unable to place an order, with its
|
|
@@ -319,9 +329,13 @@ verbs writes content.
|
|
|
319
329
|
commit does, and a full quota or a name already in use is refused there.
|
|
320
330
|
- **Archiving** — `archive_strategy` with the `strategyId` and the `expectedRevision` you read.
|
|
321
331
|
State how many agents are bound, that their configuration stays byte-identical, that open
|
|
322
|
-
positions are unaffected and that the player's draft is kept
|
|
323
|
-
|
|
324
|
-
|
|
332
|
+
positions are unaffected and that the player's draft is kept, re-based onto the revision the
|
|
333
|
+
archive produces.
|
|
334
|
+
- **Restoring** — find the archived strategy with `list_strategies` and `get_strategy` with
|
|
335
|
+
`includeInactive: true`, which add the player's own strategies in any state; another player's
|
|
336
|
+
PRIVATE strategy stays hidden either way. `restore_strategy` with the `strategyId` and
|
|
337
|
+
`expectedRevision` brings back unchanged, already-viable content and keeps the player's draft,
|
|
338
|
+
re-based onto the restored revision. Content that is not viable is
|
|
325
339
|
refused with `REPAIR_REQUIRED` and stays archived: stage the repair into the strategy's draft and
|
|
326
340
|
commit it — that commit restores it, and its read says `operation: RESTORE`.
|
|
327
341
|
|
|
@@ -12,8 +12,8 @@ shapes are binding in the sense that matters — they are checked, not merely as
|
|
|
12
12
|
elsewhere in this file are not covered by that gate, and vocabulary moves with deploys, so discovery
|
|
13
13
|
in the conversation stays the authority — prefer what `list_strategy_vocabulary`,
|
|
14
14
|
`get_strategy_column_contract`, and `get_strategy_signal_definition` return over anything
|
|
15
|
-
printed here, and read exact headers from a preview's
|
|
16
|
-
them.
|
|
15
|
+
printed here, and read exact headers from a `detail: "detailed"` preview's
|
|
16
|
+
`authoring.conditionColumns` before conditioning on them.
|
|
17
17
|
|
|
18
18
|
## The full-power checklist
|
|
19
19
|
|
|
@@ -69,8 +69,8 @@ things you do depends on the operation: on a **CREATE, omit `sectionKey` entirel
|
|
|
69
69
|
is refused, since a new strategy owns no custom sections yet; on an **UPDATE or RESTORE, send back
|
|
70
70
|
the keys `get_strategy` returned** for the sections you are keeping, and omit it on a section you
|
|
71
71
|
add. Either way you never invent one. To section-qualify a duplicated header, read the key from a
|
|
72
|
-
preview's `conditionColumns` or from the qualified candidates a
|
|
73
|
-
refusal offers.
|
|
72
|
+
`detail: "detailed"` preview's `authoring.conditionColumns` or from the qualified candidates a
|
|
73
|
+
`CONDITION_COLUMN_AMBIGUOUS` refusal offers.
|
|
74
74
|
|
|
75
75
|
**Event columns print only on their event.** `MACD_cross` and `EMA5_13` (Bullish/Bearish) carry a
|
|
76
76
|
value on the crossing bar and are null on every other one, which reads as UNRESOLVED. Use an event
|
|
@@ -145,7 +145,7 @@ decide it (TRUE once `atLeast` bars read TRUE, FALSE once the rest can no longer
|
|
|
145
145
|
UNRESOLVED.
|
|
146
146
|
|
|
147
147
|
What a header admits is SERVED, never guessed: every column in the strategy's report catalog
|
|
148
|
-
(`preview_strategy_report` → `conditionColumns[].outputs[].conditionHold`, and each scalar metric in
|
|
148
|
+
(`preview_strategy_report` at `detail: "detailed"` → `authoring.conditionColumns[].outputs[].conditionHold`, and each scalar metric in
|
|
149
149
|
the vocabulary) carries `{ timeframe, maxWindow, maxAtLeast, refusal }` — the timeframe it counts,
|
|
150
150
|
the largest `of`, the largest `atLeast`, and, when it admits only Once, why. `maxWindow` is the
|
|
151
151
|
history the store keeps for that column, less the column's own lookback and warm-up. A hold past
|
|
@@ -101,10 +101,10 @@ giveback 30 buffer 0.15; timeDecay ON aggressive (45/15, 15→60, stale 30).
|
|
|
101
101
|
|
|
102
102
|
## Using a playbook
|
|
103
103
|
|
|
104
|
-
Discover → confirm headers (`get_strategy_column_contract`, or one `preview_strategy_report`
|
|
105
|
-
whose `conditionColumns` lists every addressable header with
|
|
106
|
-
calibrate literals against the previewed live values → stage the draft
|
|
107
|
-
diagnostics name → read it back and review the drafted rule rows, then the draft's
|
|
108
|
-
preview —
|
|
109
|
-
markers) → commit per the strategy-authoring flow. Coin selection is call context, not strategy
|
|
104
|
+
Discover → confirm headers (`get_strategy_column_contract`, or one `preview_strategy_report` at
|
|
105
|
+
`detail: "detailed"`, whose `authoring.conditionColumns` lists every addressable header with
|
|
106
|
+
operators and vocabulary) → calibrate literals against the previewed live values → stage the draft
|
|
107
|
+
and fix what its diagnostics name → read it back and review the drafted rule rows, then the draft's
|
|
108
|
+
own report preview — the conditions register (`gridConditions`), verdict tally, and
|
|
109
|
+
`marketReadMarkers` (fix `unknown` / `ambiguous` markers) → commit per the strategy-authoring flow. Coin selection is call context, not strategy
|
|
110
110
|
state: explicit tickers for focused work, `ranked` (with an optional category) for scanning books.
|
|
@@ -33,7 +33,15 @@ Not "what were its returns" — whether it did *the thing it was told to do*.
|
|
|
33
33
|
at its own `strategyRevision`, and judging it against the strategy's current revision measures it
|
|
34
34
|
by rules it is not running.
|
|
35
35
|
- `get_agent_performance` and `list_trade_outcomes` — judge against that mandate.
|
|
36
|
-
- `get_trade_outcome_by_decision` / `get_trade_chart` when a specific trade needs explaining.
|
|
36
|
+
- `get_trade_outcome_by_decision` / `get_trade_chart` when a specific trade needs explaining. A
|
|
37
|
+
measurable trade's `tradeExcursion` reads in R: `mfeR` and `maeR` (the best and worst it reached),
|
|
38
|
+
`exitR`, and `giveBackR` (what it surrendered between its peak and the close). `exitEfficiency` is
|
|
39
|
+
a union — branch on its `state` before reading `efficiencyPercent`. All of them are gross of
|
|
40
|
+
costs; `netPnl` is the after-fee figure.
|
|
41
|
+
- The record around the trades: `get_agent_game_history` and `get_user_agent_game_history` (Market
|
|
42
|
+
Grid results, one agent or all), `get_agent_thought_log` and `get_user_thought_log` (the
|
|
43
|
+
reasoning), `get_agent_activity_feed` and `get_user_activity_feed` (what happened), and
|
|
44
|
+
`get_agent_explorer` for where the agent stands among public agents.
|
|
37
45
|
- `get_signal_performance` when the question is whether the agent's signals are working, as
|
|
38
46
|
distinct from whether its trades made money.
|
|
39
47
|
|
|
@@ -43,9 +51,16 @@ reading a clean report about a messy account learns nothing.
|
|
|
43
51
|
|
|
44
52
|
## 3. Open positions, with protections and distance to trigger
|
|
45
53
|
|
|
46
|
-
- `
|
|
47
|
-
|
|
48
|
-
a
|
|
54
|
+
- `list_user_active_positions` for everything at once: it carries the live mark and P&L
|
|
55
|
+
(`markPrice`, `unrealizedPnlUsd`, `roePct`) — check `pricingStatus` and `generatedAtMs` before
|
|
56
|
+
calling a mark current. `list_session_agent_positions` is the same view for one Market Grid
|
|
57
|
+
session. `get_agent_open_positions` is an entry-only view with no live mark: never measure a
|
|
58
|
+
distance to a trigger from it.
|
|
59
|
+
- For each open position, report its protections **and how far the live mark sits from each
|
|
60
|
+
trigger** — a stop is a number the player cannot act on; "3.1% from the stop" is one they can.
|
|
61
|
+
- `get_decision_order_attribution` maps an executed order back to the decision that placed it.
|
|
62
|
+
`get_open_orders` and `get_order_status` read the exchange directly — slower, and they fail when
|
|
63
|
+
the exchange is unreachable; report that as UNDETERMINED, never as no orders.
|
|
49
64
|
- `get_deployment_policy` / `get_radar_deployment` when the protection state comes from standing
|
|
50
65
|
policy rather than the position itself. `list_pending_approvals` and `list_gate_blocks` when
|
|
51
66
|
something looks like it should have fired and did not.
|
|
@@ -36,6 +36,7 @@ re-sorts a list, re-derives a verdict, or approves on the player's behalf.
|
|
|
36
36
|
|
|
37
37
|
- `scan_agent_coins` for the agent. The rows arrive server-ranked: qualifying coins first by score,
|
|
38
38
|
then the rest with their first failing gate, then coins that could not be scored with the reason.
|
|
39
|
+
The scan reads the agent's gates and spends no LLM call.
|
|
39
40
|
- Read the rows **as written**: the rank, the verdict, the first failing gate, the unscorable
|
|
40
41
|
label. Never re-sort them and never re-derive a verdict from its numbers — the server's ranking
|
|
41
42
|
is the answer.
|
|
@@ -118,3 +119,6 @@ trade.
|
|
|
118
119
|
- Never accept because the conviction reads high, because the scan ranked the coin first, or
|
|
119
120
|
because the player asked you to "find a trade" — finding is not approving. `get_entry_decision`
|
|
120
121
|
re-reads the row if the conversation moved on before they answered.
|
|
122
|
+
- Only a conversational decision awaits the player: radar fires and arena challenge reactions
|
|
123
|
+
execute on their own. `list_entry_decisions` with `status: PENDING` lists the ones still waiting
|
|
124
|
+
for an agent.
|