@battlegrid/mcp-server 31.2.94 → 31.2.97

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
@@ -3322,7 +3322,7 @@ Strategies and intelligence agents change only through their drafts, with one to
3322
3322
  1. **Choose the entity.** `list_strategies` (add `includeInactive:true` when repairing an archived strategy) and `get_strategy`, or `list_intelligence_agents` and `get_intelligence_agent`. `fork_strategy({ strategyId, sourceRevision })` copies a visible revision into a new create draft and returns its `strategyId` and `draftVersion`; it creates nothing.
3323
3323
  2. **Discover the report vocabulary live.** Walk `list_strategy_categories` → `list_strategy_vocabulary` → `get_metric_construction_hints` → `get_strategy_column_contract`, and use `get_strategy_section_template` / `preview_strategy_report`. Do not guess metric, transform, parameter, template, or enabled-timeframe facts — they are server-discovered.
3324
3324
  3. **Read the draft.** `get_<kind>_draft({ request: { <id> } })` returns the draft (or `null`), its `draftVersion` (0 when none is held), the live `committedRevision` (null for an entity not created yet), a per-axis `diff` against live, `diagnostics` and `impact`.
3325
- 4. **Stage the change.** `stage_<kind>_draft({ request: { <id>?, draftVersion, axes } })` names the version you read. Each axis is whole, except a strategy's `SIGNAL_RULES`, whose rows replace the drafted rows for the same signals and keep every other one. Omit the id to open a new create draft; the response carries the minted id. A stage that has written never refuses: the composed draft's errors and warnings come back as `diagnostics`. It is refused only when the version is one the draft never reached (`DRAFT_VERSION_MOVED`) or when the player's own form changed an axis you are staging after that version (`DRAFT_AXIS_CONTESTED`, naming `contestedAxes`).
3325
+ 4. **Stage the change.** `stage_<kind>_draft({ request: { <id>?, draftVersion, axes } })` names the version you read. Each axis is whole: it replaces the drafted axis entirely, so restate what it keeps. Omit the id to open a new create draft; the response carries the minted id. A stage that has written never refuses: the composed draft's errors and warnings come back as `diagnostics`. It is refused only when the version is one the draft never reached (`DRAFT_VERSION_MOVED`) or when the player's own form changed an axis you are staging after that version (`DRAFT_AXIS_CONTESTED`, naming `contestedAxes`).
3326
3326
  5. **Review with the player, then commit.** Read the draft again, show the player its diff and impact, and on their explicit word call `commit_<kind>_draft({ request: { <id>, draftVersion, expectedRevision } })` with exactly the two numbers that read returned — `expectedRevision: null` creates the entity at revision 1. A draft that moved is refused `DRAFT_VERSION_MOVED`, a moved revision `CONFLICT`, and an invalid draft with the same code its diagnostics carried; nothing is written. Each refusal's `details.nextAct` says what to do next (`get_draft` or `stage`). The commit is idempotent on `{ id, draftVersion }`: a retried commit replays its outcome. Changed strategy configuration propagates to every bound agent immediately; committing a draft of an archived strategy restores it.
3327
3327
 
3328
3328
  `discard_<kind>_draft({ request: { <id>, draftVersion } })` removes the draft at the version you read and never one that moved since. `preview_strategy_report({ coinSelection, source: { kind: 'DRAFT', strategyId, draftVersion } })` previews a draft as a commit would compose it. In multi-account mode the lifecycle tools use the `{ account, request }` sibling envelope; `preview_strategy_report` keeps its own flat input and takes `account` beside `coinSelection` and `source`.
@@ -3331,7 +3331,7 @@ Strategies and intelligence agents change only through their drafts, with one to
3331
3331
 
3332
3332
  ## Capabilities
3333
3333
 
3334
- Tools, prompts, and resources are **discovered live** from the connected server via `tools/list`, `prompts/list`, and `resources/list`. This package intentionally does not copy the server's catalog, formulas, signal IDs, or defaults — inspect the live connection for the authoritative, current surface. Broadly, the server exposes game play (Market Grid), market context, account state, leaderboards, intelligence agents and automation, strategy discovery/authoring, and trading signals/decisions.
3334
+ Tools, prompts, and resources are **discovered live** from the connected server via `tools/list`, `prompts/list`, and `resources/list`. This package intentionally does not copy the server's catalog, formulas, or defaults — inspect the live connection for the authoritative, current surface. Broadly, the server exposes game play (Market Grid), market context, account state, leaderboards, intelligence agents and automation, strategy discovery/authoring, and trading signals/decisions.
3335
3335
 
3336
3336
  ## Environment variables
3337
3337
 
package/SKILL.md CHANGED
@@ -30,7 +30,7 @@ to connect and to know which one to open.
30
30
 
31
31
  ## Discover the live surface first
32
32
 
33
- **Tools, prompts, and resources are discovered live from this MCP connection.** Always read the current `tools/list`, `prompts/list`, and `resources/list` before acting — a cached capability list is not authoritative after a server deployment. This skill teaches the workflows and the strict request contracts; it deliberately does not copy the server's tool catalog, metric/transform vocabulary, signal IDs, formulas, or default values. Discover those from the live tools (`list_strategy_categories`, `list_strategy_vocabulary`, `list_strategy_signals`, `get_strategy_signal_definition`, …). Never guess a metric, transform, parameter, template, signal, or enabled-timeframe fact.
33
+ **Tools, prompts, and resources are discovered live from this MCP connection.** Always read the current `tools/list`, `prompts/list`, and `resources/list` before acting — a cached capability list is not authoritative after a server deployment. This skill teaches the workflows and the strict request contracts; it deliberately does not copy the server's tool catalog, metric/transform vocabulary, formulas, or default values. Discover those from the live tools (`list_strategy_categories`, `list_strategy_vocabulary`, `list_strategy_signals`, `get_strategy_signal_definition`, …). Never guess a metric, transform, parameter, template, signal, or enabled-timeframe fact.
34
34
 
35
35
  ## Single-account vs multi-account request shape
36
36
 
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.94";
52
+ export declare const PACKAGE_VERSION = "31.2.97";
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.94';
55
+ export const PACKAGE_VERSION = '31.2.97';
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@battlegrid/mcp-server",
3
- "version": "31.2.94",
3
+ "version": "31.2.97",
4
4
  "description": "BattleGrid MCP server — play crypto prediction games from AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "generator": "battlegrid-app/server/scripts/export-mcp-skills.mjs",
3
- "contractVersion": "105.0.0",
3
+ "contractVersion": "108.2.0",
4
4
  "files": {
5
- "battlegrid-agent-management/SKILL.md": "8ebb7d4fcc5d6a9ce463a762bf58d04a7f641369f7feaf64d2489727531e6f00",
5
+ "battlegrid-agent-management/SKILL.md": "34a868f8068df189ce13af47c23011aabcf6a1f07128da4d4706066628cfaa5f",
6
6
  "battlegrid-agent-management/references/agent-stage-examples.md": "d47555906ce8dedf4c17422f8f5d60187f2d6b3c0af5d9545617a10a5bdb59a1",
7
- "battlegrid-arena-play/SKILL.md": "25f078eb31db5cd3d78ce0bc251802c32f94234fd8a8c6467c5b68abc41706f2",
8
- "battlegrid-market-analysis/SKILL.md": "875bda71dd766ad06ac8e508679bcd3400a600cf74d2eac6c922dbe23175f325",
9
- "battlegrid-radar-deployment/SKILL.md": "093ac358cd4f1a67a7dd467b0b4161c9a055cdd516d49ebb23bd4e9ef44aa200",
10
- "battlegrid-radar-deployment/references/arena-stage-examples.md": "f924b70801a4b72bbde5a80823408939903cba6b294d8554fc4afc11d80b3333",
7
+ "battlegrid-arena-play/SKILL.md": "719dfd57a9ad5b70801f366f11d0e0a57c87c7aae7751b9acca7a5a1584aa36e",
8
+ "battlegrid-market-analysis/SKILL.md": "b647dbe9db4ecc67b744b7f7a82ec4e56f2e7f4d2cb1c20546649085b1ae1529",
9
+ "battlegrid-radar-deployment/SKILL.md": "12ae488bcc81e17fdd749448ecd98f42846c98960895c1d579db833836739eb2",
10
+ "battlegrid-radar-deployment/references/arena-stage-examples.md": "f605aaa266a291ef1b6d02a0e8885ad5df2fea88c800be2b6625cd629cd741f2",
11
11
  "battlegrid-radar-deployment/references/radar-stage-examples.md": "1ddad4a11f021dd65234ee65cc12d7d1561fe9acfd61cb021f4352080d4cecd5",
12
- "battlegrid-strategy-authoring/SKILL.md": "fcc4ab6ae7e75e0949cef057134288e5e6e67ff96d3238bb551775ba5ce22f95",
13
- "battlegrid-strategy-authoring/references/strategy-stage-examples.md": "1c35353c7280934486b65d5defe80f87278e77955b6041db677238940e589b50",
14
- "battlegrid-strategy-doctor/SKILL.md": "14f20bff9e2b5a59d11634fe3615b1298d672d5e2eba06d3dc8698b571b3bee3",
15
- "battlegrid-strategy-examples/SKILL.md": "528049af46a0a829628681d16076129eb57e898445c803e4ebafae98699a3b65",
16
- "battlegrid-strategy-examples/references/playbooks.md": "9e4038df885bb840d6ee58ba0475a9214dc58d12bf355c91c8aae625d58e3096",
17
- "battlegrid-strategy-examples/references/recipes.md": "61382acdd295fa159f055b787ba501f1c015f383f59a6714a973057f10de611f",
18
- "battlegrid-strategy-examples/references/tradingview-ports.md": "706a7dd3a120b2f3d5fa3190924f493cf4ebaf5df895bbeb155c2db73f8f5ece",
19
- "battlegrid-trade-analysis/SKILL.md": "f545b916dc2a37c8fc35e16b27fa6f78ead4302e67f65ac584765c1e069b4ab2",
20
- "battlegrid-trade-proposal/SKILL.md": "d207a30065c17e13efaf5391805e5603e6956633cba5d0a1ff60e276518d9696"
12
+ "battlegrid-strategy-authoring/SKILL.md": "2b6bb9a9f419bae5dd85457f6f89131fd6f09ab218f67a0d9e27cad4072945fe",
13
+ "battlegrid-strategy-authoring/references/strategy-stage-examples.md": "9822cc2bcc8975a3e436c2a960b10e03c95e6e6b4b04bc2206e0ac90688cab66",
14
+ "battlegrid-strategy-doctor/SKILL.md": "e34e055b0cc9b355bc1adeb5d49d464eaa0756ca3f48dc89ca2ccdda94e1311f",
15
+ "battlegrid-strategy-examples/SKILL.md": "baf8f976d1b33c9009f21bb292943798a233464ebe4149f2f887cc40e2bfa5d4",
16
+ "battlegrid-strategy-examples/references/playbooks.md": "2309eb7e8324f563c5b1b51e05da931b37c542484135a2be749eff6ef78aa40f",
17
+ "battlegrid-strategy-examples/references/recipes.md": "3fc3280a854fca924b77f2fe154231e91a0dc779023413597d966cbb1ac88baf",
18
+ "battlegrid-strategy-examples/references/tradingview-ports.md": "fe70a84c700f0cd72b9adf91cafccae2af0db007951afc9be37bc3134142c5a1",
19
+ "battlegrid-trade-analysis/SKILL.md": "3f927b4f9796178526fa1673a2043c5f14358c39aa955de33192ea58641f18fb",
20
+ "battlegrid-trade-proposal/SKILL.md": "e761fc6bddc0d1db79fcb90046d03a18439562c8658de726ec286830edd6369b"
21
21
  }
