{
  "tool_id": "art-489-model-test-battery",
  "tool_version": "1.0.0",
  "display_name": "Model Test Battery",
  "mcp_name": "run_model_test_battery",
  "mandate_type": "compliance_control",
  "wave": 77,
  "gpu": false,
  "url": "https://ainumbers.co/chaingraph/art-489-model-test-battery.html",
  "description": "Runs the deterministic-given-data quantitative model validation battery: discriminatory power (Gini coefficient, Kolmogorov-Smirnov statistic) from scored outcomes, population and characteristic stability (PSI, CSI) between two declared snapshots using the caller's own bins, back-test outcome-vs-predicted per declared bin, and a calibration comparison (predicted vs actual rate, max absolute diff). Every test is graded against a POLICY-SUPPLIED threshold object -- this node never chooses or hardcodes a threshold. If a threshold is missing for a requested test, that test is reported skipped_no_threshold, never silently defaulted; if the underlying data is missing or insufficient (e.g. a single-class scored set for Gini/KS), the test is reported skipped_insufficient_data. Each result carries the test's standard name, its metric value, its threshold, and pass/breach so the artifact reads as a workpaper section, not an opinion. Model inputs and specifications are expected to arrive as a workbook export via the shipped WB-BRIDGE-1 workbook-to-OCG artifact bridge (tool 554); this node itself accepts plain JSON so any upstream source can feed it. Pairs with art-488 model-replication-diff (recompute-and-diff) as the two deterministic legs of a model validation cycle -- neither node emits a soundness or fitness-for-use opinion. Inline deterministic transcendental math (no engine Math.exp/log) so the same input always produces the same execution_hash on every surface. NaN-safe. Zero network, zero PII.",
  "input_schema_ref": "chaingraph/art-489-model-test-battery.html#manifest",
  "consumes": [],
  "feeds": [],
  "status": "live",
  "conformance_fixtures": true,
  "compute_capability": "server",
  "compute_images": [{"system":"sha256-source","image_id":"sha256:20e07ad532c59a2c5619ce03881ce808c367002a5572176618bbb8b6ba06e178","valid_from":"2026-07-10"},{"system":"risc0","image_id":"sha256:a1a0bc89b5b1febaeda3519f6dbade0fa5ac16beeb143c4e1b01689573567bc6","valid_from":"2026-06-28"}],
  "export_capability": [
    "json"
  ],
  "compute_proof_ready": "ready",
  "compute_proof": {
    "type": "ZkVmReceipt",
    "system": "risc0",
    "receiptFormat": "groth16-bn254",
    "imageId": "sha256:a1a0bc89b5b1febaeda3519f6dbade0fa5ac16beeb143c4e1b01689573567bc6",
    "seal": "GpTmEqL3pSA6aIHJ4PWZEVFd93WO+zRi7jrg4Aj/jJkFi+zaCBStX5mM0Xe8dzdt+cJuF5rCjFWo93A5MnmfGhouHskrlZO1QMLiXmRR6uCSNBsLhbb5OcrO2+iBFV6CGTxxEYEcGm7cRbaDhr44R1bIVVRn6aWtVSYI0EyvqeUrPjpb5Zl4PISwJnCXxoSGyvuqZWM+fam1nRuqrJN65wPKr0CndimDsTKmUMmzmfyvWwqq3xFTjvYSrzK3jTFQJ6OpSgi0ghxupAmVcNfJOZNl2royRnuwKwsCboa+ErYrqzD94K9a04RGtgx7bzEWXxQGubXASDXpFa860CgiOw==",
    "journal": {
      "chaingraph_version": "0.4.0",
      "kernel_digest": "sha256:20e07ad532c59a2c5619ce03881ce808c367002a5572176618bbb8b6ba06e178",
      "output": {
        "as_of_date": "2026-01-15",
        "back_test": {
          "per_bin": [
            {
              "abs_diff": 0.02,
              "actual_rate": 0.07,
              "bin": "1",
              "n": 100,
              "predicted_rate": 0.05
            },
            {
              "abs_diff": 0.01,
              "actual_rate": 0.09,
              "bin": "2",
              "n": 80,
              "predicted_rate": 0.1
            }
          ]
        },
        "tests": [
          {
            "comparison": ">=",
            "detail": {
              "auc": 1,
              "n_negative": 3,
              "n_positive": 3,
              "n_scored": 6
            },
            "metric_value": 1,
            "name": "gini_coefficient",
            "result": "pass",
            "standard_name": "Gini coefficient",
            "threshold": 0.4,
            "threshold_field": "gini_min"
          },
          {
            "comparison": ">=",
            "detail": {
              "n_negative": 3,
              "n_positive": 3,
              "n_scored": 6
            },
            "metric_value": 1,
            "name": "ks_statistic",
            "result": "pass",
            "standard_name": "Kolmogorov-Smirnov statistic",
            "threshold": 0.3,
            "threshold_field": "ks_min"
          },
          {
            "comparison": "<=",
            "detail": [
              {
                "actual_pct": 0.45,
                "bin": "low",
                "contribution": 0.0052680258,
                "expected_pct": 0.5
              },
              {
                "actual_pct": 0.55,
                "bin": "high",
                "contribution": 0.004765509,
                "expected_pct": 0.5
              }
            ],
            "metric_value": 0.0100335348,
            "name": "population_stability_index",
            "result": "pass",
            "standard_name": "Population Stability Index (PSI)",
            "threshold": 0.25,
            "threshold_field": "psi_max"
          },
          {
            "comparison": "<=",
            "detail": [
              {
                "characteristic": "ltv",
                "detail": [
                  {
                    "actual_pct": 0.4,
                    "bin": "low",
                    "contribution": 0.0223143551,
                    "expected_pct": 0.5
                  },
                  {
                    "actual_pct": 0.6,
                    "bin": "high",
                    "contribution": 0.0182321557,
                    "expected_pct": 0.5
                  }
                ],
                "index": 0.0405465108
              }
            ],
            "metric_value": 0.0405465108,
            "name": "characteristic_stability_index",
            "result": "pass",
            "standard_name": "Characteristic Stability Index (CSI, max across characteristics)",
            "threshold": 0.25,
            "threshold_field": "csi_max"
          },
          {
            "comparison": "<=",
            "detail": [
              {
                "abs_diff": 0.02,
                "actual_rate": 0.07,
                "bin": "1",
                "n": 100,
                "predicted_rate": 0.05
              },
              {
                "abs_diff": 0.01,
                "actual_rate": 0.09,
                "bin": "2",
                "n": 80,
                "predicted_rate": 0.1
              }
            ],
            "metric_value": 0.02,
            "name": "calibration",
            "result": "pass",
            "standard_name": "Calibration (predicted vs actual rate per bin, max abs diff)",
            "threshold": 0.05,
            "threshold_field": "calibration_max_diff"
          }
        ],
        "tests_breached": 0,
        "tests_passed": 5,
        "tests_run": 5,
        "tests_skipped_insufficient_data": 0,
        "tests_skipped_no_threshold": 0,
        "threshold_version": "policy-2026-Q1",
        "thresholds_applied": {
          "calibration_max_diff": 0.05,
          "csi_max": 0.25,
          "gini_min": 0.4,
          "ks_min": 0.3,
          "psi_max": 0.25
        }
      }
    }
  }
}
