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 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 and reproducible from the open-source core it names. It is not
424
- signed.
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 variants per matrix.
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,970 | 96% |
463
- | (default, with CANLI_KEY) | 18 | 5,834 | 93% |
464
- | `all` | 20 | 6,241 | 100% |
465
- | `validate` | 11 | 3,650 | 58% |
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.0",
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.0",
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.0",
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 (Hansen's SPA with variants). 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}`,
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, Hansen's SPA (validate_reality_check, with its receipt);
343
- // with one series, the single-series test Null Zoo v1 chose. Either way the result quotes
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