22
22
  }
@@ -171,7 +171,7 @@ State the blast radius **from server fields, as numbers**, before the confirm fo
171
171
  - **Rebind** — a strategy change is the draft's STRATEGY_BINDING axis: stage `{ strategyId }`, read
172
172
  `get_agent_draft`, and take both strategies from its `impact.rebind` — the strategy it replaces
173
173
  (`fromStrategyName`) and the one it binds (`toStrategyName`, at `toStrategyRevision`). Say that
174
- the target strategy's context modules, signal rules, prose and timeframe **replace** the ones
174
+ the target strategy's report, conditions, trade levels, prose and timeframe **replace** the ones
175
175
  materialized on the agent (this is not a merge), naming both strategies. Agent-owned settings are
176
176
  untouched. The commit checks the new strategy against the coins the radar acts on for this agent;
177
177
  a refusal names the coin and the condition — surface it, never retry it unchanged.
@@ -47,7 +47,10 @@ the enablement path there.
47
47
  1. `list_market_grid_sessions` with status `PENDING` — the sessions still enterable. **The
48
48
  `sessionId` you use comes from here; never fabricate one.**
49
49
  2. `get_market_grid_session` — the coin pool (note each coin's `id`), the entry fee, the pool and
50
- the lock time.
50
+ the session's three instants: `startsAt` (the **Opening Bell** — the open of the one candle it
51
+ scores), `lockAt` (entries close) and `settleAt` (the candle closes). Entries stay open through
52
+ the Opening Bell window, from `startsAt` until `lockAt`, so an entry made inside the window can
53
+ read the candle that closed at the bell; the full candle from `startsAt` is scored either way.
51
54
  3. `get_market_context` for that session — the indicators, rankings and trends the picks will
52
55
  actually be reasoned from.
53
56
  4. `check_market_grid_submission` — **before composing anything.** If a submission already exists,
@@ -102,7 +105,8 @@ reasoning as the player's, and the attribution is part of what was scored.
102
105
 
103
106
  ### 5. After settlement
104
107
 
105
- - A session moves PENDING → LIVE → RESOLVING → SETTLED. Two states sit off that path: CANCELLED
108
+ - A session moves PENDING → LIVE → RESOLVING → SETTLED. It stays PENDING through the Opening Bell
109
+ window and goes LIVE at `lockAt`. Two states sit off that path: CANCELLED
106
110
  (entry fees refunded) and SETTLEMENT_QUARANTINED (settlement exhausted its retries and awaits an
107
111
  operator). Either one is the answer — report it as the status.
108
112
  - `get_market_grid_results` — available only once the session is SETTLED. Before that it returns a
@@ -115,6 +119,22 @@ reasoning as the player's, and the attribution is part of what was scored.
115
119
  the picks, so say that rather than reconstructing one. `list_my_market_grid_entries` is the history
116
120
  across sessions. An agent's decisions are a different record, `get_agent_journal`.
117
121
 
122
+ ## On the arena's session page
123
+
124
+ When the conversation is embedded in the player's Market Grid session page, the round on screen
125
+ arrives as the attached scope, and the session it names is the one in scope.
126
+
127
+ - **Propose, do not submit.** When the player asks for a grid, call `generate_agent_grid` for the
128
+ session in scope (the billed-inference warning in step 3 still applies). The result reaches them
129
+ as a card with **LOAD INTO GRID**, which puts the picks into their own builder as a starting point.
130
+ - **A loaded grid they have not changed is the agent's.** Their builder will not place it as theirs.
131
+ If they want the agent's grid entered as it stands, run step 4: one confirmation, then
132
+ `submit_agent_grid` on their explicit pick, never on free text.
133
+ - **Once they change a pick, the grid is theirs.** They place it themselves from their ticket. Do not
134
+ submit it for them, and do not describe it as the agent's.
135
+ - **A newer generation for the same agent replaces the older card.** The older one reads SUPERSEDED;
136
+ only the newest is what `submit_agent_grid` would enter.
137
+
118
138
  ## Refusals, and what each one means
119
139
 
120
140
  Each is typed and distinguishable. Read the code, do not paraphrase:
@@ -40,6 +40,7 @@ Run these in order. Skip a step only when the player's question makes it irrelev
40
40
  `source: { "kind": "FIELDS", "timeframe": …, "sections": [ … ] }` — no authoring vocabulary is
41
41
  needed. Use `{ "mode": "ranked", "limit": N }` as the coin selection when you have no explicit
42
42
  list. Looping a per-coin tool over N coins costs several times this and returns the same values.
43
+ A refused preview names its recovery in `nextAct`.
43
44
  4. **Coin deep-dive**, when the player named a coin or when one dominates the read: the SAME
44
45
  `preview_strategy_report` call as step 3, with `{ "mode": "explicit", "tickers": ["SOL"] }` as the
45
46
  coin selection and the funding / open-interest / positioning sections chosen — one coin is a
@@ -36,9 +36,8 @@ approves needs no deployment. An Arena deployment enters an agent into a preset'
36
36
  5. **Answering "why isn't it firing?" by paging the journal.** *Cue: any question about why a
37
37
  deployed agent has been quiet — "is it working?", "it hasn't traded all day", "what's blocking
38
38
  it?".* `get_radar_activity_summary` now answers the whole question in one small call — which
39
- cause recurs, how far the score sits from firing, and what just happened — so paging the journal
40
- for it tallies an aggregate the server already computed and re-derives a proximity reading it
41
- already serves. The journal read is for ONE occurrence, or for more rows than the summary's ten.
39
+ cause recurs, how often the pair qualified, and what just happened — so paging the journal for it
40
+ tallies an aggregate the server already computed and re-derives a reading it already serves. The journal read is for ONE occurrence, or for more rows than the summary's ten.
42
41
  → step 5.
43
42
 
44
43
  ## Sequence
@@ -198,18 +197,26 @@ resolver:
198
197
  - `reading.live` is the reading its qualification verdict was built from: the gates with their margins
199
198
  (`qualification`); every entry-lane condition — required, direction-setting, and the ones they
200
199
  reference — with its outcome and its clause values against their thresholds
201
- (`conditions.entries[]`); the allocated signals with their attribution; and the data it lacked
200
+ (`conditions.entries[]`); and the data it lacked
202
201
  (`missingData`). An `UNEVALUATED` entry is a condition this tick could not read, with its
203
202
  `reachReason`. A pair the scan can never read was refused above, so every such cause is one the next
204
203
  sweep can change — report it as the current reading, never as a reason the deployment will not
205
204
  work. `anchorBarStatus` says which bar the conditions read (`live` while it is still forming), and
206
- `scoredBarStart` names the bar the signals and gates were scored on. **A live reading decides
205
+ `scoredBarStart` names the bar the gates were read on. **A live reading decides
207
206
  nothing**: the radar decides at the close, on the closed bar, so say what it reads right now, never
208
207
  that it will fire.
209
208
  - `reading.lastClose` is the one decision the agent's on-duty row names as its last close: `RECORDED`
210
209
  with that bar's close-decision record — the reading it was decided on, or why it was missed —
211
210
  `PENDING` while that record is still being written, or `NONE` when the pair remembers no decision.
212
- For the decisions before it, call `get_radar_close_decisions` (step 5).
211
+ For the decisions before it, call `get_radar_close_decisions` (step 5). Name a close by the served
212
+ `barCloseAt` — on a record's `bar`, on a `PENDING` close and on the on-duty row's
213
+ `closeDecision.last` — and a `DEFERRED` row's bar being decided by `closeDecision.decidingBarStart`;
214
+ never add a timeframe to `barStart`.
215
+ - `reading.sinceClose` is how the live reading moved since the deciding reading, computed by the
216
+ server: the ATR reading's move (`UP`, `DOWN`, `UNCHANGED`), whether the required conditions, the
217
+ trade levels, the condition verdict and the first failing gate changed, and each live condition
218
+ against the deciding entry for its key (`ABSENT`, `NOT_READ`, `UNCHANGED`, `CHANGED`). It is `null` unless `lastClose` is `RECORDED`
219
+ on a reading. Quote it; never compare the two readings yourself.
213
220
 
