#!/usr/bin/env node /** * CI-style validation for the simulation-only capital efficiency overlay. * * Checks: * - JSON configs and scenario files parse. * - Baseline scenario stays capital-overlay free. * - Capital stress scenarios emit required risk metrics. * - Deterministic seeds produce byte-identical scorecards. * - Optimizer never marks leverage above policy gates as deployable. */ const fs = require('fs'); const path = require('path'); const { execFileSync } = require('child_process'); const ROOT = path.join(__dirname, '..'); const CONFIG_DIR = path.join(ROOT, 'config'); const SCENARIOS_DIR = path.join(CONFIG_DIR, 'scenarios'); const RUNNER = path.join(ROOT, 'scripts', 'run-scenario.cjs'); const REQUIRED_CAPITAL_FIELDS = [ 'roi_mean', 'roi_p05', 'roi_p95', 'pnl_distribution', 'max_drawdown_p95', 'liquidation_probability', 'peg_deviation_frequency', 'external_liquidity_floor_violations', 'volatility_throttle_events', 'spread_adjustment_events', ]; const STRESS_SCENARIOS = [ 'crash_40pct_external_asset', 'high_vol_sigma_spike', 'bank_run_redemption_spike', ]; function readJson(file) { return JSON.parse(fs.readFileSync(file, 'utf8')); } function runScenario(name, extraArgs = []) { const out = execFileSync(process.execPath, [RUNNER, ...extraArgs, name], { cwd: ROOT, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], }); return { raw: out, json: JSON.parse(out) }; } function fail(msg) { process.stderr.write(`[capital-efficiency] ${msg}\n`); process.exit(1); } function assert(cond, msg) { if (!cond) fail(msg); } function main() { const files = [ path.join(CONFIG_DIR, 'scenario-schema.json'), path.join(CONFIG_DIR, 'scorecard-schema.json'), path.join(CONFIG_DIR, 'capital-efficiency-policy.json'), ...fs.readdirSync(SCENARIOS_DIR) .filter((f) => f.endsWith('.json')) .map((f) => path.join(SCENARIOS_DIR, f)), ]; for (const file of files) readJson(file); const policy = readJson(path.join(CONFIG_DIR, 'capital-efficiency-policy.json')); const maxDeployableLeverage = Number(policy.gates?.maxDeployableLeverage ?? policy.risk?.hardMaxLeverage ?? 4); const gates = policy.gates || {}; const maxLiquidationProbability = Number(gates.maxLiquidationProbability ?? 0.02); const maxDrawdownP95 = Number(gates.maxDrawdownP95 ?? 0.25); const maxPegDeviationFrequency = Number(gates.maxPegDeviationFrequency ?? 0.05); const maxExternalLiquidityFloorViolations = Number(gates.maxExternalLiquidityFloorViolations ?? 0); const guard = policy.liveExecutionGuard || {}; assert(guard.status === 'simulation_only', 'liveExecutionGuard.status must remain simulation_only until external approvals exist'); assert(guard.riskDashboardEvidence, 'risk dashboard evidence path is required'); assert(guard.operatorRunbookEvidence, 'operator runbook evidence path is required'); assert(guard.treasuryLiquidityCommitmentEvidence, 'treasury liquidity commitment evidence path is required'); for (const evidencePath of [ guard.riskDashboardEvidence, guard.operatorRunbookEvidence, guard.treasuryLiquidityCommitmentEvidence, ]) { assert(fs.existsSync(path.join(ROOT, evidencePath)), `evidence path missing: ${evidencePath}`); } const baseline = runScenario('hub_only_11').json; assert(baseline.capital_efficiency_enabled !== true, 'hub_only_11 unexpectedly enabled capital overlay'); for (const scenario of [ 'chain138_deployed_capital_efficiency', ...STRESS_SCENARIOS, ]) { const scorecard = runScenario(scenario).json; assert(scorecard.capital_efficiency_enabled === true, `${scenario} did not emit capital overlay`); for (const field of REQUIRED_CAPITAL_FIELDS) { assert(Object.prototype.hasOwnProperty.call(scorecard, field), `${scenario} missing ${field}`); } if (STRESS_SCENARIOS.includes(scenario)) { assert(scorecard.liquidation_probability <= maxLiquidationProbability, `${scenario} liquidation probability exceeds gate`); assert(scorecard.max_drawdown_p95 <= maxDrawdownP95, `${scenario} p95 drawdown exceeds gate`); assert(scorecard.peg_deviation_frequency <= maxPegDeviationFrequency, `${scenario} peg deviation frequency exceeds gate`); assert(scorecard.external_liquidity_floor_violations <= maxExternalLiquidityFloorViolations, `${scenario} external liquidity floor violations exceed gate`); } } const a = runScenario('crash_40pct_external_asset').raw; const b = runScenario('crash_40pct_external_asset').raw; assert(a === b, 'deterministic seed repeat check failed for crash_40pct_external_asset'); const optimizer = runScenario('leverage_sweep_1x_to_4x', ['--optimizer']).json; assert(optimizer.optimizer_enabled === true, 'optimizer did not emit optimizer payload'); for (const candidate of optimizer.top_candidates || []) { if (candidate.deployable) { assert(candidate.leverage <= maxDeployableLeverage, `deployable candidate exceeds maxDeployableLeverage: ${candidate.leverage}`); } } process.stdout.write('capital efficiency validation OK\n'); } main();