canli-validation-mcp 0.13.0 → 0.13.1
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 +8 -7
- package/package.json +3 -3
- package/src/schemas.mjs +15 -1
- package/src/server.mjs +3 -2
package/README.md
CHANGED
|
@@ -420,10 +420,11 @@ Every envelope this server returns carries these sentences, verbatim, from the A
|
|
|
420
420
|
its costs, survivorship, or any lookahead in how the series was built.
|
|
421
421
|
- A deflated Sharpe or overfitting probability above or below any threshold is not admission to
|
|
422
422
|
anything and is not a forecast.
|
|
423
|
-
- The receipt is content-hashed
|
|
424
|
-
|
|
423
|
+
- The receipt is content-hashed, reproducible from the open-source core it names, and signed with
|
|
424
|
+
Ed25519 by a key published at https://canlicapital.com/.well-known/canli-receipt-keys.json.
|
|
425
425
|
- Quotas: 1000 validations per key per UTC day, 5 keys per client per UTC day, 1048576 bytes per
|
|
426
|
-
request, 20000 observations per series, 200
|
|
426
|
+
validation request, 1024 bytes per key revocation request, 20000 observations per series, 200
|
|
427
|
+
variants per matrix.
|
|
427
428
|
|
|
428
429
|
Each tool's description also states one of these sentences, so an agent sees the boundary before
|
|
429
430
|
it calls the tool, not only after.
|
|
@@ -459,10 +460,10 @@ tokenizers give different absolute counts), in the shape an OpenAI-style client
|
|
|
459
460
|
|
|
460
461
|
| CANLI_TOOLSETS | tools | tokens per turn | of all |
|
|
461
462
|
|---|---|---|---|
|
|
462
|
-
| (default) | 19 | 5,
|
|
463
|
-
| (default, with CANLI_KEY) | 18 | 5,
|
|
464
|
-
| `all` | 20 | 6,
|
|
465
|
-
| `validate` | 11 | 3,
|
|
463
|
+
| (default) | 19 | 5,978 | 96% |
|
|
464
|
+
| (default, with CANLI_KEY) | 18 | 5,842 | 93% |
|
|
465
|
+
| `all` | 20 | 6,249 | 100% |
|
|
466
|
+
| `validate` | 11 | 3,658 | 59% |
|
|
466
467
|
| `receipts` | 1 | 182 | 3% |
|
|
467
468
|
| `company` | 1 | 273 | 4% |
|
|
468
469
|
| `status` | 1 | 89 | 1% |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "canli-validation-mcp",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "Check whether a backtest is real: deflated Sharpe, CSCV probability of backtest overfitting, minimum track record and backtest length, haircut Sharpe and luck-equivalent trials, as an MCP server. Local mode, hosted endpoint, signed receipts.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"test:package": "node test/package-smoke.mjs"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@modelcontextprotocol/server": "2.1
|
|
41
|
+
"@modelcontextprotocol/server": "2.3.1",
|
|
42
42
|
"zod": "4.6.5"
|
|
43
43
|
},
|
|
44
44
|
"mcpName": "io.github.arhancanli/canli-validation-mcp",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"url": "https://github.com/arhancanli/canlicapital/issues"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@modelcontextprotocol/client": "2.1
|
|
55
|
+
"@modelcontextprotocol/client": "2.3.1",
|
|
56
56
|
"fast-check": "4.10.2"
|
|
57
57
|
}
|
|
58
58
|
}
|
package/src/schemas.mjs
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// docs/superpowers/specs/2026-09-05-developer-key-validation-api-design.md section 4 for the
|
|
8
8
|
// validator semantics these shapes mirror.
|
|
9
9
|
import { z } from "zod";
|
|
10
|
+
import { NULL_ZOO_V1 } from "./local/js/null-zoo-v1-sizes.js";
|
|
10
11
|
|
|
11
12
|
// One description per input field, shared by every shape that uses the field, so a client reads
|
|
12
13
|
// the same meaning, unit and example wherever the field appears. Agents choose arguments from
|
|
@@ -331,13 +332,26 @@ export const LIMITS_SENTENCES = Object.freeze({
|
|
|
331
332
|
export const REGISTRY_LIMITS_CLAUSE = "is not admission to anything and is not a forecast.";
|
|
332
333
|
export const REGISTRY_DESCRIPTION_MAX = 100;
|
|
333
334
|
|
|
335
|
+
// The headline tests audit_backtest can run, by the names the shipped size table uses. The
|
|
336
|
+
// description reads the chosen ones from that table, so it cannot name a test the audit does not run.
|
|
337
|
+
export const HEADLINE_TEST_NAMES = Object.freeze({
|
|
338
|
+
reality_check: "White's Reality Check",
|
|
339
|
+
spa_consistent: "Hansen's SPA",
|
|
340
|
+
spa_upper: "Hansen's SPA (upper p-value)",
|
|
341
|
+
luck_trials_lo: "luck trials with Lo's correction",
|
|
342
|
+
});
|
|
343
|
+
const headlineName = (test) => {
|
|
344
|
+
if (!HEADLINE_TEST_NAMES[test]) throw new Error(`No description name for the headline test ${test}`);
|
|
345
|
+
return HEADLINE_TEST_NAMES[test];
|
|
346
|
+
};
|
|
347
|
+
|
|
334
348
|
// One tool description per tool, each stating (in one sentence lifted from the boundary language
|
|
335
349
|
// above) what the tool's result cannot be used to claim, so an agent sees this before it ever
|
|
336
350
|
// calls the tool, not only inside the returned envelope.
|
|
337
351
|
export const TOOL_DESCRIPTIONS = Object.freeze({
|
|
338
352
|
get_key: `Issue a free validation key for this session. Rarely needed: the first validation issues one itself unless CANLI_KEY or local mode is set, and the read tools need none. ${LIMITS_SENTENCES.quotas}`,
|
|
339
353
|
validate_deflated_sharpe: `Deflated Sharpe ratio: the probability (0 to 1) that the selected strategy's Sharpe beats the best that luck gives across the variants tried, with the probabilistic Sharpe and that luck benchmark. Send the seven statistics or a return series. With every variant's returns use validate_overfitting; luck as a trial count, validate_luck_trials; a multiple-testing haircut, validate_haircut_sharpe. ${LIMITS_SENTENCES.notAdmission}`,
|
|
340
|
-
audit_backtest: `One-call audit of a strategy's returns. Headline: one test whose false-positive rate was measured on nine return shapes (
|
|
354
|
+
audit_backtest: `One-call audit of a strategy's returns. Headline: one test whose false-positive rate was measured on nine return shapes (${headlineName(NULL_ZOO_V1.with_variants.test)} with variants, ${headlineName(NULL_ZOO_V1.single_series.test)} without). Then deflated Sharpe, minimum track record and, with variants, overfitting and out-of-sample decay, each with its receipt, plus fix_next. Send every variant tried (variants_file) so trials are counted; point returns_file at a CSV instead of pasting. ${LIMITS_SENTENCES.notAdmission}`,
|
|
341
355
|
validate_overfitting: `Probability of backtest overfitting (0 to 1) by CSCV: how often the in-sample best variant falls below the out-of-sample median. Needs every variant's returns (periods by variants); with summary statistics only, use validate_deflated_sharpe. ${LIMITS_SENTENCES.notAdmission}`,
|
|
342
356
|
validate_reality_check: `Data-snooping tests on every variant a search tried: Hansen's SPA p-value that the best beat the benchmark only by luck, White's Reality Check, and the variants Romano-Wolf StepM finds better. Send all variants tried, not only the winners. ${LIMITS_SENTENCES.notAdmission}`,
|
|
343
357
|
validate_paper_evidence: `Checks paper-evidence.v0 structure and disclosures. With CANLI_LOCAL=1, record_file reads an export bundle and journal_file verifies signatures, source hashes and recomputed claims. Without a journal, source facts and signatures are unchecked. Local files are never uploaded. ${LIMITS_SENTENCES.scope}`,
|
package/src/server.mjs
CHANGED
|
@@ -339,8 +339,9 @@ async function runValidator(session, tool, path, body) {
|
|
|
339
339
|
const sameJson = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
340
340
|
|
|
341
341
|
// audit_backtest: one calibrated test first, then the checks behind it.
|
|
342
|
-
// headline with every variant's returns,
|
|
343
|
-
//
|
|
342
|
+
// headline with every variant's returns, the test Null Zoo v1 chose from validate_reality_check's
|
|
343
|
+
// result (White's Reality Check since 0.12.0), with its receipt; with one series, the
|
|
344
|
+
// single-series test it chose. Either way the result quotes
|
|
344
345
|
// that test's measured false-positive rate on returns shaped like these
|
|
345
346
|
// (local/js/null-zoo-v1-sizes.js) and the worst across the nine families.
|
|
346
347
|
// checks the deflated Sharpe (an estimate), the minimum track record and, with variants, CSCV
|