214
221
  An `UNSCORABLE` entry is an on-duty agent the preview could not read on the coin, with
215
222
  `coinDataStopped` when the coin's data explains why; it never fails the preview. `readings` is null
@@ -304,7 +311,7 @@ Four reads, cheapest first. Stop as soon as the player's question is answered.
304
311
  the agent the pause refused, not to a trade. That is the whole answer while the pause lasts; never
305
312
  send the player to change an agent or a policy for it. Most "is it working?" questions end here.
306
313
  When the question is what ONE on-duty agent of a scanning coin needs to fire — which condition
307
- reads false, how far a gate sits from its threshold — drill into its row
314
+ reads false, how far the ATR reading sits from its floor — drill into its row
308
315
  with `get_agent_coin_qualification({ agentId, coinTickers: [<the coin's ticker>], reading: true })`
309
316
  and read the verdict's `reading` as step 2 of the deploy flow describes it: `live` is what the
310
317
  agent reads now, and `lastClose` is the decision its row names as its last close, with the reading
@@ -313,11 +320,12 @@ Four reads, cheapest first. Stop as soon as the player's question is answered.
313
320
  carries three parts and they answer three different questions, each on its own scope:
314
321
  - `groups` — which cause recurs and how often, over the window the response names. Quote the
315
322
  counts with that window; never sum them across calls.
316
- - `curveDigest` — how FAR the score sits from firing, over the FIRST on-duty agent's ring (the
317
- lowest-numbered slot on duty now, named in `curveAgentName`). This is what
318
- separates "lower the minimum two points and it fires" from "this strategy does not fit this
319
- coin": `bestUnqualifiedScorePercent` against `latestThresholdPercent`. Its `ringStartAt` /
320
- `ringEndAt` describe the ring, NOT the cause window above.
323
+ - `curveDigest` — how often the pair qualified, over the FIRST on-duty agent's ring (the
324
+ lowest-numbered slot on duty now, named in `curveAgentName`): `qualifiedCount` of
325
+ `sampleCount`, and the latest ATR% with how many samples read one. A pair that qualified on no
326
+ sample is one whose strategy does not fit this coin as it trades now; the `groups` above name the
327
+ gate that blocked it. Its `ringStartAt` / `ringEndAt` describe the ring, NOT the cause window
328
+ above.
321
329
  - `recentEvents` — the last ten key events, lean. Deliberately NOT bounded by the cause window, so
322
330
  a pair quiet for longer returns no groups beside populated older rows. That is correct, not a
323
331
  contradiction; each row carries its own `occurredAt`.
@@ -334,7 +342,7 @@ Four reads, cheapest first. Stop as soon as the player's question is answered.
334
342
  `outcome` (`FIRED`, `NOT_QUALIFIED`, `CLAIMED` or `MISSED`), the fire's `fireDisposition` as
335
343
  arbitration settled it, and the `evidence` the bar was decided on — the closed-bar reading's gates
336
344
  with their margins, every condition's outcome with its clause evidence, each condition the scan
337
- could not evaluate with its reach reason, the allocated signals and `missingData` — or, for a
345
+ could not evaluate with its reach reason, and `missingData` — or, for a
338
346
  `MISSED` bar, the close step's own answer: the bar never settled, an input was not on its due bar,
339
347
  or the window passed. An `outcome` of `FIRED` says the bar qualified and its agent was offered the
340
348
  coin's fire; `fireDisposition` says what the fire came to — `FIRED` when a decision was enqueued,
@@ -22,7 +22,7 @@ axis you omit keeps the value the draft already has.
22
22
  "draftVersion": 0,
23
23
  "axes": {
24
24
  "DEFAULT_SLOT": {
25
- "defaultSlot": { "agentId": "<AGENT_ID>", "minConfidence": null, "entryStrategy": "STANDARD" }
25
+ "defaultSlot": { "agentId": "<AGENT_ID>", "minConfidence": null }
26
26
  }
27
27
  }
28
28
  }
@@ -42,7 +42,6 @@ axis you omit keeps the value the draft already has.
42
42
  {
43
43
  "agentId": "<AGENT_ID>",
44
44
  "minConfidence": null,
45
- "entryStrategy": "STANDARD",
46
45
  "conditions": [{ "kind": "regime", "regimes": ["bull_expansion", "bull_ranging"] }]
47
46
  }
48
47
  ]
