create-tradejs 3.1.22 → 3.1.23
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 +19 -3
- package/dist/index.js +36 -5
- package/dist/skill-bundle/.codex/skills/ai-train-local-research/SKILL.md +596 -0
- package/dist/skill-bundle/.codex/skills/ai-train-local-research/references/gate-ablation.md +324 -0
- package/dist/skill-bundle/.codex/skills/ai-train-local-research/references/reporting.md +227 -0
- package/dist/skill-bundle/.codex/skills/ai-train-local-research/scripts/ai-gate-ablation.mjs +5082 -0
- package/dist/skill-bundle/.codex/skills/ai-train-local-research/scripts/ai-gate-ablation.test.mjs +1170 -0
- package/dist/skill-bundle/.codex/skills/backtest-config-redis/SKILL.md +17 -0
- package/dist/skill-bundle/.codex/skills/backtest-config-redis/scripts/get_backtest_config.sh +21 -0
- package/dist/skill-bundle/.codex/skills/runtime-parity-mismatch-analysis/SKILL.md +146 -0
- package/dist/skill-bundle/.codex/skills/save-strategy-config-from-backtest/SKILL.md +58 -0
- package/dist/skill-bundle/.codex/skills/save-strategy-config-from-backtest/agents/openai.yaml +4 -0
- package/dist/skill-bundle/.codex/skills/strategy-backtest-research/SKILL.md +334 -0
- package/dist/skill-bundle/.codex/skills/strategy-backtest-research/references/research-notes.md +247 -0
- package/dist/skill-bundle/.codex/skills/strategy-backtest-research/scripts/backtest-run-metrics.mjs +647 -0
- package/dist/skill-bundle/.codex/skills/strategy-backtest-research/scripts/backtest-run-metrics.test.mjs +321 -0
- package/dist/skill-bundle/.codex/skills/strategy-backtest-research/scripts/fast-ai-export-metrics.mjs +744 -0
- package/dist/skill-bundle/.codex/skills/strategy-backtest-research/scripts/fast-ai-export-metrics.test.mjs +553 -0
- package/dist/skill-bundle/.codex/skills/strategy-backtest-research/scripts/research-notes-check.mjs +125 -0
- package/dist/skill-bundle/.codex/skills/strategy-improvement-research/SKILL.md +18 -1
- package/dist/skill-bundle/.codex/skills/strategy-release/SKILL.md +22 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/agents/openai.yaml +4 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/references/diagnose-live.md +126 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/references/direction-policy.md +141 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/references/directional-parameter-split.md +93 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/references/evidence-limitations.md +76 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/references/evidence-retention.md +157 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/references/historical-hypothesis-audit.md +163 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/references/professional-research-loop.md +198 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/references/release-workflow.md +755 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/references/research-objective.md +255 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/references/verdict-contract.md +200 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/scripts/direction-policy-checkpoint.mjs +137 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/scripts/direction-policy-checkpoint.test.mjs +85 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/scripts/directional-parameter-checkpoint.mjs +149 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/scripts/directional-parameter-checkpoint.test.mjs +120 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/scripts/release-progress-checkpoint.mjs +621 -0
- package/dist/skill-bundle/.codex/skills/strategy-release/scripts/release-progress-checkpoint.test.mjs +349 -0
- package/dist/skill-bundle/.codex/tradejs-skill-bundle.json +44 -3
- package/package.json +1 -1
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# Release research objective and candidate revalidation
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
1. Version the objective
|
|
6
|
+
2. Use a hierarchical objective
|
|
7
|
+
3. Condition terminal evidence on support
|
|
8
|
+
4. Revalidate historical candidates
|
|
9
|
+
5. Keep one global trial ledger
|
|
10
|
+
6. Required artifacts
|
|
11
|
+
7. Progress checkpoint payload
|
|
12
|
+
|
|
13
|
+
## 1. Version the objective
|
|
14
|
+
|
|
15
|
+
Every release task starts a new immutable lineage unless the user explicitly
|
|
16
|
+
names an existing lineage to continue. Audit prior work, but never count a
|
|
17
|
+
prior round, rescue child, gate ablation, report, or verdict as work completed
|
|
18
|
+
inside the new lineage.
|
|
19
|
+
|
|
20
|
+
Before the baseline, persist a `tradejs-release-objective/v2` artifact. Its
|
|
21
|
+
file SHA-256 is the `objectiveFingerprint` for the lineage. Freeze:
|
|
22
|
+
|
|
23
|
+
- the return unit and risk normalization;
|
|
24
|
+
- cost/slippage and adverse-cost scenarios;
|
|
25
|
+
- development, tuning, sealed-test, walk-forward, and terminal partitions;
|
|
26
|
+
- eligibility gates, Pareto dimensions, and tie-break rules;
|
|
27
|
+
- independent-event grouping and support bands;
|
|
28
|
+
- drawdown, concentration, capacity, and execution guardrails;
|
|
29
|
+
- the global trial-ledger reference used for DSR/PBO.
|
|
30
|
+
|
|
31
|
+
Any change to these fields creates a new objective fingerprint. Do not reuse a
|
|
32
|
+
ranking, verdict, or selected candidate from another fingerprint.
|
|
33
|
+
|
|
34
|
+
## 2. Use a hierarchical objective
|
|
35
|
+
|
|
36
|
+
Do not maximize full-period PnL, Sharpe, win rate, or recent-window PnL in
|
|
37
|
+
isolation. Use this hierarchy:
|
|
38
|
+
|
|
39
|
+
1. **Integrity and causality.** Complete reconciled evidence, signal-time
|
|
40
|
+
inputs, point-in-time execution semantics, and comparable risk/cost units
|
|
41
|
+
are mandatory.
|
|
42
|
+
2. **Economic edge.** Require positive aggregate expectancy per unit risk after
|
|
43
|
+
normal costs and PF above 1 on the maximum-covered historical evaluation.
|
|
44
|
+
Apply the same check to every active approved side; an explicitly suppressed
|
|
45
|
+
side remains a zero row. Nested calendar slices do not repeat this gate.
|
|
46
|
+
3. **Selection adjustment.** Report probabilistic and deflated Sharpe using
|
|
47
|
+
non-IID-aware returns and the complete effective trial count. A raw
|
|
48
|
+
per-trade annualized Sharpe is diagnostic, not selection authority.
|
|
49
|
+
4. **Risk robustness.** Enforce preregistered realized MaxDD, tail/CVaR,
|
|
50
|
+
recovery, time-under-water, adverse-cost, concentration, and capacity
|
|
51
|
+
guardrails.
|
|
52
|
+
5. **Temporal robustness.** Prefer non-overlapping/event-grouped walk-forward
|
|
53
|
+
evidence and regime coverage. Nested 3y/4y/max and recent calendar windows
|
|
54
|
+
are context, not independent confirmations or waiting periods.
|
|
55
|
+
6. **Executable support.** Require independent events, viable cadence, and an
|
|
56
|
+
event-arrival rate consistent with the strategy thesis.
|
|
57
|
+
|
|
58
|
+
Rank eligible candidates on a Pareto frontier across expectancy/risk, PF,
|
|
59
|
+
deflated Sharpe, MaxDD/recovery, walk-forward stability, cost stress,
|
|
60
|
+
independent support, and cadence. Use a scalar score only as a frozen tie-break,
|
|
61
|
+
never to compensate for a failed integrity or economic gate.
|
|
62
|
+
|
|
63
|
+
Treat win rate only together with payoff ratio and expectancy. Treat maximum
|
|
64
|
+
loss streak, losing-month streak, drawdown duration, and worst rolling returns
|
|
65
|
+
as risk diagnostics and monitoring bounds, not optimization targets. Absolute
|
|
66
|
+
streaks grow mechanically with sample size and cannot fairly rank candidates
|
|
67
|
+
with different cadence.
|
|
68
|
+
|
|
69
|
+
## 3. Condition terminal evidence on support
|
|
70
|
+
|
|
71
|
+
Always report continuous-run 365d/180d/90d/30d/7d rows, including zero rows,
|
|
72
|
+
but use them to describe current regime and cadence rather than to decide when a
|
|
73
|
+
prospective test may start. Classify each ALL/LONG/SHORT cohort by independent
|
|
74
|
+
event count:
|
|
75
|
+
|
|
76
|
+
- `underpowered`: fewer than 20 independent closed events;
|
|
77
|
+
- `diagnostic`: 20 through 49 independent closed events;
|
|
78
|
+
- `selection_grade`: at least 50 independent closed events.
|
|
79
|
+
|
|
80
|
+
An `underpowered` terminal row is `n/a` for pass/fail. It cannot reject a
|
|
81
|
+
candidate, prove current-market decay, justify another threshold, or force a
|
|
82
|
+
calendar wait. A `diagnostic` row may motivate the one preregistered causal
|
|
83
|
+
recent-direction repair, but cannot reject an otherwise eligible composition by
|
|
84
|
+
itself. A `selection_grade` row may cap a historical `READY_FOR_RUNTIME` claim
|
|
85
|
+
or lower the candidate's Pareto rank, but it does not block an otherwise valid
|
|
86
|
+
`MAX_LOSS_VALUE=1` prospective test. Hard causality, reconciliation, execution,
|
|
87
|
+
maximum-covered economics, and frozen portfolio-risk failures still block it.
|
|
88
|
+
|
|
89
|
+
For sparse strategies also report the last 20/50/100 independent events and
|
|
90
|
+
compare observed calendar cadence with the preregistered historical
|
|
91
|
+
event-arrival distribution. Zero trades are a cadence observation, not a loss;
|
|
92
|
+
classify them as abnormal only when they breach that frozen distribution. The
|
|
93
|
+
next review is triggered by independent events or a risk/parity breach, never
|
|
94
|
+
by waiting 7, 30, or 180 calendar days.
|
|
95
|
+
|
|
96
|
+
## 4. Revalidate historical candidates
|
|
97
|
+
|
|
98
|
+
Objective changes invalidate old rankings, not the underlying evidence. Before
|
|
99
|
+
inventing new hypotheses, build a deduplicated inventory of every historical
|
|
100
|
+
core, deterministic-gate, direction-policy, rescue, shortlisted, and untested
|
|
101
|
+
candidate. Group semantic duplicates by behavior/config fingerprint.
|
|
102
|
+
|
|
103
|
+
For every reconstructable candidate:
|
|
104
|
+
|
|
105
|
+
1. Recompute the new objective from retained normalized trades when window,
|
|
106
|
+
universe, costs, execution semantics, source behavior, and risk unit match.
|
|
107
|
+
2. Otherwise rerun the exact historical behavior on the new frozen contract
|
|
108
|
+
with `--cacheOnly` before ranking it when it could reach the new frontier.
|
|
109
|
+
3. Record `rescored`, `bridge-rerun`, `rejected`, `partial`, or
|
|
110
|
+
`unreconstructable`, with the source inventory entry, evidence paths, and
|
|
111
|
+
hashes. Use `new-trial-required` for an inventoried behavior that was never
|
|
112
|
+
economically tested; schedule it inside the normal new-candidate budget.
|
|
113
|
+
4. Put every evaluated behavior in the global trial ledger even when it is no
|
|
114
|
+
longer shortlisted. Re-scoring does not erase the original selection look.
|
|
115
|
+
5. Preserve exposed tails as exposed. A new lineage or objective fingerprint
|
|
116
|
+
never makes previously viewed data sealed again.
|
|
117
|
+
|
|
118
|
+
Metric-only re-scoring and exact bridge reruns of already-tested behavior do
|
|
119
|
+
not consume the new lineage's 18 causal-candidate slots. They remain part of
|
|
120
|
+
the global multiple-testing count. A changed threshold, feature, direction
|
|
121
|
+
policy, payoff rule, or other behavior is a new candidate and consumes the
|
|
122
|
+
normal family/rescue budget.
|
|
123
|
+
|
|
124
|
+
Finish the revalidation board before freezing the three new causal families.
|
|
125
|
+
An old candidate may become the matched control or finalist under the new
|
|
126
|
+
objective, but the task must still perform its new causal improvement rounds;
|
|
127
|
+
revalidation is evidence-first preparation, not a substitute for new research.
|
|
128
|
+
|
|
129
|
+
## 5. Keep one global trial ledger
|
|
130
|
+
|
|
131
|
+
The trial ledger spans tasks, lineages, source branches, objective versions,
|
|
132
|
+
core variants, gate variants, directional policies, and rescue attempts.
|
|
133
|
+
Deduplicate exact behavior reruns but retain every distinct selection look.
|
|
134
|
+
Record at least:
|
|
135
|
+
|
|
136
|
+
- candidate/behavior fingerprint and parent family;
|
|
137
|
+
- first-seen lineage and every evaluation lineage;
|
|
138
|
+
- objective fingerprint;
|
|
139
|
+
- development/tuning/test exposure status;
|
|
140
|
+
- return series, sample size, skew, kurtosis, and serial-dependence method;
|
|
141
|
+
- raw, probabilistic, and deflated Sharpe;
|
|
142
|
+
- effective independent trial count and PBO/selection diagnostics.
|
|
143
|
+
|
|
144
|
+
Do not reset DSR/PBO because a new chat, Git commit, research id, or objective
|
|
145
|
+
was created. Repeated research is legitimate only when the ledger makes the
|
|
146
|
+
increasing selection burden explicit.
|
|
147
|
+
|
|
148
|
+
## 6. Required artifacts
|
|
149
|
+
|
|
150
|
+
Before round 1, persist:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"schema": "tradejs-release-candidate-revalidation/v2",
|
|
155
|
+
"strategy": "<Strategy>",
|
|
156
|
+
"lineageId": "<new-lineage-id>",
|
|
157
|
+
"objectiveFingerprint": "<objective-artifact-sha256>",
|
|
158
|
+
"historyInventorySha256": "<history-inventory-sha256>",
|
|
159
|
+
"status": "complete",
|
|
160
|
+
"priorCandidateCount": 1,
|
|
161
|
+
"candidates": [
|
|
162
|
+
{
|
|
163
|
+
"historyEntryIndex": 0,
|
|
164
|
+
"disposition": "rescored|bridge-rerun|rejected|partial|unreconstructable|new-trial-required",
|
|
165
|
+
"behaviorFingerprint": "<sha256>",
|
|
166
|
+
"evidence": []
|
|
167
|
+
}
|
|
168
|
+
],
|
|
169
|
+
"unresolved": [],
|
|
170
|
+
"trialLedger": { "path": "<path>", "sha256": "<sha256>" }
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`priorCandidateCount: 0` is valid only when the bound history inventory proves
|
|
175
|
+
that no prior behavior candidate exists. Refactor-only and superseded-duplicate
|
|
176
|
+
entries are excluded; every other deduplicated entry needs exactly one indexed
|
|
177
|
+
disposition. Hash this artifact and reference it from the opportunity map, all
|
|
178
|
+
new round specs/handoffs, the rescue board, selected composition, and final
|
|
179
|
+
decision.
|
|
180
|
+
|
|
181
|
+
## 7. Progress checkpoint payload
|
|
182
|
+
|
|
183
|
+
Use `tradejs-release-progress-input/v2`. Completion claims are artifact-backed:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"schema": "tradejs-release-progress-input/v2",
|
|
188
|
+
"strategy": "<Strategy>",
|
|
189
|
+
"lineageId": "<new-lineage-id>",
|
|
190
|
+
"objectiveContract": { "artifact": { "path": "...", "sha256": "..." } },
|
|
191
|
+
"historyAudit": {
|
|
192
|
+
"complete": true,
|
|
193
|
+
"artifact": { "path": "...", "sha256": "..." }
|
|
194
|
+
},
|
|
195
|
+
"candidateRevalidation": {
|
|
196
|
+
"required": true,
|
|
197
|
+
"complete": true,
|
|
198
|
+
"artifact": { "path": "...", "sha256": "..." }
|
|
199
|
+
},
|
|
200
|
+
"baseline": {
|
|
201
|
+
"complete": true,
|
|
202
|
+
"reconciled": true,
|
|
203
|
+
"artifact": { "path": "...", "sha256": "..." }
|
|
204
|
+
},
|
|
205
|
+
"opportunityMap": {
|
|
206
|
+
"complete": true,
|
|
207
|
+
"artifact": { "path": "...", "sha256": "..." }
|
|
208
|
+
},
|
|
209
|
+
"hypothesisPortfolio": {
|
|
210
|
+
"frozen": true,
|
|
211
|
+
"artifact": { "path": "...", "sha256": "..." }
|
|
212
|
+
},
|
|
213
|
+
"families": [
|
|
214
|
+
{
|
|
215
|
+
"id": "<family>",
|
|
216
|
+
"status": "active",
|
|
217
|
+
"roundArtifacts": [
|
|
218
|
+
{
|
|
219
|
+
"round": 1,
|
|
220
|
+
"researchId": "<id>",
|
|
221
|
+
"manifestArtifact": { "path": "...", "sha256": "..." },
|
|
222
|
+
"resultArtifact": { "path": "...", "sha256": "..." },
|
|
223
|
+
"traceArtifacts": [{ "path": "...", "sha256": "..." }],
|
|
224
|
+
"handoffArtifact": { "path": "...", "sha256": "..." }
|
|
225
|
+
}
|
|
226
|
+
]
|
|
227
|
+
}
|
|
228
|
+
],
|
|
229
|
+
"rescueBoard": { "complete": false },
|
|
230
|
+
"directionalParameterCheckpoint": { "required": false, "complete": false },
|
|
231
|
+
"directionPolicyCheckpoint": { "required": false, "complete": false },
|
|
232
|
+
"fullAiReport": { "complete": false },
|
|
233
|
+
"chart": { "complete": false },
|
|
234
|
+
"selectedComposition": null,
|
|
235
|
+
"limitations": []
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Provide exactly three family entries. `roundArtifacts`, not a caller-supplied
|
|
240
|
+
count, determines completed rounds. Each round requires a completed matching
|
|
241
|
+
core manifest, result, trace declared by that result, and causal handoff whose
|
|
242
|
+
`resultSha256` matches the result file. A family retired before round 3 also
|
|
243
|
+
requires a hashed `retirementArtifact`.
|
|
244
|
+
|
|
245
|
+
A completed rescue board uses `tradejs-release-rescue-board/v2`, binds the same
|
|
246
|
+
strategy/lineage/objective, embeds artifact-backed child evidence, and accounts
|
|
247
|
+
for all three slots through `children` plus bounded `missingSlots` reasons.
|
|
248
|
+
|
|
249
|
+
After the exact chart is frozen, create
|
|
250
|
+
`tradejs-release-selected-composition/v2`. It binds the strategy, lineage,
|
|
251
|
+
candidate id, composition fingerprint, objective fingerprint, historical
|
|
252
|
+
matrix SHA, chart SHA, and core/gate fingerprints. Pass its reference as
|
|
253
|
+
`selectedComposition.artifact`. The checkpoint returns
|
|
254
|
+
`tradejs-release-progress/v2` and copies the verified selected identity into
|
|
255
|
+
its decision output for `strategy-release decide`.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Verdict contract
|
|
2
|
+
|
|
3
|
+
Return exactly one mode-specific verdict. Put the verdict first, then the
|
|
4
|
+
composition/incident identity, evidence completeness, ALL/LONG/SHORT table,
|
|
5
|
+
causal findings, limitations, and approval-safe next action.
|
|
6
|
+
|
|
7
|
+
## Shared rules
|
|
8
|
+
|
|
9
|
+
- Treat a verdict as an evidence classification, not an authorization token.
|
|
10
|
+
- Keep ALL, LONG, and SHORT statuses separate. A positive aggregate cannot hide
|
|
11
|
+
a failed side, and a negative side cannot be silently disabled. An explicit
|
|
12
|
+
tested `long_only` or `short_only` deterministic-gate policy is allowed, but
|
|
13
|
+
the suppressed raw side and its zero approved row must remain visible.
|
|
14
|
+
- Apply `evidence-first, novelty-second`. A release verdict is incomplete until
|
|
15
|
+
the historical commit/evidence inventory is hashed, every stronger prior
|
|
16
|
+
result is classified and bridged to the current window/universe/config/cost
|
|
17
|
+
contract, and every selected untested historical behavior has a recorded
|
|
18
|
+
disposition. Do not call a weaker new search exhaustive while comparable
|
|
19
|
+
prior evidence remains unexplained.
|
|
20
|
+
- Bind the verdict to one `tradejs-release-objective/v2` fingerprint. Complete
|
|
21
|
+
the historical-candidate revalidation board under that fingerprint and retain
|
|
22
|
+
every distinct old/new behavior in the global trial ledger before ranking a
|
|
23
|
+
finalist.
|
|
24
|
+
- A current gate that approves zero/negligible rows from a profitable raw side
|
|
25
|
+
is incomplete evidence. Do not return a final market-unsuitable verdict until
|
|
26
|
+
the mandatory five-variant side-rescue round has been executed and recorded.
|
|
27
|
+
- A raw aggregate that fails because one side is the dominant loss is not a
|
|
28
|
+
final verdict while the opposite side passes the frozen useful-side rule.
|
|
29
|
+
Complete the five-variant direction-containment checkpoint before rejecting
|
|
30
|
+
the composition.
|
|
31
|
+
- `READY_FOR_RUNTIME` requires a genuinely sealed chronological gate test:
|
|
32
|
+
pocket discovery may know its count and time bounds but not its PnL or feature
|
|
33
|
+
outcomes. A test opened before variant freeze is permanently exposed and can
|
|
34
|
+
support only historical diagnosis/forward-candidate selection in that
|
|
35
|
+
lineage.
|
|
36
|
+
- Treat `MAX_LOSS_VALUE` as risk scale rather than decision-logic identity.
|
|
37
|
+
Preserve its immutable change history, normalize monetary comparisons to the
|
|
38
|
+
release risk unit, and return `INSUFFICIENT_EVIDENCE` when either scale is
|
|
39
|
+
unavailable. Never compare unnormalized dollar drawdowns across risk scales.
|
|
40
|
+
- Treat local Redis config names/ids and deployment/account ids, and
|
|
41
|
+
server credentials as environment binding rather than composition logic.
|
|
42
|
+
Never infer production absence from missing local keys. A locally unbound but
|
|
43
|
+
otherwise verified candidate is `MICRO_FORWARD_READY` with
|
|
44
|
+
`requiresRuntimeBinding=true`; bind and reverify it on the runtime server.
|
|
45
|
+
Activation (`ENABLE`) remains execution-critical and must equal the
|
|
46
|
+
authorized handoff before forward execution.
|
|
47
|
+
- Use aggregate portfolio MaxDD for ALL and side-only realized MaxDD for each
|
|
48
|
+
direction.
|
|
49
|
+
- Report every terminal row, but apply the support classes from
|
|
50
|
+
[research-objective.md](research-objective.md). An underpowered row is `n/a`
|
|
51
|
+
and a diagnostic row cannot reject a composition by itself. A selection-grade
|
|
52
|
+
row may limit historical readiness and candidate rank, but no terminal
|
|
53
|
+
calendar row blocks an otherwise valid risk-1 prospective test. Empty recent
|
|
54
|
+
windows are cadence evidence, not losses.
|
|
55
|
+
- A complete release verdict, including `UNSUITABLE_FOR_CURRENT_MARKET`,
|
|
56
|
+
requires the full window matrix and the complete `$ai-train-local-research`
|
|
57
|
+
report. A negative verdict cannot replace omitted statistics with an artifact
|
|
58
|
+
link or a short rescue leaderboard.
|
|
59
|
+
- Prefer `INSUFFICIENT_EVIDENCE` over extrapolation when lineage, completeness,
|
|
60
|
+
parity, point-in-time validity, independent support, or reconciliation fails.
|
|
61
|
+
- This classifies the historical claim; it does not automatically mean stop.
|
|
62
|
+
Retrospective-universe or exposed-holdout limitations require continued
|
|
63
|
+
bounded research and may end in a risk-1 prospective handoff.
|
|
64
|
+
- Keep any unapproved next composition in forward incubation/advisory mode.
|
|
65
|
+
- A verdict never means “wait”. Pair it with the deterministic research action:
|
|
66
|
+
bounded recent-direction repair, authorized risk-1 micro-forward, a concrete
|
|
67
|
+
blocker, or stop. An exposed holdout blocks `READY_FOR_RUNTIME` but does not
|
|
68
|
+
block prospective micro-forward evidence.
|
|
69
|
+
|
|
70
|
+
## Release verdicts
|
|
71
|
+
|
|
72
|
+
### `READY_FOR_RUNTIME`
|
|
73
|
+
|
|
74
|
+
Use only when all conditions hold:
|
|
75
|
+
|
|
76
|
+
- the one final core plus deterministic gate composition is immutable and
|
|
77
|
+
completely reconciled;
|
|
78
|
+
- the bounded core loop used one anchor plus two evidence-driven refinement
|
|
79
|
+
pairs per surviving family, then completed the mandatory cadence-diverse
|
|
80
|
+
rescue board, never exceeded 3×5+3 candidates, and completed full
|
|
81
|
+
metric/match/trace analysis before each child;
|
|
82
|
+
- one isolated-long finalist and one gate round followed the preregistered
|
|
83
|
+
rules without reopening the held-out evidence;
|
|
84
|
+
- BOTH directions stayed enabled in raw evidence and ALL/LONG/SHORT were
|
|
85
|
+
reported; the approved composition either passes its explicit rules for both
|
|
86
|
+
sides or uses a preregistered, held-out-tested `long_only`/`short_only` gate
|
|
87
|
+
policy whose retained side and ALL stream pass while the suppressed side is
|
|
88
|
+
shown explicitly as zero approved support;
|
|
89
|
+
- full, terminal, cold-start/reset, concentration, capacity, causality, and
|
|
90
|
+
current-market evidence satisfy the release contract;
|
|
91
|
+
- no unresolved runtime-parity or data-lineage blocker remains.
|
|
92
|
+
- the progress decision, selected-composition artifact, objective fingerprint,
|
|
93
|
+
historical matrix, and chart all identify the same candidate/composition.
|
|
94
|
+
|
|
95
|
+
Meaning: the composition supports the strongest historical claim. The verdict
|
|
96
|
+
alone is not mutation authority; a `release`-mode invocation separately
|
|
97
|
+
authorizes the exact risk-1 rollout unless it explicitly forbids runtime
|
|
98
|
+
changes. Never place, cancel, or close orders manually.
|
|
99
|
+
|
|
100
|
+
### `UNSUITABLE_FOR_CURRENT_MARKET`
|
|
101
|
+
|
|
102
|
+
Use when evidence is complete and valid, but no composition satisfies the
|
|
103
|
+
prospective rule: positive maximum-covered economics for every active approved
|
|
104
|
+
side plus frozen drawdown/tail/cost/concentration/support guardrails. A recent
|
|
105
|
+
calendar loss alone is not sufficient. Typical evidence includes failed active
|
|
106
|
+
side economics, unacceptable portfolio DD/capacity, or no qualifying isolated
|
|
107
|
+
finalist.
|
|
108
|
+
|
|
109
|
+
Do not use this verdict merely because the first three rounds produced no
|
|
110
|
+
eligible finalist. It requires the historical bridge and all available rescue
|
|
111
|
+
slots to be complete. It also requires the direction-policy checkpoint, the
|
|
112
|
+
maximum-window diagnostic handoff, the full window matrix, and the complete
|
|
113
|
+
AI-gate report. A stronger unbridged prior result or an unresolved
|
|
114
|
+
reconstructable historical hypothesis makes the evidence incomplete instead.
|
|
115
|
+
|
|
116
|
+
Meaning: preserve the composition and failures as immutable research. Keep any
|
|
117
|
+
continued observation advisory/forward-only; do not tune around the exposed
|
|
118
|
+
period inside the same lineage.
|
|
119
|
+
|
|
120
|
+
### `INSUFFICIENT_EVIDENCE`
|
|
121
|
+
|
|
122
|
+
Use when a release conclusion cannot be supported, including partial/OOM/error
|
|
123
|
+
runs, missing common cached coverage, incomplete side cohorts, export/Redis
|
|
124
|
+
mismatch, unavailable point-in-time inputs, stale/open holdout, inadequate
|
|
125
|
+
independent support, missing cold-start evidence, ambiguous lineage, an
|
|
126
|
+
incomplete historical hypothesis audit, or a bounded trial cap reached while a
|
|
127
|
+
stronger reconstructable historical backlog remains.
|
|
128
|
+
|
|
129
|
+
Meaning: identify the smallest missing evidence item and its action ceiling.
|
|
130
|
+
Hard-invalid evidence must be repaired. Retrospective-universe, exposed-tail,
|
|
131
|
+
and prospective-support limitations do not justify waiting for perfect history:
|
|
132
|
+
complete the bounded contour and prepare/start the separately authorized
|
|
133
|
+
`MAX_LOSS_VALUE=1` micro-forward candidate. Do not convert uncertainty into
|
|
134
|
+
current-market unsuitability or historical readiness.
|
|
135
|
+
|
|
136
|
+
## Diagnose-live verdict precedence
|
|
137
|
+
|
|
138
|
+
Apply this order:
|
|
139
|
+
|
|
140
|
+
1. Return `INSUFFICIENT_EVIDENCE` when the released composition, incident
|
|
141
|
+
evidence, or comparison completeness cannot be established.
|
|
142
|
+
2. Return `RUNTIME_DIVERGENCE` when material runtime/replay/config/context/
|
|
143
|
+
execution non-parity explains or invalidates the observed sample.
|
|
144
|
+
3. With parity established, return `GENERALIZATION_FAILURE` when adequate new
|
|
145
|
+
post-cutoff evidence breaches the preregistered generalization bounds.
|
|
146
|
+
4. With parity and adequate support established, return `EXPECTED_DRAWDOWN`
|
|
147
|
+
when the observation remains inside the frozen release distribution.
|
|
148
|
+
|
|
149
|
+
### `RUNTIME_DIVERGENCE`
|
|
150
|
+
|
|
151
|
+
Require concrete mismatched evidence such as closed-candle boundary, config or
|
|
152
|
+
fingerprint, state restoration, causal context, deterministic gate decision,
|
|
153
|
+
allocator/risk/order lifecycle, fill, fee/slippage, or exit differences.
|
|
154
|
+
|
|
155
|
+
Do not call a strategy generalized or failed while material parity divergence
|
|
156
|
+
remains unresolved.
|
|
157
|
+
|
|
158
|
+
### `EXPECTED_DRAWDOWN`
|
|
159
|
+
|
|
160
|
+
Require exact composition parity, adequate incident/forward support, and losses,
|
|
161
|
+
streak, drawdown, cadence, concentration, sides, and regimes within the frozen
|
|
162
|
+
release bounds. This verdict does not imply future recovery or authorize higher
|
|
163
|
+
risk.
|
|
164
|
+
|
|
165
|
+
### `GENERALIZATION_FAILURE`
|
|
166
|
+
|
|
167
|
+
Require exact composition parity and adequate independent post-selection
|
|
168
|
+
evidence outside the release cutoff. Show which preregistered ALL/LONG/SHORT,
|
|
169
|
+
regime, concentration, or drawdown bound failed. Do not use an exposed tuning
|
|
170
|
+
window or a handful of correlated symbol rows as proof.
|
|
171
|
+
|
|
172
|
+
### `INSUFFICIENT_EVIDENCE`
|
|
173
|
+
|
|
174
|
+
Use when runtime evidence is remote/unavailable, ids cannot be linked, the
|
|
175
|
+
incident window is incomplete, parity is unknown, sample/event support is too
|
|
176
|
+
small, release bounds are missing, or evidence has conflicting lineage.
|
|
177
|
+
|
|
178
|
+
## Required final shape
|
|
179
|
+
|
|
180
|
+
```text
|
|
181
|
+
VERDICT: <exact enum>
|
|
182
|
+
MODE: <release|diagnose-live>
|
|
183
|
+
COMPOSITION: <core fingerprint> + <deterministic gate fingerprint>
|
|
184
|
+
EVIDENCE: <complete|incomplete> — <one-line reason>
|
|
185
|
+
HISTORY AUDIT: <inventory SHA> — <bridged/excluded/unresolved counts>
|
|
186
|
+
PRIOR BRIDGE: <strongest prior result and current-contract disposition>
|
|
187
|
+
RESCUE BOARD: <up to 3 seed cadence/failure/child/result rows, or hard reason per empty slot>
|
|
188
|
+
DIRECTION POLICY: <trigger, five variants, selected/rejected policy, checkpoint SHA>
|
|
189
|
+
|
|
190
|
+
ALL/LONG/SHORT: N, PnL, PnL/trade, PF, WR, realized MaxDD, cadence/day
|
|
191
|
+
WINDOW MATRIX: <full/3y/4y/max-covered/365d/180d/90d/30d/7d for control and best aggregate/LONG/SHORT/policy attempts>
|
|
192
|
+
AI-GATE REPORT: <decision, qN+, full/terminal outcome, cadence/fan-out, risk-adjusted, quality/direction, validation, artifact SHA>
|
|
193
|
+
CAUSAL/PARITY FINDING: <bounded evidence statement>
|
|
194
|
+
LIMITATIONS: <material limitations or none>
|
|
195
|
+
NEXT ACTION: <REPAIR_RECENT_DIRECTION|START_MICRO_FORWARD|MICRO_FORWARD_READY|FORWARD_BLOCKED|STOP_RESEARCH> — <bounded reason>
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Also cite the immutable `tradejs-release-progress/v2` artifact. If it reports
|
|
199
|
+
`verdictAllowed=false`, do not emit this final shape yet; perform its next
|
|
200
|
+
action first.
|
package/dist/skill-bundle/.codex/skills/strategy-release/scripts/direction-policy-checkpoint.mjs
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
|
|
6
|
+
const DIRECTIONS = ['LONG', 'SHORT'];
|
|
7
|
+
|
|
8
|
+
function assertMetric(metric, label) {
|
|
9
|
+
for (const field of [
|
|
10
|
+
'trades',
|
|
11
|
+
'pnl',
|
|
12
|
+
'pnlPerTrade',
|
|
13
|
+
'profitFactor',
|
|
14
|
+
'cadencePerDay',
|
|
15
|
+
]) {
|
|
16
|
+
if (!Number.isFinite(metric?.[field])) {
|
|
17
|
+
throw new Error(`${label}.${field} must be finite`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isUseful(metric, rule) {
|
|
23
|
+
return (
|
|
24
|
+
metric.trades >= rule.minimumTrades &&
|
|
25
|
+
metric.cadencePerDay >= rule.minimumCadencePerDay &&
|
|
26
|
+
metric.pnl > rule.minimumPnl &&
|
|
27
|
+
metric.pnlPerTrade > rule.minimumPnlPerTrade &&
|
|
28
|
+
metric.profitFactor > rule.minimumProfitFactor
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function evaluateDirectionPolicyCheckpoint(input) {
|
|
33
|
+
const rule = {
|
|
34
|
+
minimumTrades: 0,
|
|
35
|
+
minimumCadencePerDay: 0,
|
|
36
|
+
minimumPnl: 0,
|
|
37
|
+
minimumPnlPerTrade: 0,
|
|
38
|
+
minimumProfitFactor: 1,
|
|
39
|
+
maximumNegligibleApprovalShare: 0.05,
|
|
40
|
+
...input?.usefulSideRule,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
assertMetric(input?.raw?.ALL, 'raw.ALL');
|
|
44
|
+
for (const direction of DIRECTIONS) {
|
|
45
|
+
assertMetric(input?.raw?.[direction], `raw.${direction}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const statuses = Object.fromEntries(
|
|
49
|
+
DIRECTIONS.map((direction) => [
|
|
50
|
+
direction,
|
|
51
|
+
isUseful(input.raw[direction], rule) ? 'useful' : 'failed',
|
|
52
|
+
]),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const hidden = DIRECTIONS.find((direction) => {
|
|
56
|
+
if (statuses[direction] !== 'useful' || !input.gateApproved) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const approved = input.gateApproved[direction];
|
|
60
|
+
if (!approved || !Number.isFinite(approved.trades)) {
|
|
61
|
+
throw new Error(`gateApproved.${direction}.trades must be finite`);
|
|
62
|
+
}
|
|
63
|
+
const share = input.raw[direction].trades
|
|
64
|
+
? approved.trades / input.raw[direction].trades
|
|
65
|
+
: 0;
|
|
66
|
+
return share <= rule.maximumNegligibleApprovalShare;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
if (hidden) {
|
|
70
|
+
return {
|
|
71
|
+
schema: 'tradejs-direction-policy-decision/v1',
|
|
72
|
+
trigger: 'profitable_side_hidden',
|
|
73
|
+
required: true,
|
|
74
|
+
usefulSideRule: rule,
|
|
75
|
+
rawSideStatuses: statuses,
|
|
76
|
+
retainedSide: hidden,
|
|
77
|
+
proposedPolicy: `${hidden.toLowerCase()}_pass_through`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const usefulDirections = DIRECTIONS.filter(
|
|
82
|
+
(direction) => statuses[direction] === 'useful',
|
|
83
|
+
);
|
|
84
|
+
if (usefulDirections.length === 1) {
|
|
85
|
+
const retainedSide = usefulDirections[0];
|
|
86
|
+
const failingSide = retainedSide === 'LONG' ? 'SHORT' : 'LONG';
|
|
87
|
+
const contamination =
|
|
88
|
+
input.raw[failingSide].pnl < 0 &&
|
|
89
|
+
input.raw.ALL.pnl < input.raw[retainedSide].pnl;
|
|
90
|
+
if (contamination) {
|
|
91
|
+
return {
|
|
92
|
+
schema: 'tradejs-direction-policy-decision/v1',
|
|
93
|
+
trigger: 'losing_side_contamination',
|
|
94
|
+
required: true,
|
|
95
|
+
usefulSideRule: rule,
|
|
96
|
+
rawSideStatuses: statuses,
|
|
97
|
+
retainedSide,
|
|
98
|
+
failingSide,
|
|
99
|
+
proposedPolicy: `${retainedSide.toLowerCase()}_only`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
schema: 'tradejs-direction-policy-decision/v1',
|
|
106
|
+
trigger: 'no_side_salvage',
|
|
107
|
+
required: false,
|
|
108
|
+
usefulSideRule: rule,
|
|
109
|
+
rawSideStatuses: statuses,
|
|
110
|
+
retainedSide: null,
|
|
111
|
+
proposedPolicy: 'both',
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function main() {
|
|
116
|
+
const inputIndex = process.argv.indexOf('--input');
|
|
117
|
+
if (inputIndex === -1 || !process.argv[inputIndex + 1]) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
'Usage: direction-policy-checkpoint.mjs --input <input.json>',
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
const input = JSON.parse(
|
|
123
|
+
await readFile(process.argv[inputIndex + 1], 'utf8'),
|
|
124
|
+
);
|
|
125
|
+
process.stdout.write(
|
|
126
|
+
`${JSON.stringify(evaluateDirectionPolicyCheckpoint(input), null, 2)}\n`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) {
|
|
131
|
+
main().catch((error) => {
|
|
132
|
+
process.stderr.write(
|
|
133
|
+
`${error instanceof Error ? error.message : String(error)}\n`,
|
|
134
|
+
);
|
|
135
|
+
process.exitCode = 1;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
|
|
4
|
+
import { evaluateDirectionPolicyCheckpoint } from './direction-policy-checkpoint.mjs';
|
|
5
|
+
|
|
6
|
+
const rule = {
|
|
7
|
+
minimumTrades: 144,
|
|
8
|
+
minimumCadencePerDay: 0.1,
|
|
9
|
+
minimumPnl: 0,
|
|
10
|
+
minimumPnlPerTrade: 0,
|
|
11
|
+
minimumProfitFactor: 1,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const metric = (trades, pnl, pnlPerTrade, profitFactor, cadencePerDay) => ({
|
|
15
|
+
trades,
|
|
16
|
+
pnl,
|
|
17
|
+
pnlPerTrade,
|
|
18
|
+
profitFactor,
|
|
19
|
+
cadencePerDay,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('requires LONG-only containment for the RelativeRotation control profile', () => {
|
|
23
|
+
const decision = evaluateDirectionPolicyCheckpoint({
|
|
24
|
+
usefulSideRule: rule,
|
|
25
|
+
raw: {
|
|
26
|
+
ALL: metric(1203, -39, -0.032, 0.995, 0.835),
|
|
27
|
+
LONG: metric(886, 157.67, 0.178, 1.031, 0.615),
|
|
28
|
+
SHORT: metric(317, -196.67, -0.62, 0.907, 0.22),
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
assert.equal(decision.required, true);
|
|
33
|
+
assert.equal(decision.trigger, 'losing_side_contamination');
|
|
34
|
+
assert.equal(decision.retainedSide, 'LONG');
|
|
35
|
+
assert.equal(decision.proposedPolicy, 'long_only');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('requires recovery when a useful raw side has negligible gate approvals', () => {
|
|
39
|
+
const decision = evaluateDirectionPolicyCheckpoint({
|
|
40
|
+
usefulSideRule: rule,
|
|
41
|
+
raw: {
|
|
42
|
+
ALL: metric(500, 100, 0.2, 1.1, 0.5),
|
|
43
|
+
LONG: metric(250, 120, 0.48, 1.2, 0.25),
|
|
44
|
+
SHORT: metric(250, -20, -0.08, 0.97, 0.25),
|
|
45
|
+
},
|
|
46
|
+
gateApproved: {
|
|
47
|
+
LONG: { trades: 0 },
|
|
48
|
+
SHORT: { trades: 40 },
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
assert.equal(decision.required, true);
|
|
53
|
+
assert.equal(decision.trigger, 'profitable_side_hidden');
|
|
54
|
+
assert.equal(decision.proposedPolicy, 'long_pass_through');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('does not manufacture a side policy when neither side passes the frozen rule', () => {
|
|
58
|
+
const decision = evaluateDirectionPolicyCheckpoint({
|
|
59
|
+
usefulSideRule: rule,
|
|
60
|
+
raw: {
|
|
61
|
+
ALL: metric(500, -200, -0.4, 0.8, 0.5),
|
|
62
|
+
LONG: metric(250, -80, -0.32, 0.9, 0.25),
|
|
63
|
+
SHORT: metric(250, -120, -0.48, 0.85, 0.25),
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
assert.equal(decision.required, false);
|
|
68
|
+
assert.equal(decision.trigger, 'no_side_salvage');
|
|
69
|
+
assert.equal(decision.proposedPolicy, 'both');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('rejects incomplete metric inputs instead of guessing', () => {
|
|
73
|
+
assert.throws(
|
|
74
|
+
() =>
|
|
75
|
+
evaluateDirectionPolicyCheckpoint({
|
|
76
|
+
usefulSideRule: rule,
|
|
77
|
+
raw: {
|
|
78
|
+
ALL: metric(1, 1, 1, 1, 1),
|
|
79
|
+
LONG: metric(1, 1, 1, 1, 1),
|
|
80
|
+
SHORT: { trades: 1 },
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
/raw\.SHORT\.pnl must be finite/,
|
|
84
|
+
);
|
|
85
|
+
});
|