@battlegrid/mcp-server 31.2.65 → 31.2.67
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 +58 -3
- package/SKILL.md +5 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/EXPORT.json +8 -8
- package/skills/battlegrid-agent-management/SKILL.md +116 -73
- package/skills/battlegrid-market-analysis/SKILL.md +9 -5
- package/skills/battlegrid-strategy-authoring/SKILL.md +248 -208
- package/skills/battlegrid-strategy-doctor/SKILL.md +15 -6
- package/skills/battlegrid-strategy-examples/SKILL.md +34 -24
- package/skills/battlegrid-strategy-examples/references/playbooks.md +5 -5
- package/skills/battlegrid-strategy-examples/references/recipes.md +3 -2
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: battlegrid-strategy-authoring
|
|
3
|
-
description: Build a trading strategy with the player from a plain-English idea — gather evidence, lock the spec with them,
|
|
3
|
+
description: Build a trading strategy with the player from a plain-English idea — gather evidence, lock the spec with them, stage it into the strategy's draft against the platform grammar, show them exactly what will run, and commit it only once they confirm. Also forks, tunes, restores, archives and previews existing strategies. Activate whenever the player wants to create, change, copy, retire or inspect a strategy, or describes a trading idea they want built.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Strategy Authoring
|
|
7
7
|
|
|
8
8
|
You are turning an idea into a strategy that will trade real money on the player's live agents.
|
|
9
|
-
The whole point of this flow is that **nothing
|
|
9
|
+
The whole point of this flow is that **nothing is committed until they have seen what will actually
|
|
10
10
|
run and said yes to it.**
|
|
11
11
|
|
|
12
12
|
## The three failures this flow exists to prevent
|
|
@@ -15,11 +15,12 @@ All three come from real authoring sessions, and all three were discovered only
|
|
|
15
15
|
was already built. None of them is allowed to happen here.
|
|
16
16
|
|
|
17
17
|
1. **Built ≠ picked.** The player selected a "≥ +10%" trigger and a +5% trigger was implemented.
|
|
18
|
-
Nobody noticed until the results looked wrong. You prevent this by showing the *
|
|
19
|
-
|
|
18
|
+
Nobody noticed until the results looked wrong. You prevent this by showing the *drafted* rules,
|
|
19
|
+
as the server's own draft read serves them, next to their *locked* picks, before committing, and
|
|
20
|
+
naming any contradiction yourself.
|
|
20
21
|
2. **Silent zero-trigger.** A strategy was built that could never fire, and produced nothing for
|
|
21
|
-
days before anyone diagnosed it. You prevent this by reading the
|
|
22
|
-
per-signal preview before
|
|
22
|
+
days before anyone diagnosed it. You prevent this by reading the draft's own report preview and
|
|
23
|
+
the per-signal preview before committing, and flagging a draft that shows no passing conditions.
|
|
23
24
|
|
|
24
25
|
3. **Silent substitution.** A player asked for a strategy that triggers on the daily chart and
|
|
25
26
|
executes on the 4-hour. The grammar carries no such semantics. Instead of saying so, the flow
|
|
@@ -29,8 +30,8 @@ was already built. None of them is allowed to happen here.
|
|
|
29
30
|
learn otherwise.** You prevent this by testing expressibility BEFORE the spec lock, and by
|
|
30
31
|
naming the gap in the question itself — see step 2.
|
|
31
32
|
|
|
32
|
-
A strategy that reaches
|
|
33
|
-
of this skill, even if the player is happy with it.
|
|
33
|
+
A strategy that reaches a commit without all three checks having been made and reported is a
|
|
34
|
+
failure of this skill, even if the player is happy with it.
|
|
34
35
|
|
|
35
36
|
## Sequence
|
|
36
37
|
|
|
@@ -53,16 +54,17 @@ later step, so the player pays for the same payload twice and keeps paying for i
|
|
|
53
54
|
detail you did not keep, scroll back rather than re-fetching.
|
|
54
55
|
|
|
55
56
|
**Drafts are carved out of that rule.** A draft is the player's unsaved work, and another surface —
|
|
56
|
-
their builder, another device, an earlier
|
|
57
|
+
their builder, another device, an earlier stage of yours — can change it while you work. Read it
|
|
57
58
|
again whenever you are about to act on it.
|
|
58
59
|
|
|
59
60
|
**Start from what they are already part-way through.**
|
|
60
61
|
|
|
61
62
|
- Holding no strategy id? Call `list_strategy_drafts` first. If a draft comes back, say what it is,
|
|
62
63
|
when it was last touched and which surface touched it, and offer to continue it — never start a
|
|
63
|
-
second edit beside one the player has open.
|
|
64
|
+
second edit beside one the player has open. A draft whose strategy does not exist yet is a new
|
|
65
|
+
strategy they began; continuing it means staging into its id.
|
|
64
66
|
- Holding an id? Call `get_strategy_draft` before you propose anything. A draft means the player is
|
|
65
|
-
mid-edit.
|
|
67
|
+
mid-edit, and the `draftVersion` it returns (0 when there is none) is what your first stage names.
|
|
66
68
|
|
|
67
69
|
### 2. Lock the spec before you build anything
|
|
68
70
|
|
|
@@ -108,20 +110,25 @@ conversation. A field you remember from another strategy is not discovery.
|
|
|
108
110
|
question you would otherwise guess — and a refusal you would otherwise earn:
|
|
109
111
|
|
|
110
112
|
- **A CREATE omits `sectionKey`.** It is derived from the section itself, so the same submitted
|
|
111
|
-
section at the same position yields the same key on every
|
|
112
|
-
yourself on a CREATE is refused with a hint
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
113
|
+
section at the same position yields the same key on every validation — each stage's diagnostics
|
|
114
|
+
and the commit alike. Minting a `custom:<uuid>` yourself on a CREATE is refused with a hint
|
|
115
|
+
telling you to omit `sectionKey` on CREATE; on an UPDATE, send back the key the strategy's REPORT
|
|
116
|
+
carries for each section you keep — from `get_strategy`, or from the draft's REPORT when it holds
|
|
117
|
+
one — and omit it on a section you add. This is the one composition field whose right answer is
|
|
118
|
+
"leave it out".
|
|
119
|
+
- **The `entry` axis is a union keyed by its trigger.** `ON_CANDLE_CLOSE` is sent alone —
|
|
120
|
+
`{ "entry": { "trigger": "ON_CANDLE_CLOSE" } }` — and a `levelOffsetAtrMultiple` or
|
|
121
|
+
`validForBars` beside it is refused as an unrecognized key. A level trigger (`STOP_THROUGH_LEVEL`,
|
|
122
|
+
`ON_RETEST`) sends both of them, with no defaults. A CREATE that stages no entry takes the
|
|
123
|
+
platform's seed entry, so the axis is not required on every CREATE — stage it whenever the locked
|
|
124
|
+
spec names an entry. Every trigger is decided at the close of the strategy's OWN bar, so there is
|
|
125
|
+
no confirm-timeframe key; for the level triggers the level itself is derived from the trigger and
|
|
126
|
+
the trade's direction, never named. A multi-bar hold belongs to the clause or group that needs
|
|
127
|
+
it — its own `hold: { atLeast, of }`, which the editor calls **Hold** (Once, In a row, Within, At
|
|
128
|
+
least), counted in completed bars of the column's own timeframe — not to this axis. Every clause
|
|
129
|
+
and group carries `hold`; `{ "atLeast": 1, "of": 1 }` is Once. The `strategy-examples` skill
|
|
130
|
+
carries the vocabulary, the served hold domain (a crossover is held "within" only; a Developing
|
|
131
|
+
column cannot be held) and the per-column Confirmed / Developing read.
|
|
125
132
|
- `get_strategy_column_contract` → `outputs[].conditionOperators`. An empty array means that
|
|
126
133
|
rendered header has no comparison semantics and cannot appear in a condition clause at all.
|
|
127
134
|
Legality is per rendered header, not per column: a trajectory's slot header and its `_trend`
|
|
@@ -136,203 +143,235 @@ position-management presets, worked desk-grade playbooks — activate `strategy-
|
|
|
136
143
|
teaches what to compose; this skill stays the authority on the flow.
|
|
137
144
|
|
|
138
145
|
`derive_strategy_rule_view` belongs here, at composition time, and only here: it reports report
|
|
139
|
-
membership and registry-default allocations for
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
`simulate_aggregate_score` does **not** belong here. It is a review tool (step 5) and running it
|
|
143
|
-
now answers a question about
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
the
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
`
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
146
|
+
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.
|
|
148
|
+
|
|
149
|
+
`simulate_aggregate_score` does **not** belong here. It is a review tool (step 5), and running it
|
|
150
|
+
now answers a question about rows you have not staged, not about the draft the player will be
|
|
151
|
+
asked to approve.
|
|
152
|
+
|
|
153
|
+
### 4. Stage, and iterate on the diagnostics
|
|
154
|
+
|
|
155
|
+
**Every change goes through the strategy's draft.** `stage_strategy_draft` takes, inside its
|
|
156
|
+
`request`, the `strategyId`, the `draftVersion` your last read returned (0 when there was none) and
|
|
157
|
+
the `axes` you propose. It writes those axes into the player's draft — attributed to you, landing in
|
|
158
|
+
their builder as unsaved changes — and commits nothing. Each stage returns the draft's new
|
|
159
|
+
`version`: that is the `draftVersion` your next stage names. Stage each change once, and never fire
|
|
160
|
+
two stages in parallel against one draft.
|
|
161
|
+
|
|
162
|
+
**A new strategy is a create draft.** Omit `strategyId` and send `draftVersion: 0` on the first
|
|
163
|
+
stage; the response carries the id minted for it, which every later call names. A create needs
|
|
164
|
+
IDENTITY (`{ name, description, tagline }`) and TIMEFRAME_PROFILE (`{ timeframe }`). A create with
|
|
165
|
+
no REPORT starts from the platform's starting report (Price Action, RSI, MACD and Moving Averages),
|
|
166
|
+
one with no ENTRY takes the seed entry, and the rule rows you stage overlay a creation seed in
|
|
167
|
+
which every signal is Off.
|
|
168
|
+
|
|
169
|
+
**An UPDATE carries only the axes that change.** Axes you omit keep the values the draft has, and
|
|
170
|
+
an axis the draft does not hold is the committed strategy's. Each axis you send is written WHOLE —
|
|
171
|
+
a REPORT is the complete section list, CONDITIONS the complete set — except SIGNAL_RULES, whose
|
|
172
|
+
rows replace the drafted rows for the same `signalId` and keep every other one. Restating an axis
|
|
173
|
+
you are not changing is never required, changes nothing about the result, and the player pays for
|
|
174
|
+
every byte of it on this call and on every later step of the conversation. Send the axes you are
|
|
175
|
+
changing; send no other axis.
|
|
176
|
+
|
|
177
|
+
**A rule row is complete.** Every staged row carries `signalId`, `allocation` and `required`;
|
|
178
|
+
`params` only when the thresholds change, and omitting it keeps the stored ones byte-identically.
|
|
179
|
+
"Raise volume_surge to Critical" is one row with `allocation: 3` and `required` exactly as it
|
|
180
|
+
stands now — read it from the draft's SIGNAL_RULES row when the draft holds one, otherwise from
|
|
181
|
+
`get_strategy`. Never set `required` from memory, and never change it unless the player asked about
|
|
182
|
+
the Required flag: a wrong value there is how a scoring signal silently becomes a mandatory trade
|
|
183
|
+
gate. Stage no row for a signal you are not changing.
|
|
184
|
+
|
|
185
|
+
**Read the diagnostics every stage returns.** Past its checks of shape — an undeclared key, a
|
|
186
|
+
parameter beside `ON_CANDLE_CLOSE`, a coin that names nothing — a stage refuses nothing for being
|
|
187
|
+
incomplete or invalid, because the draft is the player's unsaved work. The stage's `diagnostics`
|
|
188
|
+
are where you learn what the commit would do:
|
|
189
|
+
|
|
190
|
+
- `errors` — the refusals the commit would raise, each with its `field` and `details` naming the
|
|
191
|
+
`path`, the value it received and the `allowedDomain` it accepts. Fix the axis and stage again.
|
|
192
|
+
- `warnings` and `mismatches` — observations that never refuse. `NO_SIGNAL_ACTIVE` means the
|
|
193
|
+
strategy scores nothing and will never route a trade; a mismatch means the report and the
|
|
194
|
+
weights disagree. Fix each one, or carry it into the review as something to explain.
|
|
195
|
+
|
|
196
|
+
An empty `errors` is not a promise: the strategy quota, the name and capital feasibility are
|
|
197
|
+
decided only by the commit itself.
|
|
198
|
+
|
|
199
|
+
**Stop after three consecutive autonomous restages.** A fourth means you are guessing — show the
|
|
200
|
+
player the diagnostics and ask. Never present a draft for confirmation while it still carries
|
|
175
201
|
diagnostics you have not explained to them.
|
|
176
202
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
203
|
+
**When a stage is refused**, nothing was written:
|
|
204
|
+
|
|
205
|
+
- **`DRAFT_AXIS_CONTESTED`** names the axes the player's own hand changed after the version you
|
|
206
|
+
named. Their edit is newer than your proposal: read the draft, tell them so, and propose again
|
|
207
|
+
only when they ask. Never re-send the same values.
|
|
208
|
+
- **`DRAFT_VERSION_MOVED`** — the version you named is one the draft never reached: it was read from
|
|
209
|
+
a draft since committed or discarded. Read it again and propose against what the player now has.
|
|
210
|
+
|
|
211
|
+
Never raise the number to get past either refusal.
|
|
212
|
+
|
|
213
|
+
### 5. Review — show the drafted truth, not your summary of it
|
|
214
|
+
|
|
215
|
+
Once the stage's diagnostics carry nothing you cannot explain, read the draft with
|
|
216
|
+
`get_strategy_draft`. Everything here comes from that read:
|
|
217
|
+
|
|
218
|
+
- **What will actually run.** Its `diff` — every drafted axis with its `live` and drafted value
|
|
219
|
+
and the field-level `changes` between them, the drafted signal-rule rows among them — beside the
|
|
220
|
+
picks they locked in step 2. **If any drafted row or diff entry contradicts a locked pick, say so
|
|
221
|
+
in words before you ask for anything.** Do not make them spot it.
|
|
222
|
+
- **All of what the commit publishes.** The diff names every axis the draft holds, including
|
|
223
|
+
unsaved work the player had in it before you staged. Read that list out in the confirmation as
|
|
224
|
+
the commit's own: the player is approving all of it, not only what you proposed.
|
|
225
|
+
- **Whether it can fire.** `preview_strategy_report` with
|
|
226
|
+
`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. Support it
|
|
228
|
+
with `get_coin_signal_preview` on the locked universe's main coin(s). The preview's
|
|
229
|
+
`coinSelection` is its cohort, never strategy state: no strategy has one and `get_strategy` will
|
|
230
|
+
not return one, so choose it — a short explicit list of the tickers the change is about for a
|
|
231
|
+
single-gate edit, a `ranked` cohort for a broad one. Any reasonable cohort is correct.
|
|
232
|
+
- **A routing what-if**, optionally, via `simulate_aggregate_score` — **after the draft read, never
|
|
233
|
+
before it.** This is a calculator, not a verdict: it computes over whatever inputs you hand it.
|
|
234
|
+
Feed it what the commit would carry — the gate and the allocations as the read serves them (the
|
|
235
|
+
drafted value where the draft holds the axis, the committed one where it does not) and the
|
|
236
|
+
per-signal scores from the preview you just read — and show those inputs beside its output so a
|
|
237
|
+
copy slip is visible on the card itself.
|
|
194
238
|
|
|
195
239
|
**Flag before confirming** if the preview shows no passing conditions, the coin preview shows
|
|
196
|
-
zero triggered signals,
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
240
|
+
zero triggered signals, the simulation reports `wouldRoute: false`, or the diagnostics warn
|
|
241
|
+
`NO_SIGNAL_ACTIVE`. Any one of those means the strategy probably never fires — ask whether to
|
|
242
|
+
revise rather than presenting it as healthy.
|
|
243
|
+
|
|
244
|
+
**State the impact as numbers, not buried in prose.** The read's `impact` carries:
|
|
245
|
+
|
|
246
|
+
- `operation` — CREATE, UPDATE or RESTORE. A RESTORE is a draft over an archived strategy: say
|
|
247
|
+
that committing it also restores the strategy and moves its bound agents, by count, from
|
|
248
|
+
ORPHANED to BOUND.
|
|
249
|
+
- `boundAgentCount`, `openPositionCount` and `timeframeChanged`. A change to signal rules reaches
|
|
250
|
+
every bound agent the moment it commits — say so.
|
|
251
|
+
- `admission` — for a create draft or an archived strategy, the quota and whether the name is
|
|
252
|
+
free. It is advisory: the commit decides.
|
|
253
|
+
- `capital` — each bound agent the drafted stop band would leave unable to place an order, with its
|
|
254
|
+
smallest order against the order floor. Name every one.
|
|
201
255
|
|
|
202
256
|
There is no backtest here and no expected-frequency figure. Do not imply one. What you have is a
|
|
203
257
|
point-in-time reading, and you say so.
|
|
204
258
|
|
|
205
|
-
### 6.
|
|
206
|
-
|
|
207
|
-
**A draft decides which of the two you are doing.**
|
|
259
|
+
### 6. Commit — only on the player's explicit pick
|
|
208
260
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
- **They hold none** → compile → confirm → apply, as below.
|
|
261
|
+
**In a conversation the Strategy Builder hosts**, each stage is already on the player's rail as
|
|
262
|
+
attributed unsaved changes, and their own Create, Save or Restore is one way to commit it. Report
|
|
263
|
+
that the change is staged and name the axes; offer to commit it yourself only through the same
|
|
264
|
+
confirmation as below.
|
|
214
265
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
confirmation as the plan's own: the player is approving all of it, not only what you proposed.
|
|
218
|
-
|
|
219
|
-
If a staging call is refused as contested, it names the axes the player's own hand changed after
|
|
220
|
-
your compile. Do not retry it and do not work around it — compile again so the new plan absorbs
|
|
221
|
-
those edits, then stage that one. The same holds when it is refused because the strategy committed
|
|
222
|
-
a newer revision after your compile: compile again against what is committed now.
|
|
223
|
-
|
|
224
|
-
**Offer to discard a draft only on the player's explicit word**, never on your own judgement that
|
|
225
|
-
it looks stale, and never batched into another act. State when it was last touched and which
|
|
226
|
-
surface touched it, ask, and call `discard_strategy_draft` with `confirm: true` only if they say
|
|
227
|
-
so. The unsaved values are gone afterwards and there is no other copy.
|
|
266
|
+
One `ask_user` confirmation carrying the diff, the impact and the remaining warnings, offering
|
|
267
|
+
Commit / Revise / Cancel.
|
|
228
268
|
|
|
229
|
-
**
|
|
230
|
-
|
|
231
|
-
consent. Report that it is staged, name the axes, and present no apply confirmation — the server
|
|
232
|
-
refuses `apply_strategy_plan` from such a conversation as a tool error, so calling it spends an op
|
|
233
|
-
of your budget and commits nothing.
|
|
269
|
+
On **Commit**, call `commit_strategy_draft` with the `strategyId` and exactly two numbers from the
|
|
270
|
+
`get_strategy_draft` read the confirmation showed, and nothing else:
|
|
234
271
|
|
|
235
|
-
|
|
272
|
+
- `draftVersion` — that read's `draftVersion`
|
|
273
|
+
- `expectedRevision` — that read's `committedRevision`, which is `null` for a strategy not
|
|
274
|
+
created yet
|
|
236
275
|
|
|
237
|
-
|
|
276
|
+
Never reconstruct either from prose or memory, and never take them from a stage response: the
|
|
277
|
+
player approved one read, and the commit names that read. It publishes exactly that draft over
|
|
278
|
+
exactly that revision, through the same committer the builder's Save runs.
|
|
238
279
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
There is no `plan` member, and one is rejected as an unrecognized key. The server keeps the plan your
|
|
243
|
-
compile approved and reads it back, so **nothing is copied from the compile response** — the whole
|
|
244
|
-
class of mis-transcription is gone rather than guarded against.
|
|
245
|
-
|
|
246
|
-
`planToken` is opaque: forward it byte-for-byte exactly as received. Never retype, abbreviate or
|
|
247
|
-
reconstruct it. A mangled token addresses no approved plan and is refused with the real one intact.
|
|
248
|
-
|
|
249
|
-
On **Revise**, return to step 4. On **Cancel**, stop and let the token lapse.
|
|
280
|
+
On **Revise**, return to step 4. On **Cancel**, stop: the draft stays as staged and nothing is
|
|
281
|
+
committed.
|
|
250
282
|
|
|
251
283
|
If the player types free text while the confirm form is open, that is **not** consent and not a
|
|
252
|
-
cancellation. Answer what they said, then present the same
|
|
253
|
-
Prose never triggers
|
|
284
|
+
cancellation. Answer what they said, then present the same read's confirmation again, unchanged.
|
|
285
|
+
Prose never triggers a commit. The same holds for an answer typed into the form's own
|
|
254
286
|
answer-in-your-own-words box: it is the player's words in an answer slot, not a confirming pick,
|
|
255
287
|
so treat it exactly as you would free text in the chat.
|
|
256
288
|
|
|
257
|
-
Do not pre-check
|
|
258
|
-
|
|
289
|
+
Do not pre-check ownership, viability, quota or the name before calling. The server is the only
|
|
290
|
+
authority on all of them; your job is to react to what it returns.
|
|
291
|
+
|
|
292
|
+
**Report the change from the receipt.** The commit returns the committed `strategy` and, when
|
|
293
|
+
signal rules moved, `ruleChanges` with the server's own `before` and `after` for each edited
|
|
294
|
+
signal. State those. Never describe a prior value from memory or from an earlier read — the
|
|
295
|
+
receipt is the only record that cannot be stale.
|
|
296
|
+
|
|
297
|
+
**Offer to discard a draft only on the player's explicit word**, never on your own judgement that
|
|
298
|
+
it looks stale, and never batched into another act. `get_strategy_draft` is the read of what a
|
|
299
|
+
discard destroys: say what the draft holds, when it was last touched and which surface touched it,
|
|
300
|
+
ask, and only if they say so call `discard_strategy_draft` with the `strategyId` and the
|
|
301
|
+
`draftVersion` you read. There is no dry run and no confirmation parameter — the version is the
|
|
302
|
+
fence, and a draft written since your read is refused with `DRAFT_VERSION_MOVED` and nothing is
|
|
303
|
+
removed. The unsaved values are gone afterwards and there is no other copy.
|
|
259
304
|
|
|
260
305
|
### 7. Lifecycle
|
|
261
306
|
|
|
262
|
-
`fork_strategy`, `
|
|
263
|
-
`preview_strategy_report` are part of this flow.
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
the
|
|
307
|
-
|
|
308
|
-
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
- **A
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
- **An apply whose outcome you never saw** (interrupted or timed out) — read the committed state
|
|
331
|
-
first with `get_strategy` or `list_strategies`. If it committed, report success. **Never
|
|
332
|
-
re-apply and never recompile over an unverified outcome** — a blind retry duplicates the
|
|
333
|
-
strategy or dies on the name check.
|
|
334
|
-
- **A run that ended on a budget guard mid-build** — when they nudge you, recompile and re-enter
|
|
335
|
-
at the review. Never apply a plan compiled in a run that was cut short; treat it as stale.
|
|
307
|
+
`fork_strategy`, `restore_strategy`, `archive_strategy`, `discard_strategy_draft` and
|
|
308
|
+
`preview_strategy_report` are part of this flow. Every change to a strategy's content — a single
|
|
309
|
+
tuned rule included — is a staged draft committed with `commit_strategy_draft`; none of the other
|
|
310
|
+
verbs writes content.
|
|
311
|
+
|
|
312
|
+
- **Tuning a single rule** is one SIGNAL_RULES row staged (step 4), read, confirmed and committed.
|
|
313
|
+
State how many agents are bound, and that the change reaches every one of them immediately.
|
|
314
|
+
- **Forking** — `fork_strategy` takes the `strategyId`, the exact `sourceRevision` to copy and an
|
|
315
|
+
optional `name`, and returns a NEW create draft's `strategyId` and `draftVersion`. **No strategy
|
|
316
|
+
exists yet.** Read the draft with `get_strategy_draft` — every authored axis equals the source
|
|
317
|
+
revision's, and ORIGIN names the source — stage any change into it, review it as above, and on the
|
|
318
|
+
player's word commit it with `expectedRevision: null`. Forking spends no strategy slot; the
|
|
319
|
+
commit does, and a full quota or a name already in use is refused there.
|
|
320
|
+
- **Archiving** — `archive_strategy` with the `strategyId` and the `expectedRevision` you read.
|
|
321
|
+
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
|
+
- **Restoring** — `restore_strategy` with the `strategyId` and `expectedRevision` brings back
|
|
324
|
+
unchanged, already-viable content and keeps the player's draft. Content that is not viable is
|
|
325
|
+
refused with `REPAIR_REQUIRED` and stays archived: stage the repair into the strategy's draft and
|
|
326
|
+
commit it — that commit restores it, and its read says `operation: RESTORE`.
|
|
327
|
+
|
|
328
|
+
**Your `ask_user` is the approval, and the server does not repeat it.** No strategy verb takes a
|
|
329
|
+
confirmation flag. So never call `commit_strategy_draft`, `archive_strategy`, `restore_strategy` or
|
|
330
|
+
`discard_strategy_draft` on a turn where the player has not made an explicit confirming pick —
|
|
331
|
+
never because you judged the change safe. Free text typed while a confirmation is open is not
|
|
332
|
+
consent: answer it, then present the same confirmation again. That covers words typed into the
|
|
333
|
+
form's own answer box as well as words sent in chat — a confirming pick is one of the options you
|
|
334
|
+
offered, and nothing else is.
|
|
335
|
+
|
|
336
|
+
## When the server refuses
|
|
337
|
+
|
|
338
|
+
Each refusal is a specific typed code, and a refusal of a draft's stage or commit names its next
|
|
339
|
+
act in `details.nextAct` — `get_draft` or `stage`; a moved or contested draft names `get_draft`
|
|
340
|
+
from any tool. Read it and take the cheapest correct step — never retry the same call blindly.
|
|
341
|
+
|
|
342
|
+
- **`DRAFT_VERSION_MOVED`** (`nextAct: get_draft`) — the draft changed after your read: the
|
|
343
|
+
player's form saved an edit, another surface staged, or a human-paced review outlived it. Read
|
|
344
|
+
it again, present the new diff and impact, and **ask for confirmation again.** Never commit a
|
|
345
|
+
newer version on your own judgement that it matches the one they already approved; they approve
|
|
346
|
+
the draft that will actually be committed.
|
|
347
|
+
- **`CONFLICT`** (`nextAct: get_draft`) — the strategy committed a newer revision after your read;
|
|
348
|
+
the details carry `expectedRevision` and `actualRevision`. The same recovery: read, re-present,
|
|
349
|
+
re-confirm.
|
|
350
|
+
- **A commit already in progress** (`nextAct: get_draft`) — a commit of this draft version is in
|
|
351
|
+
flight or was interrupted. Read the draft: if its version moved, the commit landed, so read the
|
|
352
|
+
strategy and report it; otherwise commit again once the refusal's wait has passed, or stage again.
|
|
353
|
+
- **A validation error** (`nextAct: stage`) — the error the diagnostics named, with its own
|
|
354
|
+
`field` and `details`. Nothing was written. Return to step 4: fix the axis, stage, read, and
|
|
355
|
+
confirm again.
|
|
356
|
+
- **A refusal with no `nextAct`** — the strategy quota (`FORBIDDEN`), a name already in use,
|
|
357
|
+
`REPAIR_REQUIRED`, viability, or a `CONFLICT` whose `details.reason` is `RADAR_DEPLOYMENT_MOVED`. The draft is
|
|
358
|
+
untouched. Clear the cause with the player — a rename is an IDENTITY stage, which makes a new
|
|
359
|
+
version to read and confirm — then commit the draft they confirmed. A moved radar deployment is
|
|
360
|
+
a race, not a decision: read and commit again.
|
|
361
|
+
- **A commit whose outcome you never saw** (interrupted or timed out) — send the same commit again
|
|
362
|
+
first: the server replays the original receipt for the same draft version, so a commit that
|
|
363
|
+
landed is reported once and never doubled. If that retry is refused as moved, verify the
|
|
364
|
+
committed state with `get_strategy` or `list_strategies` and reconcile with the player before
|
|
365
|
+
anything else. **Never stage or commit anything new over an unverified outcome.**
|
|
366
|
+
- **A run that ended on a budget guard mid-build** — when they nudge you, read the draft again
|
|
367
|
+
with `get_strategy_draft` and re-enter at the review with the version and revision you just read.
|
|
368
|
+
Never trust a draft version, diagnostics or a confirmation from a run that was cut short.
|
|
369
|
+
- **An unknown coin** — a `benchmarkTicker` in a staged REPORT, a `coinSelection` ticker or the
|
|
370
|
+
`marketReadLensTicker` that names no catalogued coin is refused as a validation error naming that
|
|
371
|
+
field (`Unknown coin symbol: '<input>'`), with nothing written. Symbols are case-insensitive and
|
|
372
|
+
exchange symbols resolve (`btc`, `kPEPE`, `xyz:BRENTOIL` all reach their coin, and the draft
|
|
373
|
+
stores the canonical ticker), so the refusal means the coin is not tracked: never retry with
|
|
374
|
+
another casing — ask the player which coin they meant.
|
|
336
375
|
|
|
337
376
|
## When the grammar cannot express the ask
|
|
338
377
|
|
|
@@ -348,19 +387,20 @@ make that concrete, and all three have to hold:
|
|
|
348
387
|
|
|
349
388
|
- the gap is named in the **question you put to the player**, not only in prose around it
|
|
350
389
|
- the nearest expressible option says what it gives up
|
|
351
|
-
- nothing is
|
|
390
|
+
- nothing is staged for the original ask, because there is nothing to stage
|
|
352
391
|
|
|
353
|
-
## Keep
|
|
392
|
+
## Keep each stage within the draft cap
|
|
354
393
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
lean strategy plus follow-up edits is
|
|
358
|
-
|
|
394
|
+
The axes one stage carries are capped at 256,000 UTF-8 bytes — the same cap the builder's own
|
|
395
|
+
draft write enforces — and a stage past it is refused at the boundary naming the cap, with nothing
|
|
396
|
+
written. Splitting a build into a lean strategy plus follow-up edits is also a choice about
|
|
397
|
+
reviewability: each commit is one diff the player can read.
|
|
359
398
|
|
|
360
399
|
## Reporting discipline
|
|
361
400
|
|
|
362
401
|
- Report numbers exactly as the tools return them. Never recompute or re-derive.
|
|
363
|
-
-
|
|
364
|
-
|
|
402
|
+
- A stage changes the player's draft and nothing else — no strategy, agent or revision. A commit is
|
|
403
|
+
the write that reaches the strategy and every agent bound to it. Say which one you are about to
|
|
404
|
+
do.
|
|
365
405
|
- A tool that fails is reported as failed. Never fill a gap with a plausible value.
|
|
366
406
|
- Be concise. They are deciding whether to point real money at this.
|