@@ -68,7 +67,6 @@ session occurrence, never both.
68
67
  {
69
68
  "agentId": "<AGENT_ID>",
70
69
  "minConfidence": 0.6,
71
- "entryStrategy": "TWO_LOOK",
72
70
  "conditions": [
73
71
  { "kind": "session_start", "startTimes": ["14:00:00", "15:00:00"], "days": [1, 2, 3, 4, 5] }
74
72
  ]
@@ -93,7 +91,6 @@ session occurrence, never both.
93
91
  {
94
92
  "agentId": "<AGENT_ID>",
95
93
  "minConfidence": null,
96
- "entryStrategy": "STANDARD",
97
94
  "conditions": [
98
95
  { "kind": "regime", "regimes": ["volatile"] },
99
96
  { "kind": "session_start", "startTimes": ["14:00:00"], "days": [1, 2, 3, 4, 5] }
@@ -15,12 +15,13 @@ 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 *drafted* rules,
18
+ Nobody noticed until the results looked wrong. You prevent this by showing the *drafted* conditions,
19
19
  as the server's own draft read serves them, next to their *locked* picks, before committing, and
20
20
  naming any contradiction yourself.
21
21
  2. **Silent zero-trigger.** A strategy was built that could never fire, and produced nothing for
22
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
+ its diagnostics before committing, and flagging a draft that shows no passing conditions or
24
+ warns `NO_ENTRY_CONDITION`.
24
25
 
25
26
  3. **Silent substitution.** A player asked for a strategy that triggers on the daily chart and
26
27
  executes on the 4-hour. The grammar carries no such semantics. Instead of saying so, the flow
@@ -100,13 +101,19 @@ anywhere; if the two ever disagree, you have created the exact ambiguity this st
100
101
  ### 3. Discover the grammar — never guess it
101
102
 
102
103
  `list_strategy_categories` → `list_strategy_vocabulary` → `get_strategy_column_contract` and
103
- `get_strategy_section_template` → `list_strategy_signals`, plus
104
- `get_strategy_signal_definition` for each signal you intend to use.
104
+ `get_strategy_section_template`.
105
105
 
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. 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.
106
+ Compose sections, columns and conditions **only** from vocabulary returned in this conversation. A
107
+ field you remember from another strategy is not discovery.
108
+
109
+ **Conditions are the only deterministic entry gate.** A condition gates an entry when it is
110
+ `required` or carries a verdict (UP, DOWN or NEITHER); a building block — neither required nor a
111
+ verdict carrier — gates nothing, and an exit rule never counts. A strategy whose entry conditions
112
+ include no required and no verdict-carrying condition never routes a trade: every coin fails first
113
+ with `NO_ENTRY_CONDITION`, and its draft carries the warning of the same name. It stays a valid
114
+ strategy — Market Grid reads it as context — so a strategy the player means to trade needs at least
115
+ one. Before any condition is read, a coin must clear the ATR floor, `minAtrPct`, the
116
+ TRADE_LEVEL_POLICY dial beside the stop-loss band.
110
117
 
111
118
  **Read the answer, not just the call.** Each of these returns one field that decides a composition
112
119
  question you would otherwise guess — and a refusal you would otherwise earn:
@@ -150,25 +157,17 @@ question you would otherwise guess — and a refusal you would otherwise earn:
150
157
  transform (and a chained transform) reads its series: the read shape, the window's unit, the price
151
158
  basis and what an absent bar does. `seriesHome` says where the metric's series is kept — `candle`,
152
159
  `history`, or `null` when the metric has no series, which is why a series transform does not
153
- compose on it. Window and offset carry a declared `minimum` and no fixed maximum; the lookback
154
- cap is the bound.
160
+ compose on it. Window and offset carry a declared `minimum` and a served `maximum` on each metric's
161
+ transform entry — the largest value whose read size fits the lookback cap, or `null` when none
162
+ does. Stage at most that maximum.
155
163
  - `get_metric_construction_hints` → `rankOrderings`. Present only when rank is composable on that
156
164
  metric, already range-gated server-side — read the offered set rather than deriving one from
157
165
  the metric's native output.
158
166
 
159
167
  For full-surface composition patterns — custom and benchmark sections, condition trees with
160
- verdicts and enforcement gates, weight pyramids and gate math, trade-level and
161
- position-management presets, worked desk-grade playbooks — activate `strategy-examples`. It
162
- teaches what to compose; this skill stays the authority on the flow.
163
-
164
- `derive_strategy_rule_view` belongs here, at composition time, and only here: it reports report
165
- membership and registry-default allocations for sections and rows you are about to stage. It reads
166
- no draft and no strategy, so it can never stand in for the review in step 5. Its suggestions and
167
- reset-to-default choices change only what you stage next — no tool applies one on its own.
168
-
169
- `simulate_aggregate_score` does **not** belong here. It is a review tool (step 5), and running it
170
- now answers a question about rows you have not staged, not about the draft the player will be
171
- asked to approve.
168
+ verdicts and `required` enforcement, the trade-level policy with its ATR floor, position-management
169
+ presets, worked desk-grade playbooks — activate `strategy-examples`. It teaches what to compose; this
170
+ skill stays the authority on the flow.
172
171
 
173
172
  ### 4. Stage, and iterate on the diagnostics
174
173
 
@@ -184,24 +183,24 @@ two stages in parallel against one draft. Complete stage payloads showing the en
184
183
  stage; the response carries the id minted for it, which every later call names. A create needs
185
184
  IDENTITY (`{ name, description, tagline }`) and TIMEFRAME_PROFILE (`{ timeframe }`). A create with
186
185
  no REPORT starts from the platform's starting report (Price Action, RSI, MACD and Moving Averages),
187
- one with no ENTRY takes the seed entry, and the rule rows you stage overlay a creation seed in
188
- which every signal is Off.
186
+ and one with no ENTRY takes the seed entry. A create with no CONDITIONS declares no entry gate and
187
+ will not trade until one is staged.
189
188
 
190
189
  **An UPDATE carries only the axes that change.** Axes you omit keep the values the draft has, and
191
190
  an axis the draft does not hold is the committed strategy's. Each axis you send is written WHOLE —
192
- a REPORT is the complete section list, CONDITIONS the complete set — except SIGNAL_RULES, whose
193
- rows replace the drafted rows for the same `signalId` and keep every other one. Restating an axis
191
+ a REPORT is the complete section list, CONDITIONS the complete set. Restating an axis
194
192
  you are not changing is never required, changes nothing about the result, and the player pays for
195
193
  every byte of it on this call and on every later step of the conversation. Send the axes you are
196
194
  changing; send no other axis.
197
195
 
198
- **A rule row is complete.** Every staged row carries `signalId`, `allocation` and `required`;
199
- `params` only when the thresholds change, and omitting it keeps the stored ones byte-identically.
200
- "Raise volume_surge to Critical" is one row with `allocation: 3` and `required` exactly as it
201
- stands now — read it from the draft's SIGNAL_RULES row when the draft holds one, otherwise from
202
- `get_strategy`. Never set `required` from memory, and never change it unless the player asked about
203
- the Required flag: a wrong value there is how a scoring signal silently becomes a mandatory trade
204
- gate. Stage no row for a signal you are not changing.
196
+ **A whole axis restates what it keeps.** "Raise the ATR floor to 0.8%" is one TRADE_LEVEL_POLICY
197
+ stage carrying all four of its dials — `minStopLossAtrMultiple`, `maxStopLossAtrMultiple`,
198
+ `minRiskRewardRatio` and `minAtrPct` — the three you are not changing exactly as they stand now:
199
+ read them from the draft's TRADE_LEVEL_POLICY when the draft holds it, otherwise from
200
+ `get_strategy`. The same holds for a condition: CONDITIONS carries every condition, each with its
201
+ `required` flag and verdict as they stand. Never set `required` or a verdict from memory, and never
202
+ change either unless the player asked: a wrong value there is how a building block silently becomes
203
+ a mandatory trade gate, or a gate silently disappears.
205
204
 
206
205
  **Read the diagnostics every stage returns.** Past its checks of shape — an undeclared key, a
207
206
  parameter beside `ON_CANDLE_CLOSE`, a coin that names nothing — a stage refuses nothing for being
@@ -210,9 +209,9 @@ are where you learn what the commit would do:
210
209
 
211
210
  - `errors` — the refusals the commit would raise, each with its `field` and `details` naming the
212
211
  `path`, the value it received and the `allowedDomain` it accepts. Fix the axis and stage again.
213
- - `warnings` and `mismatches` — observations that never refuse. `NO_SIGNAL_ACTIVE` means the
214
- strategy scores nothing and will never route a trade; a mismatch means the report and the
215
- weights disagree. Fix each one, or carry it into the review as something to explain.
212
+ - `warnings` — observations that never refuse. `NO_ENTRY_CONDITION` means the strategy declares no
213
+ required and no verdict-carrying entry condition, so it will never route a trade. Fix it, or carry
214
+ it into the review as something to explain.
216
215
 
217
216
  An empty `errors` is not a promise: the strategy quota, the name and capital feasibility are
218
217
  decided only by the commit itself.
@@ -237,7 +236,7 @@ Once the stage's diagnostics carry nothing you cannot explain, read the draft wi
237
236
  `get_strategy_draft`. Everything here comes from that read:
238
237
 
239
238
  - **What will actually run.** Its `diff` — every drafted axis with its `live` and drafted value
240
- and the field-level `changes` between them, the drafted signal-rule rows among them — beside the
239
+ and the field-level `changes` between them, the drafted conditions among them — beside the
241
240
  picks they locked in step 2. **If any drafted row or diff entry contradicts a locked pick, say so
242
241
  in words before you ask for anything.** Do not make them spot it.
243
242
  - **All of what the commit publishes.** The diff names every axis the draft holds, including
@@ -250,23 +249,16 @@ Once the stage's diagnostics carry nothing you cannot explain, read the draft wi
250
249
  register with every coin's verdict, and the verdict tally; ask for `"detailed"` only when you need
251
250
  each coin's full evaluation or the addressable headers (`authoring`). A preview is bounded by a
252
251
  deadline and a result-character cap, both served by discovery as `previewExecutionLimits`
253
- (`deadlineMs`, `maxResultChars`); one over either is refused whole, never truncated — narrow the
254
- cohort and preview again. Support it
255
- with `get_coin_signal_preview` on the locked universe's main coin(s). The preview's
256
- `coinSelection` is its cohort, never strategy state: no strategy has one and `get_strategy` will
257
- not return one, so choose it — a short explicit list of the tickers the change is about for a
258
- single-gate edit, a `ranked` cohort for a broad one. Any reasonable cohort is correct.
259
- - **A routing what-if**, optionally, via `simulate_aggregate_score` — **after the draft read, never
260
- before it.** This is a calculator, not a verdict: it computes over whatever inputs you hand it.
261
- Feed it what the commit would carry — the gate and the allocations as the read serves them (the
262
- drafted value where the draft holds the axis, the committed one where it does not) and the
263
- per-signal scores from the preview you just read — and show those inputs beside its output so a
264
- copy slip is visible on the card itself.
265
-
266
- **Flag before confirming** if the preview shows no passing conditions, the coin preview shows
267
- zero triggered signals, the simulation reports `wouldRoute: false`, or the diagnostics warn
268
- `NO_SIGNAL_ACTIVE`. Any one of those means the strategy probably never fires — ask whether to
269
- revise rather than presenting it as healthy.
252
+ (`deadlineMs`, `maxResultChars`); one over either is refused whole, never truncated, and the
253
+ refusal carries `nextAct: narrow` — preview again asking for less, in the order the tool's
254
+ description gives. The preview's `coinSelection` is its cohort, never strategy state: no strategy
255
+ has one and `get_strategy` will not return one, so choose it — a short explicit list of the
256
+ tickers the change is about for a single-condition edit, a `ranked` cohort for a broad one. Any
257
+ reasonable cohort is correct.
258
+
259
+ **Flag before confirming** if the preview shows no passing conditions or the diagnostics warn
260
+ `NO_ENTRY_CONDITION`. Either one means the strategy probably never fires — ask whether to revise
261
+ rather than presenting it as healthy.
270
262
 
271
263
  **State the impact as numbers, not buried in prose.** The read's `impact` carries:
272
264
 
@@ -314,13 +306,13 @@ Prose never triggers a commit. The same holds for an answer typed into the form'
314
306
  answer-in-your-own-words box: it is the player's words in an answer slot, not a confirming pick,
315
307
  so treat it exactly as you would free text in the chat.
316
308
 
317
- Do not pre-check ownership, viability, quota or the name before calling. The server is the only
309
+ Do not pre-check ownership, validity, quota or the name before calling. The server is the only
318
310
  authority on all of them; your job is to react to what it returns.
319
311
 
320
- **Report the change from the receipt.** The commit returns the committed `strategy` and, when
321
- signal rules moved, `ruleChanges` with the server's own `before` and `after` for each edited
322
- signal. State those. Never describe a prior value from memory or from an earlier read — the
323
- receipt is the only record that cannot be stale.
312
+ **Report the change from the read and the receipt.** The commit returns the committed `strategy`.
313
+ State each change as its live value in the read the player confirmed against its value in the
314
+ receipt's strategy. Never describe a value from memory or from any other read — those two are the
315
+ only records that cannot be stale.
324
316
 
325
317
  **Offer to discard a draft only on the player's explicit word**, never on your own judgement that
326
318
  it looks stale, and never batched into another act. `get_strategy_draft` is the read of what a
@@ -334,11 +326,12 @@ removed. The unsaved values are gone afterwards and there is no other copy.
334
326
 
335
327
  `fork_strategy`, `restore_strategy`, `archive_strategy`, `discard_strategy_draft` and
336
328
  `preview_strategy_report` are part of this flow. Every change to a strategy's content — a single
337
- tuned rule included — is a staged draft committed with `commit_strategy_draft`; none of the other
338
- verbs writes content.
329
+ tuned condition or dial included — is a staged draft committed with `commit_strategy_draft`; none of
330
+ the other verbs writes content.
339
331
 
340
- - **Tuning a single rule** is one SIGNAL_RULES row staged (step 4), read, confirmed and committed.
341
- State how many agents are bound, and that the change reaches every one of them immediately.
332
+ - **Tuning a single condition or dial** is its axis staged whole (step 4), read, confirmed and
333
+ committed. State how many agents are bound, and that the change reaches every one of them
334
+ immediately.
342
335
  - **Forking** — `fork_strategy` takes the `strategyId`, the exact `sourceRevision` to copy and an
343
336
  optional `name`, and returns a NEW create draft's `strategyId` and `draftVersion`. **No strategy
344
337
  exists yet.** Read the draft with `get_strategy_draft` — every authored axis equals the source
@@ -352,10 +345,9 @@ verbs writes content.
352
345
  - **Restoring** — find the archived strategy with `list_strategies` and `get_strategy` with
353
346
  `includeInactive: true`, which add the player's own strategies in any state; another player's
354
347
  PRIVATE strategy stays hidden either way. `restore_strategy` with the `strategyId` and
355
- `expectedRevision` brings back unchanged, already-viable content and keeps the player's draft,
356
- re-based onto the restored revision. Content that is not viable is
357
- refused with `REPAIR_REQUIRED` and stays archived: stage the repair into the strategy's draft and
358
- commit it — that commit restores it, and its read says `operation: RESTORE`.
348
+ `expectedRevision` brings back the unchanged content and keeps the player's draft, re-based onto
349
+ the restored revision. To change the content as it comes back, stage the change into the
350
+ strategy's draft and commit it — that commit restores it, and its read says `operation: RESTORE`.
359
351
 
360
352
  **Your `ask_user` is the approval, and the server does not repeat it.** No strategy verb takes a
361
353
  confirmation flag. So never call `commit_strategy_draft`, `archive_strategy`, `restore_strategy` or
@@ -369,7 +361,8 @@ offered, and nothing else is.
369
361
 
370
362
  Each refusal is a specific typed code, and a refusal of a draft's stage or commit names its next
371
363
  act in `details.nextAct` — `get_draft` or `stage`; a moved or contested draft names `get_draft`
372
- from any tool. Read it and take the cheapest correct step — never retry the same call blindly.
364
+ from any tool, and a refused preview names `narrow`. Read it and take the cheapest correct step —
365
+ never retry the same call blindly.
373
366
 
374
367
  - **`DRAFT_VERSION_MOVED`** (`nextAct: get_draft`) — the draft changed after your read: the
375
368
  player's form saved an edit, another surface staged, or a human-paced review outlived it. Read
@@ -385,8 +378,8 @@ from any tool. Read it and take the cheapest correct step — never retry the sa
385
378
  - **A validation error** (`nextAct: stage`) — the error the diagnostics named, with its own
386
379
  `field` and `details`. Nothing was written. Return to step 4: fix the axis, stage, read, and
387
380
  confirm again.
388
- - **A refusal with no `nextAct`** — the strategy quota (`FORBIDDEN`), a name already in use,
389
- `REPAIR_REQUIRED`, viability, or a `CONFLICT` whose `details.reason` is `RADAR_DEPLOYMENT_MOVED`. The draft is
381
+ - **A refusal with no `nextAct`** — the strategy quota (`FORBIDDEN`), a name already in use, or a
382
+ `CONFLICT` whose `details.reason` is `RADAR_DEPLOYMENT_MOVED`. The draft is
390
383
  untouched. Clear the cause with the player — a rename is an IDENTITY stage, which makes a new
391
384
  version to read and confirm — then commit the draft they confirmed. A moved radar deployment is
392
385
  a race, not a decision: read and commit again.
@@ -4,8 +4,8 @@
4
4
  checked in CI against the live `stage_strategy_draft` schema; a create example is also checked for the axes a new
5
5
  strategy needs. Its shape is current.
6
6
 
7
- These examples show the envelope and the small axes. A full composition (report sections, conditions, signal
8
- rules) is in `strategy-examples`' playbooks, which have their own compile gate.
7
+ These examples show the envelope and the small axes. A full composition (report sections, conditions, trade
8
+ levels) is in `strategy-examples`' playbooks, which have their own compile gate.
9
9
 
10
10
  Every `<UPPER_SNAKE>` value is a placeholder: `<STRATEGY_ID>` is the id a read returned. Never send a placeholder as
11
11
  written, and never invent an id. `draftVersion` is the version `get_strategy_draft` returned: 0 when there was no
@@ -33,9 +33,10 @@ and TIMEFRAME_PROFILE before it can be created.
33
33
  }
34
34
  ```
35
35
 
36
- ## Change an existing strategy's setup gates
36
+ ## Change an existing strategy's trade levels
37
37
 
38
- SETUP_GATES is sent whole: all three gates, even when only one changes.
38
+ TRADE_LEVEL_POLICY is sent whole: all four dials, even when only one changes. `minAtrPct` is the ATR% volatility floor
39
+ a coin must clear before any condition is read; the other three are the stop-loss band and the reward-to-risk floor.
39
40
 
40
41
  ```json stage_strategy_draft
41
42
  {
@@ -43,7 +44,12 @@ SETUP_GATES is sent whole: all three gates, even when only one changes.
43
44
  "strategyId": "<STRATEGY_ID>",
44
45
  "draftVersion": 2,
45
46
  "axes": {
46
- "SETUP_GATES": { "minAggregateScore": 60, "minRequiredCount": 1, "minAtrPct": 0.5 }
47
+ "TRADE_LEVEL_POLICY": {
48
+ "minStopLossAtrMultiple": 1,
49
+ "maxStopLossAtrMultiple": 2,
50
+ "minRiskRewardRatio": 1.5,
51
+ "minAtrPct": 0.8
52
+ }
47
53
  }
48
54
  }
49
55
  }
@@ -50,22 +50,26 @@ Three reads, and they are not interchangeable:
50
50
 
51
51
  ### 2. Diagnose from typed sources
52
52
 
53
- - **The one vocabulary is `TradeEvaluationAttemptReasonCode`** — 25 members, two of them
53
+ - **The one vocabulary is `TradeEvaluationAttemptReasonCode`**, two of its members
54
54
  `@deprecated` and historical-only (`TRADING_MODE_OFF`, `TRADING_MODE_INELIGIBLE`): if either
55
55
  turns up, it is an old row, not a live cause, and you say so. Do not translate a code into a
56
56
  different enum's wording, and do not try to unify the platform's overlapping reason vocabularies
57
57
  — they describe different stages and merging them invents a cause.
58
- - Render every code through its display meta. A raw `SETUP_GATES` or `OPEN_POSITION_CONFLICT` on
58
+ - Render every code through its display meta. A raw `NO_ENTRY_CONDITION` or `OPEN_POSITION_CONFLICT` on
59
59
  screen is a system identifier leaking into an explanation.
60
60
  - **`get_agent_decision_context` is keyed by COIN**, not by agent. Use it for "why did nothing
61
61
  happen on SOL", once you know which coin the blocks are about.
62
62
  - **`get_agent_coin_qualification` answers the forward-looking half.** The reason codes above say
63
63
  why an agent did NOT trade in the past; this says whether a coin would route for it RIGHT NOW,
64
- and which gate stops it — candidate levels, aggregate score, required-signal count, the ATR%
65
- volatility floor and the agent's own required conditions, without spending an LLM call. Read the
66
- four-member verdict as written: `NOT_ENFORCED` means the agent's own threshold switches the gate
67
- off, `UNMEASURABLE` means the input was missing and the gate fail-opened. Neither is a pass, and
64
+ and which gate stops it — the strategy's entry condition, candidate levels, the ATR% volatility
65
+ floor and the strategy's required conditions and verdict, without spending an LLM call. Read the
66
+ four-member verdict as written: `NOT_ENFORCED` means the strategy declares nothing for that gate to
67
+ enforce, `UNMEASURABLE` means the input was missing and the gate fail-opened. Neither is a pass, and
68
68
  reporting either as "cleared" is the conflation the verdict vocabulary exists to prevent.
69
+ - **`NO_ENTRY_CONDITION` is a property of the strategy, not of the market.** It fails every coin
70
+ first, in both directions: the bound strategy declares no required and no verdict-carrying entry
71
+ condition, so it never routes a trade. Say so once, for every coin at once, and route the fix — a
72
+ required or verdict condition — to the strategy-authoring flow; no coin or radar change clears it.
69
73
  - **A failing condition comes back as a KEY — resolve it.** `requiredConditions.failedKeys` names
70
74
  gates like `LOCATION_OK`: an identifier, not an explanation. Read the agent's bound strategy with
71
75
  `get_strategy` (the `strategyId` is on `get_intelligence_agent`), find the matching
@@ -1,18 +1,17 @@
1
1
  ---
2
2
  name: battlegrid-strategy-examples
3
- description: Full-surface composition patterns for the strategy studio — validated desk-grade examples of custom report sections, benchmark sections, condition trees with verdicts and enforcement gates, tiered signal weights, routing gates, ATR trade levels, and position management. Activate beside strategy-authoring whenever a strategy is being composed or upgraded beyond a basic template.
3
+ description: Full-surface composition patterns for the strategy studio — validated desk-grade examples of custom report sections, benchmark sections, condition trees with verdicts and required enforcement, the entry-condition rule, ATR trade levels with the ATR floor, and position management. Activate beside strategy-authoring whenever a strategy is being composed or upgraded beyond a basic template.
4
4
  ---
5
5
 
6
6
  # Strategy Studio — full-power composition patterns
7
7
 
8
8
  `strategy-authoring` owns the flow (evidence → locked spec → discover → stage → review →
9
9
  commit). This skill owns **what to compose**: a default build — a few platform sections, no
10
- conditions, untouched weights — wastes the studio. The playbooks below are compiled in CI, so their
10
+ conditions, untouched trade levels — wastes the studio, and one with no entry condition never trades. The playbooks below are compiled in CI, so their
11
11
  shapes are binding in the sense that matters — they are checked, not merely asserted. Loose tokens
12
12
  elsewhere in this file are not covered by that gate, and vocabulary moves with deploys, so discovery
13
- in the conversation stays the authority — prefer what `list_strategy_vocabulary`,
14
- `get_strategy_column_contract`, and `get_strategy_signal_definition` return over anything
15
- printed here, and read exact headers from a `detail: "detailed"` preview's
13
+ in the conversation stays the authority — prefer what `list_strategy_vocabulary` and
14
+ `get_strategy_column_contract` return over anything printed here, and read exact headers from a `detail: "detailed"` preview's
16
15
  `authoring.conditionColumns` before conditioning on them.
17
16
 
18
17
  ## The full-power checklist
@@ -22,14 +21,12 @@ Before committing a CREATE, every "no" here is a decision to state, not an omiss
22
21
  1. At least one **custom section** whose columns encode the thesis — not only platform modules.
23
22
  2. **Conditions** encode the entry logic: building blocks (`verdict: null`) + verdict carriers,
24
23
  and at least one `required: true` condition vetoing obvious disqualifiers **before any
25
- billing or LLM call**.
26
- 3. **Every signal meant to score is named in `rules`** with a deliberate tier — unnamed signals
27
- keep server defaults (Off on a CREATE). Verify against the rule rows the draft read serves,
28
- never assume.
29
- 4. **Gates** (`minAggregateScore`, `minRequiredCount`, `minAtrPct`) are computed against the
30
- chosen weight budget, not guessed.
31
- 5. **Trade levels + position management** match the setup's geometry and holding period.
32
- 6. `marketReadText` states standing orders with `{...}` markers so live values render inline.
24
+ billing or LLM call**. They are the only deterministic entry gate: with no required and no
25
+ verdict-carrying entry condition the strategy never routes a trade (`NO_ENTRY_CONDITION`).
26
+ 3. **The ATR floor** (`minAtrPct`) is set for the coins and timeframe the thesis trades, not left
27
+ at the default by accident — a coin below it is refused before any condition is read.
28
+ 4. **Trade levels + position management** match the setup's geometry and holding period.
29
+ 5. `marketReadText` states standing orders with `{...}` markers so live values render inline.
33
30
 
34
31
  ## Header grammar (system-generated — never named by the author)
35
32
 
@@ -45,6 +42,12 @@ Before committing a CREATE, every "no" here is a decision to state, not an omiss
45
42
  | `maxShare` wN | `<code>_maxShare` | `volBase_ltf_maxShare` |
46
43
  | `classifyZone` / `classifyState` | `<code>_zone` / `<code>_state` | `RSI14_zone`, `ADX_state` |
47
44
  | `levelInteraction` | `<code>_lvl`, `<code>_lvl_b<N>` at a buffer of N bps | `bbUpper_lvl`, `bbUpper_lvl_b25` |
45
+ | any, stored `"bars": "all"` | `<code>_dev`, then the transform's suffix | `RSI14_dev_t1` |
46
+ | `value` at `offset` N > 0 | `<code>_o<N>` | `RSI14_1d_o1` |
47
+
48
+ The code carries its tokens in this order: `<code>[_<tf>][_dev][_o<N>]`, then the transform's suffix.
49
+ `_dev` follows the STORED selector — the author chose Developing — whatever bar set the column then
50
+ reads; `_o<N>` appears on a `value` at offset N > 0.
48
51
 
49
52
  Non-anchor rungs affix `_ltf` (lower) / `_htf` (regime): `MAalign_htf`,
50
53
  `zones_htf_support_dist`. Chains are bounded at two: inner `distance`/`spread` → outer
@@ -56,11 +59,12 @@ when the strategy timeframe changes — `regime` is the anchor's ladder successo
56
59
  anchor). *Pinned* (`{abs: "<tf>"}`) is fixed, ignores anchor retunes, suffixes the literal
57
60
  (`RSI14_1d`, `dist_SMA200_1d`, `MAalign_1d` — validated), and binds to discovery's
58
61
  `rankedTimeframes`, a **superset** of the authorable anchor set — `{abs: "1d"}` is valid while
59
- `1d` is not an anchor. `offset: 1` on a pinned `value` column reads the last **closed** bar of
60
- that timeframe (`RSI14[t - 1]`) — the deterministic daily-close read; offset 0 reads the
61
- forming bar (provisional), and offset does not change the header, so one offset per
62
- `metric × timeframe` per section. **Daily-strategy pattern:** anchor 4h, pinned-1d thesis
63
- columns at `offset: 1`, `required: true` daily conditions gating every carrier, anchor-rung
62
+ `1d` is not an anchor. `offset` steps back inside the bar set the Read selector admits, counted
63
+ from the newest bar that set admits, and suffixes the header `_o<N>` (`RSI14_1d_o1`). A pinned
64
+ column above the strategy timeframe reads Confirmed, so its offset 0 is already the newest
65
+ **completed** bar of that timeframe — the deterministic daily-close read — and offset 1 is the
66
+ day before it. **Daily-strategy pattern:** anchor 4h, pinned-1d thesis columns with
67
+ `"bars": "closed"` at offset 0, `required: true` daily conditions gating every carrier, anchor-rung
64
68
  columns only for entry timing and risk — daily inputs then move once per daily close while
65
69
  stops and time decay keep managing intraday. **Benchmark sections** (`benchmarkTicker: "BTC"`,
66
70
  required-nullable on every custom section) read the benchmark's values on every row — the
@@ -156,7 +160,16 @@ Recipes — each one clause:
156
160
  before billing. And the RESOLVED verdict binds entry DIRECTION: `UP` admits long setups only,
157
161
  `DOWN` short only, and `NEITHER`/`UNRESOLVED` admit none — the refused side is absent from the
158
162
  setups block and from the `decide_trade` contract, not merely discouraged in them. A strategy that
159
- declares no verdict-carrying condition resolves `null` and constrains nothing.
163
+ declares no verdict-carrying condition resolves `null` and constrains no side.
164
+
165
+ **A strategy without an entry condition never routes.** An entry condition gates when it is
166
+ `required: true` or carries a verdict (`UP`, `DOWN` or `NEITHER`); a building block gates nothing,
167
+ and an exit rule never counts. A strategy whose conditions include neither never trades: every coin
168
+ fails first with `NO_ENTRY_CONDITION`, before the trade levels, the ATR floor or any condition is
169
+ read, and its draft carries the `NO_ENTRY_CONDITION` warning. It stays a valid strategy — Market Grid
170
+ reads it as context — so this is a choice to state, never an accident. When the agent decides a
171
+ routed trade, its `decide_trade` call cites 1–8 of the evaluated entry conditions in
172
+ `conditionChecklist`, and only a condition that read TRUE may be cited as `CONFIRM`.
160
173
 
161
174
  A verdict carrier must read no DEVELOPING bar. A verdict is refused over any closure that reads a
162
175
  column selecting Developing above the strategy timeframe (`CONDITION_VERDICT_READ_ILLEGAL`). The
@@ -461,7 +474,7 @@ bar whose close decides an entry is the strategy's OWN timeframe.
461
474
 
462
475
  **Every trigger is decided at the close of the strategy's own bar — there are three, and the close
463
476
  is the only entry clock.** The newest completed bar is read on the closed basis — every one-close
464
- condition resolves on that bar and the scorecard reads its close — and a reading that still qualifies
477
+ condition resolves on that bar and the gates read its close — and a reading that still qualifies
465
478
  fires at that close. A bar that does not qualify decides nothing and is not revisited. The fill lands
466
479
  at the next tick, and the platform refuses it if the market has already run past its own drift budget
467
480
  from that close. A fourth value, `AT_SIGNAL`, is readable on strategies authored before this contract
@@ -505,45 +518,16 @@ column reaches any other timeframe by pinning it (`timeframe: { abs: '4h' }`). `
505
518
  than omitting them, because the section is rebuilt whole on save and an omitted key clears the
506
519
  author's value silently. On a CREATE, omit `sectionKey` — it is derived from the section itself.
507
520
 
508
- ## Signal rules
509
-
510
- `{ signalId, allocation, required, params }` — one entry per signal you want scoring.
511
- `allocation` is the tier (0–3) and `params` replaces canonical defaults only when present. Staged
512
- into the draft's SIGNAL_RULES axis, every row is complete — `allocation` and `required` on each —
513
- and replaces the drafted row for its signal while every other row is kept.
514
-
515
- ## Signal weights and gate math
516
-
517
- Tiers: 0 Off · 1 Normal · 2 Important · 3 Critical.
518
-
519
- ```
520
- aggregateScore = Σ(score × allocation) / Σ(allocation) over triggered signals
521
- ```
522
-
523
- Weights are relative — build a pyramid: 1–2 Critical (thesis, usually `required`), 2–4
524
- Important (independent confirmation, different modules), 1–3 Normal (context), rest Off so
525
- noise cannot dilute the average. Gate check: with 3/2/2/1 weights, Critical + one Important at
526
- score 1.0 → (3+2)/8 = 0.625, so a 0.6 gate means "thesis plus one confirmation".
527
- `simulate_aggregate_score` does this arithmetic from the draft's values at review time.
528
- `required: true` counts the signal toward `minRequiredCount` when triggered; at
529
- `allocation: 0` it is rejected (contract 34). `params` replace canonical defaults only when
530
- present — read `get_strategy_signal_definition({ signalId, timeframe })` before tuning (e.g.
531
- `rsi_overbought {"threshold": 65}` for a fade book; `volume_surge {"multiplier": 1.5}`).
532
- `derive_strategy_rule_view` shows which signals a draft report feeds — weighting a signal the
533
- report never feeds is dead weight.
534
-
535
- ## Routing gates
536
-
537
- `{ minAggregateScore, minRequiredCount, minAtrPct }` — whether a scored setup may route to a
538
- trade at all. `minAggregateScore` 0–1 · `minRequiredCount` 0–20 · `minAtrPct` is the dead-market
539
- floor, with bounds from `get_trading_config_catalog`.
540
-
541
521
  ## Trade levels
542
522
 
543
- `{ minStopLossAtrMultiple, maxStopLossAtrMultiple, minRiskRewardRatio }` — where stops and
544
- targets may sit. `minStopLossAtrMultiple < maxStopLossAtrMultiple` (≤ the 3×ATR structural cap),
545
- `minRiskRewardRatio` within the served range. Sizing is risk-budget based — a wider stop means a
546
- smaller position, never more risk.
523
+ `{ minStopLossAtrMultiple, maxStopLossAtrMultiple, minRiskRewardRatio, minAtrPct }` — where stops
524
+ and targets may sit, and how much a coin must move before it is worth trading at all.
525
+ `minStopLossAtrMultiple < maxStopLossAtrMultiple` (≤ the 3×ATR structural cap), `minRiskRewardRatio`
526
+ within the served range. `minAtrPct` is the ATR floor: a coin whose ATR% sits below it is refused
527
+ (`ATR_VOLATILITY_BELOW_MIN`) before any condition is read, with bounds from
528
+ `get_trading_config_catalog`; it is multiplied with `maxStopLossAtrMultiple` in the capital check, so
529
+ a high floor with a wide stop needs more capital per trade. The axis is staged whole — all four.
530
+ Sizing is risk-budget based — a wider stop means a smaller position, never more risk.
547
531
 
548
532
  ## Position management
549
533
 
@@ -583,7 +567,7 @@ rejects an `offset`) belongs in prose above — those are permanent. A claim tha
583
567
 
584
568
  ## Where the worked material lives
585
569
 
586
- This skill's body is the contract — the axes, the header grammar, how conditions and weights behave,
570
+ This skill's body is the contract — the axes, the header grammar, how conditions and trade levels behave,
587
571
  and the absence section above. The worked material is disclosed on demand, so it costs nothing until
588
572
  you ask for it. Read a reference with `read_skill_reference` when you reach the work it covers:
589
573
 
@@ -26,11 +26,8 @@ Custom `Squeeze Scan` (no `sectionKey` — this is a CREATE): `BB_WIDTH_PCT valu
26
26
  custom section already carries them.) Conditions: `LIQUID_FLOOR` (required —
27
27
  `vol24hUsd gte 25000000`); `SQUEEZE_ON` building block (`bbWidthPct_rank_lo lte 10` AND
28
28
  `ADX lt 20`); `BREAK_UP` verdict UP (ref SQUEEZE_ON + `closeChg gt 0` + `RVOL gte 1.5` +
29
- `pctB gte 0.85`); `BREAK_DOWN` verdict DOWN (mirror with `pctB lte 0.15`). Rules:
30
- `bollinger_squeeze` 3 required · `volume_surge` 2 required `{"multiplier":1.5}` ·
31
- `volatility_atr_expanding` 2 · `sr_resistance_break` 2 · `sr_support_break` 2 ·
32
- `bollinger_upper_touch` 1 · `bollinger_lower_touch` 1 · `trend_adx_ranging` 1. Gates
33
- 0.55 / 2 / 0.8. Levels 0.75–1.75 ATR, RR 2. PM: BE 1R; trail 1.2R giveback 35 buffer 0.3.
29
+ `pctB gte 0.85`); `BREAK_DOWN` verdict DOWN (mirror with `pctB lte 0.15`). Levels 0.75–1.75 ATR,
30
+ RR 2, ATR floor 0.8% — a compression play needs the expansion to be worth the stop. PM: BE 1R; trail 1.2R giveback 35 buffer 0.3.
34
31
  Market Read: "Trade only expansions out of compression: {SQUEEZE_ON} must read TRUE… skip
35
32
  anything failing {LIQUID_FLOOR}."
36
33
 
@@ -43,11 +40,7 @@ new longs / new shorts / short covering / long liquidation), `MARK spread ORACLE
43
40
  `NO_LIQUIDATION_TAPE` required NOT-veto (`NOT [oiRegime is "long liquidation"]`);
44
41
  `CROWDED_LONGS` building block (`ann gte 25` + `oiChg gte 3` + `oiRegime is "new longs"`);
45
42
  `FADE_SHORT` verdict DOWN (ref + `RSI14 gte 65` + `chg24h gte 5`); mirrored `SQUEEZED_SHORTS`
46
- / `SQUEEZE_LONG` verdict UP. Rules: `funding_extreme_positive`/`_negative` 3 required
47
- `{"thresholdAnnualizedPct":100}` · `oi_surge` 2 `{"thresholdPct":0.03}` · `rsi_overbought` 2
48
- `{"threshold":65}` · `rsi_oversold` 2 `{"threshold":35}` · `cvd_bear_divergence` 2 ·
49
- `cvd_bull_divergence` 2 · `mfi_overbought` 1 · `mfi_oversold` 1. Gates 0.6 / 1 / 0.5. Levels
50
- 1.0–2.5 ATR, RR 1.5. PM: BE 0.8R, no trail, timeDecay ON (120/60, 10→40, stale 25).
43
+ / `SQUEEZE_LONG` verdict UP. Levels 1.0–2.5 ATR, RR 1.5, ATR floor 0.5%. PM: BE 0.8R, no trail, timeDecay ON (120/60, 10→40, stale 25).
51
44
 
52
45
  ### 3 · Relative-Strength Rotation with a Benchmark Gate — 4h cross-sectional
53
46
 
@@ -61,10 +54,8 @@ every row reads BTC. Conditions: `BTC_RISK_ON` building block (`MAalign is "bull
61
54
  `ADX gte 20` — both read bare, since only this section renders them); `BTC_RISK_OFF`
62
55
  (`MAalign is "bearish"`); `LEADER` (`roc12_rank_hi lte 5` + `RVOL_rank_hi lte 10` +
63
56
  `vol24hUsd gte 100000000`); `ROTATE_IN` verdict UP (`ALL[ref BTC_RISK_ON, ref LEADER]`);
64
- `ROTATE_OUT` verdict DOWN (`ALL[ref BTC_RISK_OFF, roc12_rank_lo lte 5]`). Rules:
65
- `comparison_sector_momentum` 3 · `rel_roc_positive`/`_negative` 2 · `ma_ema_aligned_bull`/
66
- `_bear` 2 required · `rel_ppo_bull_cross`/`_bear_cross` 1 · `volume_surge` 1. Gates
67
- 0.5 / 1 / 0.6. Levels 1–2 ATR, RR 1.8. PM: BE 1R; trail 1R giveback 45. Ranked cohort ≥ 40 —
57
+ `ROTATE_OUT` verdict DOWN (`ALL[ref BTC_RISK_OFF, roc12_rank_lo lte 5]`). Levels 1–2 ATR, RR 1.8,
58
+ ATR floor 0.6%. PM: BE 1R; trail 1R giveback 45. Ranked cohort ≥ 40 —
68
59
  rank conditions need a cohort wider than their thresholds.
69
60
 
70
61
  ### 4 · HTF Trend Pullback — 1h, multi-timeframe confluence
@@ -77,11 +68,8 @@ would be ambiguous. Conditions: `HTF_UP` building block (`MAalign_htf is "bullis
77
68
  `ADX_htf_state in ["trending","extreme"]`); `HTF_DOWN` mirror; `TREND_PRESENT` **required**
78
69
  `ANY[ref HTF_UP, ref HTF_DOWN]` — chop blocks compose-trade entirely, before billing;
79
70
  `PULLBACK_LONG` verdict UP (ref HTF_UP + `RSI14_now between 35 55` +
80
- `dist_EMA20 between -3 0.5`); `PULLBACK_SHORT` verdict DOWN (mirror, 45–65 / −0.5–3). Rules:
81
- `mtf_pullback_long`/`_short` 3 required · `htf_ma_aligned_bull`/`_bear` 2 required ·
82
- `htf_trend_adx_trending` 2 · `ma_ema_aligned_bull`/`_bear` 1 · `rsi_oversold` 1
83
- `{"threshold":40}`. Gates 0.6 / 2 / 0.7 (a pullback signal AND an HTF alignment). Levels
84
- 1–2.5 ATR, RR 2. PM: BE 1R; trail 1.5R giveback 30 buffer 0.3.
71
+ `dist_EMA20 between -3 0.5`); `PULLBACK_SHORT` verdict DOWN (mirror, 45–65 / −0.5–3). Levels
72
+ 1–2.5 ATR, RR 2, ATR floor 0.7%. PM: BE 1R; trail 1.5R giveback 30 buffer 0.3.
85
73
 
86
74
  ### 5 · Perp/Spot Flow Divergence at Structure — 15m scalp
87
75
 
@@ -93,10 +81,8 @@ perp_led_fragile / spot_led_accumulation / neutral), `includeStructureZones`
93
81
  (`zones_htf_support_dist between 0 2` + `zones_htf_support_age_h gte 12`); `DIP_BID` verdict
94
82
  UP — refs plus an `N_OF(2)` quorum over `buyPres gte 0.55` / `RVOL gte 1.2` / `closeChg gt 0`
95
83
  (quorum beats a brittle ALL); `FRAGILE_POP` verdict DOWN (`perp_led_fragile` +
96
- `zones_htf_resist_dist between -2 0` + `RVOL gte 1.3`). Rules:
97
- `flow_perp_spot_bull_divergence`/`_bear_divergence` 3 required · `cvd_bull_divergence`/
98
- `_bear_divergence` 2 · `sr_at_support`/`_at_resistance` 2 · `structure_ob_approach` 1 ·
99
- `volume_surge` 1. Gates 0.55 / 1 / 0.4. Levels 0.5–1.2 ATR, RR 1.5. PM: BE 0.7R; trail 0.9R
84
+ `zones_htf_resist_dist between -2 0` + `RVOL gte 1.3`). Levels 0.5–1.2 ATR, RR 1.5, ATR floor
85
+ 0.4%. PM: BE 0.7R; trail 0.9R
100
86
  giveback 30 buffer 0.15; timeDecay ON aggressive (45/15, 15→60, stale 30).
101
87
 
102
88
  ## Using a playbook
@@ -104,7 +90,7 @@ giveback 30 buffer 0.15; timeDecay ON aggressive (45/15, 15→60, stale 30).
104
90
  Discover → confirm headers (`get_strategy_column_contract`, or one `preview_strategy_report` at
105
91
  `detail: "detailed"`, whose `authoring.conditionColumns` lists every addressable header with
106
92
  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
93
+ and fix what its diagnostics name → read it back and review the drafted conditions, then the draft's
108
94
  own report preview — the conditions register (`gridConditions`), verdict tally, and
109
95
  `marketReadMarkers` (fix `unknown` / `ambiguous` markers) → commit per the strategy-authoring flow. Coin selection is call context, not strategy
110
96
  state: explicit tickers for focused work, `ranked` (with an optional category) for scanning books.
@@ -33,7 +33,7 @@ rather than events all live there. This document assumes them.
33
33
  | Chop filter on the entry rung | `{ "metric": "CLOSE", "transformId": "efficiency", "timeframe": { "rel": "lower" }, "window": 5, "bars": "closed" }` | `close_ltf_er` (≥0.6 directional) |
34
34
  | One-bar volume concentration | `{ "metric": "VOLUME", "transformId": "maxShare", "timeframe": { "rel": "lower" }, "window": 4, "bars": "closed" }` | `volBase_ltf_maxShare` |
35
35
  | Room to structure | `{ "metric": "STRUCT_ZONES", "transformId": "nearestZoneDist", "timeframe": { "rel": "regime" }, "side": "resistance" }` | `zones_htf_resist_dist` |
36
- | Last **closed** daily read | `{ "metric": "RSI14", "transformId": "value", "timeframe": { "abs": "1d" }, "offset": 1 }` | `RSI14_1d` — `RSI14[t - 1]` |
36
+ | Last **closed** daily read | `{ "metric": "RSI14", "transformId": "value", "timeframe": { "abs": "1d" }, "bars": "closed" }` | `RSI14_1d` — the newest completed daily bar |
37
37
 
38
38
  ## Cross detection
39
39
 
@@ -21,7 +21,7 @@ Players often ask for strategies by the name of a popular TradingView script. Po
21
21
  **process** (regime filter → setup state → trigger → stop engine), and where the catalog lacks
22
22
  the primitive, name the substitution in the spec-lock question — never present a substitute as
23
23
  the thing itself. Most TV strategies run on the daily chart: carry that with the
24
- daily-strategy pattern above (pinned-1d thesis at `offset: 1` on an intraday anchor), which
24
+ daily-strategy pattern above (pinned-1d thesis with `"bars": "closed"` at offset 0 on an intraday anchor), which
25
25
  binds decisions to daily closes while the studio keeps managing risk intraday.
26
26
 
27
27
  Event-column behaviour, state-vs-event, previous-session-level binding and the squeeze's anchor calibration are
@@ -45,8 +45,7 @@ rules about the columns themselves, not about porting — they live in the skill
45
45
  `ST_DIR enters "bullish"` is TRUE on the one completed bar the direction turned, and
46
46
  `ST_DIR exits "bullish"` on the bar it turned back — see `## Conditions` in the skill body.
47
47
  - **MACD + 200 MA filter** → `ABOVE_200` building block (`dist_SMA200 gt 0`) referenced by a
48
- carrier with `MACD_cross is "Bullish"`; rules `macd_bull/bear_cross` 3 required +
49
- `ma_sma200_above/below` 2 required; swing-trend geometry.
48
+ carrier with `MACD_cross is "Bullish"`; swing-trend geometry.
50
49
  - **Golden / Death Cross** → `SMA50 spread SMA200 × trajectory` gives state and freshness:
51
50
  `SMA50_SMA200_spread_now gt 0` AND `_trend is "rising"`; optional breadth gate on
52
51
  `mktBreadth_crypto gte 0` — every published scope resolves, not only `all`, because the leg reads
@@ -54,8 +53,7 @@ rules about the columns themselves, not about porting — they live in the skill
54
53
  the canonical definition and stays the default port; `EMA50` is available as the crypto variant
55
54
  when a player asks for it by name.
56
55
  - **RSI-2 (Connors)** → `RSI2` is native, so this ports exactly: `RSI2 lte 10` gated by required
57
- `ABOVE_200`; the source's fast exit is time — timeDecay ON (180/60, 15→50, stale 20);
58
- `rsi_oversold` 3 required with a tuned threshold. Keep the literal `lte 10` as the GATE:
56
+ `ABOVE_200`; the source's fast exit is time — timeDecay ON (180/60, 15→50, stale 20). Keep the literal `lte 10` as the GATE:
59
57
  `RSI2 × classifyZone` exists and reads on the same Connors bands, but a zone label is a fixed
60
58
  reading while the literal is a threshold the author can see and tune. Use the zone as a report
61
59
  column, never as the substitute for the gate.
@@ -63,16 +61,14 @@ rules about the columns themselves, not about porting — they live in the skill
63
61
  stretch; required `NOT [ADX_state in ["trending","extreme"]]` veto; scalp geometry +
64
62
  aggressive timeDecay (VWAP anchors daily at 00:00 UTC).
65
63
  - **Donchian / Turtle breakout** → `zone is "breakout high"` + `dist_donchianHi gte 0` +
66
- `RVOL gte 1.5`; `sr_resistance_break` 3 required; turtle exits = trend preset (trail from
64
+ `RVOL gte 1.5`; turtle exits = trend preset (trail from
67
65
  1R, giveback 50). Mirror with `"breakdown low"`. **Daily-breakout variant on any anchor:**
68
66
  pin the structure at 1d — `zone_1d is "breakout high"`, `dist_donchianHi_1d gte 0` (validated).
69
67
  **Literal previous-day levels are native**: `dist_PDH gte 0` composes directly. They are TIMELESS
70
68
  and take `{rel: 'anchor'}` — see `## Header grammar` in the skill body.
71
69
  - **ICT / SMC (FVG + order blocks)** → `STRUCT_ZONES` is the native zone engine:
72
70
  `zones_htf_support_type` (`bullish FVG`/`bullish order block`), `zones_htf_support_dist
73
- between 0 1.5`, `_age_h gte 12`, HTF bias required via `MAalign_htf`; rules
74
- `structure_fvg_approach`/`structure_ob_approach` required (their `proximityPct` is the
75
- in-zone dial). Liquidity sweeps, displacement, killzones and event *sequencing* are shapes the
71
+ between 0 1.5`, `_age_h gte 12`, HTF bias required via `MAalign_htf`. Liquidity sweeps, displacement, killzones and event *sequencing* are shapes the
76
72
  grammar does not have — a clause compares one column with a literal or with its own previous
77
73
  completed bar, never with another column or an earlier event, so an ordered sequence of events
78
74
  cannot be stated at all. That is a grammar limit, not a missing metric; name it as
@@ -28,8 +28,8 @@ Not "what were its returns" — whether it did *the thing it was told to do*.
28
28
  - `get_intelligence_agent` — restate the agent's mandate in one line, in the player's terms. This
29
29
  is the yardstick; without it "up 4%" means nothing.
30
30
  - `get_strategy` on the `strategyId` that read returns — the mandate is the bound strategy, so the
31
- yardstick is its admission gates, required conditions and trade levels, not the agent's overlay
32
- prose. Read `bindingState` too: at `SYNCING` or `ORPHANED` the agent evaluates a materialized copy
31
+ yardstick is its entry conditions — required and verdict-carrying, the only deterministic entry
32
+ gate — and its trade levels with the ATR floor, not the agent's overlay prose. Read `bindingState` too: at `SYNCING` or `ORPHANED` the agent evaluates a materialized copy
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.
@@ -19,14 +19,14 @@ re-sorts a list, re-derives a verdict, or approves on the player's behalf.
19
19
  ## 1. When the player names a coin and not an agent — choose the agent
20
20
 
21
21
  - `scan_coin_agents` for the coin. The rows arrive server-ranked across the player's own agents:
22
- `qualified` by score, then `rejected` with the first failing gate, then `unscorable` with the
22
+ `qualified` first, then `rejected` with the first failing gate, then `unscorable` with the
23
23
  reason, then `ineligible` with the refusal `propose_entry_decision` would give (`AGENT_NOT_ACTIVE`,
24
24
  `MODEL_INACTIVE`, `AGENT_HALTED`). Read them **as written** — never re-sort or re-derive a verdict.
25
25
  - **Ask the top-ranked qualifying agent**, and name the other agents that qualified so the player can
26
26
  choose one of them instead. One request per coin: the platform holds one pending request per coin
27
27
  across all of the player's agents, so ask one agent, not each of them.
28
28
  - **When none qualifies, say so plainly.** Name each agent's blocking gate or ineligibility, and offer
29
- the strategy doctor for the one closest to qualifying. Never propose through an agent the scan
29
+ the strategy doctor for the one whose blocking gate is the one to work on. Never propose through an agent the scan
30
30
  reports rejected, unscorable or ineligible.
31
31
  - **When the player has no agent at all**, the scan is empty: say so, and the next step is building one
32
32
  (a strategy first, when they have none).
@@ -34,8 +34,8 @@ re-sorts a list, re-derives a verdict, or approves on the player's behalf.
34
34
 
35
35
  ## 2. Which coins fit the agent right now
36
36
 
37
- - `scan_agent_coins` for the agent. The rows arrive server-ranked: qualifying coins first by score,
38
- then the rest with their first failing gate, then coins that could not be scored with the reason.
37
+ - `scan_agent_coins` for the agent. The rows arrive server-ranked: qualifying coins first by ticker,
38
+ then the rest with their first failing gate, then coins that could not be evaluated, with the reason.
39
39
  The scan reads the agent's gates and spends no LLM call.
40
40
  - Read the rows **as written**: the rank, the verdict, the first failing gate, the unscorable
41
41
  label. Never re-sort them and never re-derive a verdict from its numbers — the server's ranking