@neuroverseos/nv-sim 0.1.2 → 0.1.6
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 +376 -66
- package/dist/adapters/mirofish.js +461 -0
- package/dist/adapters/scienceclaw.js +750 -0
- package/dist/assets/index-CHmUN8s0.js +532 -0
- package/dist/assets/index-DWgMnB7I.css +1 -0
- package/dist/assets/mirotir-logo-DUexumBH.svg +185 -0
- package/dist/assets/reportEngine-BVdQ2_nW.js +1 -0
- package/dist/components/ConstraintsPanel.js +11 -0
- package/dist/components/StakeholderBuilder.js +32 -0
- package/dist/components/ui/badge.js +24 -0
- package/dist/components/ui/button.js +70 -0
- package/dist/components/ui/card.js +57 -0
- package/dist/components/ui/input.js +44 -0
- package/dist/components/ui/label.js +45 -0
- package/dist/components/ui/select.js +70 -0
- package/dist/engine/aiProvider.js +681 -0
- package/dist/engine/auditTrace.js +352 -0
- package/dist/engine/behavioralAnalysis.js +605 -0
- package/dist/engine/cli.js +1408 -299
- package/dist/engine/dynamicsGovernance.js +588 -0
- package/dist/engine/fullGovernedLoop.js +367 -0
- package/dist/engine/governance.js +8 -3
- package/dist/engine/governedSimulation.js +114 -17
- package/dist/engine/index.js +56 -1
- package/dist/engine/liveAdapter.js +342 -0
- package/dist/engine/liveVisualizer.js +3063 -0
- package/dist/engine/metrics/science.metrics.js +335 -0
- package/dist/engine/narrativeInjection.js +305 -0
- package/dist/engine/policyEnforcement.js +1611 -0
- package/dist/engine/policyEngine.js +799 -0
- package/dist/engine/primeRadiant.js +540 -0
- package/dist/engine/reasoningEngine.js +57 -3
- package/dist/engine/reportEngine.js +97 -0
- package/dist/engine/scenarioComparison.js +463 -0
- package/dist/engine/scenarioLibrary.js +231 -0
- package/dist/engine/swarmSimulation.js +54 -1
- package/dist/engine/worldComparison.js +358 -0
- package/dist/engine/worldStorage.js +232 -0
- package/dist/favicon.ico +0 -0
- package/dist/index.html +23 -0
- package/dist/lib/reasoningEngine.js +290 -0
- package/dist/lib/simulationAdapter.js +686 -0
- package/dist/lib/swarmParser.js +291 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/utils.js +8 -0
- package/dist/placeholder.svg +1 -0
- package/dist/robots.txt +14 -0
- package/dist/runtime/govern.js +473 -0
- package/dist/runtime/index.js +75 -0
- package/dist/runtime/types.js +11 -0
- package/package.json +17 -12
- package/variants/.gitkeep +0 -0
package/dist/engine/cli.js
CHANGED
|
@@ -51,9 +51,14 @@ const analyzer_1 = require("./analyzer");
|
|
|
51
51
|
const api_1 = require("./api");
|
|
52
52
|
const governedSimulation_1 = require("./governedSimulation");
|
|
53
53
|
const chaosEngine_1 = require("./chaosEngine");
|
|
54
|
+
const worldComparison_1 = require("./worldComparison");
|
|
55
|
+
const liveVisualizer_1 = require("./liveVisualizer");
|
|
56
|
+
const narrativeInjection_1 = require("./narrativeInjection");
|
|
57
|
+
const scenarioLibrary_1 = require("./scenarioLibrary");
|
|
54
58
|
const scenarioCapsule_1 = require("./scenarioCapsule");
|
|
59
|
+
const behavioralAnalysis_1 = require("./behavioralAnalysis");
|
|
55
60
|
const fs = __importStar(require("fs"));
|
|
56
|
-
const
|
|
61
|
+
const child_process_1 = require("child_process");
|
|
57
62
|
// ============================================
|
|
58
63
|
// CLI ARGUMENT PARSING
|
|
59
64
|
// ============================================
|
|
@@ -68,7 +73,8 @@ async function main() {
|
|
|
68
73
|
}
|
|
69
74
|
switch (command) {
|
|
70
75
|
case "compare": {
|
|
71
|
-
const presetId = args[1]
|
|
76
|
+
const presetId = (args[1] && !args[1].startsWith("--")) ? args[1] : "trading";
|
|
77
|
+
const narrativeEvents = (0, narrativeInjection_1.parseInjectArgs)(args);
|
|
72
78
|
console.log(`\n NV-SIM — Governed Simulation Comparison\n`);
|
|
73
79
|
console.log(` "We ran the same simulation twice.`);
|
|
74
80
|
console.log(` The only difference was the world rules."\n`);
|
|
@@ -78,7 +84,7 @@ async function main() {
|
|
|
78
84
|
if (presetId === "trading" || presetId === "flash_crash") {
|
|
79
85
|
console.log(` Scenario: Flash Crash — Algorithmic Cascade\n`);
|
|
80
86
|
worldId = "trading-flash-crash";
|
|
81
|
-
result = await (0, governedSimulation_1.runGovernedComparison)(governedSimulation_1.TRADING_DEMO.scenario, governedSimulation_1.TRADING_DEMO.world, governedSimulation_1.TRADING_DEMO.paths);
|
|
87
|
+
result = await (0, governedSimulation_1.runGovernedComparison)(governedSimulation_1.TRADING_DEMO.scenario, governedSimulation_1.TRADING_DEMO.world, governedSimulation_1.TRADING_DEMO.paths, narrativeEvents.length > 0 ? narrativeEvents : undefined);
|
|
82
88
|
}
|
|
83
89
|
else {
|
|
84
90
|
// Try to use an existing preset
|
|
@@ -126,11 +132,135 @@ async function main() {
|
|
|
126
132
|
harms_stakeholders: [],
|
|
127
133
|
},
|
|
128
134
|
];
|
|
129
|
-
result = await (0, governedSimulation_1.runGovernedComparison)(request, template.world.inline_definition, paths);
|
|
135
|
+
result = await (0, governedSimulation_1.runGovernedComparison)(request, template.world.inline_definition, paths, narrativeEvents.length > 0 ? narrativeEvents : undefined);
|
|
136
|
+
}
|
|
137
|
+
if (narrativeEvents.length > 0) {
|
|
138
|
+
console.log(`\n NARRATIVE INJECTIONS`);
|
|
139
|
+
console.log(" " + "-".repeat(50));
|
|
140
|
+
for (const ne of narrativeEvents) {
|
|
141
|
+
console.log(` [Round ${ne.round}] "${ne.headline}" (${ne.severity}, ${ne.propagation})`);
|
|
142
|
+
}
|
|
130
143
|
}
|
|
131
144
|
printComparisonResults(result, worldId);
|
|
132
145
|
break;
|
|
133
146
|
}
|
|
147
|
+
case "worlds": {
|
|
148
|
+
const worldAId = args[1];
|
|
149
|
+
const worldBId = args[2];
|
|
150
|
+
if (!worldAId || !worldBId) {
|
|
151
|
+
console.error(" Usage: npx nv-sim worlds <world-a> <world-b>");
|
|
152
|
+
console.error(" Example: npx nv-sim worlds trading strait_of_hormuz");
|
|
153
|
+
console.error(` Available: trading, ${Object.keys(scenarioCapsule_1.SCENARIO_TEMPLATES).join(", ")}`);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
console.log(`\n NV-SIM — World Comparison\n`);
|
|
157
|
+
console.log(` "Same agents. Different rules.`);
|
|
158
|
+
console.log(` The world shapes the outcome."\n`);
|
|
159
|
+
console.log(" " + "=".repeat(60));
|
|
160
|
+
const wcResult = await (0, worldComparison_1.runWorldComparison)(worldAId, worldBId, {
|
|
161
|
+
onProgress: (label, phase) => {
|
|
162
|
+
console.log(` ${label}: ${phase}...`);
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
printWorldComparisonResults(wcResult);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case "scenario": {
|
|
169
|
+
const scenarioId = args[1];
|
|
170
|
+
const doCompare = args.includes("--compare");
|
|
171
|
+
if (!scenarioId || scenarioId.startsWith("--")) {
|
|
172
|
+
console.error(" Usage: nv-sim scenario <scenario-id> [--compare]");
|
|
173
|
+
console.error(` Available: ${Object.keys(scenarioLibrary_1.SCENARIO_LIBRARY).join(", ")}`);
|
|
174
|
+
console.error(" Run `nv-sim scenarios` to see all scenarios.");
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
const scenario = scenarioLibrary_1.SCENARIO_LIBRARY[scenarioId];
|
|
178
|
+
if (!scenario) {
|
|
179
|
+
console.error(` Unknown scenario: ${scenarioId}`);
|
|
180
|
+
console.error(` Available: ${Object.keys(scenarioLibrary_1.SCENARIO_LIBRARY).join(", ")}`);
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
console.log(`\n NV-SIM — Scenario: ${scenario.title}\n`);
|
|
184
|
+
console.log(` ${scenario.description}\n`);
|
|
185
|
+
console.log(" " + "=".repeat(60));
|
|
186
|
+
console.log(` World: ${scenario.world}`);
|
|
187
|
+
console.log(` Events:`);
|
|
188
|
+
const scenarioEvents = (0, scenarioLibrary_1.resolveScenarioEvents)(scenario);
|
|
189
|
+
for (const ev of scenarioEvents) {
|
|
190
|
+
console.log(` [Round ${ev.round}] ${ev.headline} (${ev.severity}, ${ev.propagation})`);
|
|
191
|
+
}
|
|
192
|
+
console.log();
|
|
193
|
+
// Resolve world
|
|
194
|
+
const { resolveWorld } = await Promise.resolve().then(() => __importStar(require("./worldComparison")));
|
|
195
|
+
const resolved = resolveWorld(scenario.world);
|
|
196
|
+
const rounds = scenario.rounds ?? resolved.swarm.rounds ?? 5;
|
|
197
|
+
const request = {
|
|
198
|
+
scenario: resolved.scenario,
|
|
199
|
+
stakeholders: resolved.stakeholders,
|
|
200
|
+
assumptions: resolved.assumptions,
|
|
201
|
+
constraints: resolved.constraints,
|
|
202
|
+
depth: resolved.depth,
|
|
203
|
+
swarm: { ...resolved.swarm, rounds },
|
|
204
|
+
};
|
|
205
|
+
// Run primary scenario
|
|
206
|
+
console.log(` Running scenario on world "${scenario.world}"...`);
|
|
207
|
+
const primaryResult = await (0, governedSimulation_1.runGovernedComparison)(request, resolved.world, resolved.paths, scenarioEvents);
|
|
208
|
+
printComparisonResults(primaryResult, scenario.world);
|
|
209
|
+
// --compare: run across additional worlds
|
|
210
|
+
if (doCompare && scenario.compareWorlds && scenario.compareWorlds.length > 0) {
|
|
211
|
+
console.log(`\n ${"=".repeat(60)}`);
|
|
212
|
+
console.log(` CROSS-WORLD COMPARISON`);
|
|
213
|
+
console.log(` Running same scenario across ${scenario.compareWorlds.length} additional world(s)...\n`);
|
|
214
|
+
for (const altWorldId of scenario.compareWorlds) {
|
|
215
|
+
const altResolved = resolveWorld(altWorldId);
|
|
216
|
+
const altRounds = scenario.rounds ?? altResolved.swarm.rounds ?? 5;
|
|
217
|
+
const altRequest = {
|
|
218
|
+
scenario: altResolved.scenario,
|
|
219
|
+
stakeholders: altResolved.stakeholders,
|
|
220
|
+
assumptions: altResolved.assumptions,
|
|
221
|
+
constraints: altResolved.constraints,
|
|
222
|
+
depth: altResolved.depth,
|
|
223
|
+
swarm: { ...altResolved.swarm, rounds: altRounds },
|
|
224
|
+
};
|
|
225
|
+
console.log(` Running on world "${altWorldId}"...`);
|
|
226
|
+
const altResult = await (0, governedSimulation_1.runGovernedComparison)(altRequest, altResolved.world, altResolved.paths, scenarioEvents);
|
|
227
|
+
// Print condensed comparison
|
|
228
|
+
const pm = primaryResult.governed.metrics;
|
|
229
|
+
const am = altResult.governed.metrics;
|
|
230
|
+
console.log(`\n ${scenario.world} vs ${altWorldId}`);
|
|
231
|
+
console.log(" " + "-".repeat(50));
|
|
232
|
+
console.log(` ${scenario.world.padEnd(25)} Stability: ${(pm.stabilityScore * 100).toFixed(0)}% Collapse: ${(pm.collapseProbability * 100).toFixed(0)}% Volatility: ${(pm.maxVolatility * 100).toFixed(0)}%`);
|
|
233
|
+
console.log(` ${altWorldId.padEnd(25)} Stability: ${(am.stabilityScore * 100).toFixed(0)}% Collapse: ${(am.collapseProbability * 100).toFixed(0)}% Volatility: ${(am.maxVolatility * 100).toFixed(0)}%`);
|
|
234
|
+
const stabDiff = pm.stabilityScore - am.stabilityScore;
|
|
235
|
+
const winner = Math.abs(stabDiff) < 0.02 ? "tie" : stabDiff > 0 ? scenario.world : altWorldId;
|
|
236
|
+
console.log(` More resilient: ${winner === "tie" ? "roughly equal" : winner}`);
|
|
237
|
+
}
|
|
238
|
+
console.log(`\n Same events. Different rules. Different outcomes.`);
|
|
239
|
+
}
|
|
240
|
+
console.log(`\n Design rules. Run reality. See what changes.`);
|
|
241
|
+
console.log(` neuroverse-simulations | @neuroverseos\n`);
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
case "scenarios": {
|
|
245
|
+
console.log(`\n NV-SIM — Scenario Library\n`);
|
|
246
|
+
console.log(` "Named stress scenarios — run a crisis, not a config."\n`);
|
|
247
|
+
console.log(" " + "=".repeat(60));
|
|
248
|
+
const grouped = (0, scenarioLibrary_1.getScenariosByCategory)();
|
|
249
|
+
for (const [category, scenarios] of Object.entries(grouped)) {
|
|
250
|
+
console.log(`\n ${category.toUpperCase()}`);
|
|
251
|
+
console.log(" " + "-".repeat(40));
|
|
252
|
+
for (const s of scenarios) {
|
|
253
|
+
console.log(` ${s.id.padEnd(28)} ${s.title}`);
|
|
254
|
+
console.log(` ${"".padEnd(28)} ${s.description}`);
|
|
255
|
+
console.log(` ${"".padEnd(28)} World: ${s.world} | Events: ${s.events.length}${s.compareWorlds ? ` | Compare: ${s.compareWorlds.join(", ")}` : ""}\n`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
console.log(" " + "=".repeat(60));
|
|
259
|
+
console.log(` Usage: nv-sim scenario <id>`);
|
|
260
|
+
console.log(` nv-sim scenario <id> --compare (cross-world comparison)`);
|
|
261
|
+
console.log(`\n Example: nv-sim scenario taiwan_crisis --compare\n`);
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
134
264
|
case "analyze": {
|
|
135
265
|
const filePath = args[1];
|
|
136
266
|
let input;
|
|
@@ -279,47 +409,253 @@ async function main() {
|
|
|
279
409
|
}
|
|
280
410
|
case "visualize":
|
|
281
411
|
case "view": {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
412
|
+
console.log(`\n NV-SIM — Scenario Control Platform\n`);
|
|
413
|
+
const port = 3456;
|
|
414
|
+
(0, liveVisualizer_1.startInteractiveServer)(port, (url) => {
|
|
415
|
+
console.log(` Dashboard: ${url}`);
|
|
416
|
+
console.log(" Interactive world controls ready.\n");
|
|
417
|
+
console.log(" Change world rules, inject narrative events, run simulations.");
|
|
418
|
+
console.log(" Press Ctrl+C to stop.\n");
|
|
419
|
+
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
420
|
+
(0, child_process_1.exec)(`${openCmd} ${url}`, () => { });
|
|
421
|
+
});
|
|
422
|
+
await new Promise(() => { }); // block forever
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
case "serve":
|
|
426
|
+
case "govern": {
|
|
427
|
+
// Local governance runtime — external simulators POST to /api/evaluate
|
|
428
|
+
const governPort = args.includes("--port") ? parseInt(args[args.indexOf("--port") + 1], 10) : 3456;
|
|
429
|
+
console.log(`\n NV-SIM — Local Governance Runtime\n`);
|
|
430
|
+
console.log(` Runs on YOUR machine. No cloud. No cost.\n`);
|
|
431
|
+
console.log(" " + "=".repeat(60));
|
|
432
|
+
console.log(` Endpoint: http://localhost:${governPort}/api/evaluate`);
|
|
433
|
+
console.log(` Method: POST`);
|
|
434
|
+
console.log(` Contract: { actor, action, payload?, state?, world? }`);
|
|
435
|
+
console.log(` Response: { decision: ALLOW|BLOCK|MODIFY, reason, evidence }`);
|
|
436
|
+
console.log(" " + "=".repeat(60));
|
|
437
|
+
(0, liveVisualizer_1.startInteractiveServer)(governPort, (url) => {
|
|
438
|
+
console.log(`\n Server ready: ${url}`);
|
|
439
|
+
console.log(` Governance: ${url}/api/evaluate`);
|
|
440
|
+
console.log(` Dashboard: ${url}`);
|
|
441
|
+
console.log(` SSE stream: ${url}/events`);
|
|
442
|
+
console.log("");
|
|
443
|
+
console.log(" Session & Reporting:");
|
|
444
|
+
console.log(` Stats: GET ${url}/api/session`);
|
|
445
|
+
console.log(` Report: GET ${url}/api/session/report`);
|
|
446
|
+
console.log(` Report JSON: GET ${url}/api/session/report.json`);
|
|
447
|
+
console.log(` Reset: POST ${url}/api/session/reset`);
|
|
448
|
+
console.log(` Save: POST ${url}/api/session/save\n`);
|
|
449
|
+
console.log(" Workflow: evaluate → report → apply new rules → reset → compare");
|
|
450
|
+
console.log(" Waiting for simulator connections...");
|
|
451
|
+
console.log(" Press Ctrl+C to stop.\n");
|
|
452
|
+
});
|
|
453
|
+
await new Promise(() => { }); // block forever
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
case "run": {
|
|
457
|
+
// Run an external simulator with governance
|
|
458
|
+
const simId = args[1] ?? "mirofish";
|
|
459
|
+
const runPort = args.includes("--port") ? parseInt(args[args.indexOf("--port") + 1], 10) : 3456;
|
|
460
|
+
const noViewer = args.includes("--no-viewer");
|
|
461
|
+
console.log(`\n NV-SIM — Governed Simulation Runner\n`);
|
|
462
|
+
console.log(` Simulator: ${simId}`);
|
|
463
|
+
console.log(" " + "=".repeat(60));
|
|
464
|
+
// Step 1: Start governance server
|
|
465
|
+
console.log(` [1/3] Starting governance server on port ${runPort}...`);
|
|
466
|
+
const { createAdapter: ca, ADAPTER_REGISTRY: ar } = await Promise.resolve().then(() => __importStar(require("./liveAdapter")));
|
|
467
|
+
(0, liveVisualizer_1.startInteractiveServer)(runPort, (url) => {
|
|
468
|
+
console.log(` [1/3] Governance ready: ${url}/api/evaluate`);
|
|
469
|
+
// Step 2: Start simulator via live adapter
|
|
470
|
+
console.log(` [2/3] Starting ${simId} simulator...`);
|
|
471
|
+
// Check if we have a registry entry, otherwise try raw command
|
|
472
|
+
const adapterEntry = ar[simId];
|
|
473
|
+
if (!adapterEntry) {
|
|
474
|
+
console.error(` Unknown simulator: ${simId}`);
|
|
475
|
+
console.error(` Available: ${Object.keys(ar).join(", ")}`);
|
|
476
|
+
console.error(` Or provide command: nv-sim run generic --command "python sim.py"`);
|
|
477
|
+
process.exit(1);
|
|
478
|
+
}
|
|
479
|
+
const adapterOpts = {};
|
|
480
|
+
if (args.includes("--command")) {
|
|
481
|
+
adapterOpts.command = args[args.indexOf("--command") + 1];
|
|
482
|
+
}
|
|
483
|
+
if (args.includes("--args")) {
|
|
484
|
+
adapterOpts.args = args[args.indexOf("--args") + 1];
|
|
485
|
+
}
|
|
486
|
+
const adapter = ca(simId, adapterOpts);
|
|
487
|
+
if (!adapter) {
|
|
488
|
+
console.error(` Failed to create adapter for: ${simId}`);
|
|
489
|
+
process.exit(1);
|
|
490
|
+
}
|
|
491
|
+
let roundCount = 0;
|
|
492
|
+
adapter.on("round", (round) => {
|
|
493
|
+
roundCount++;
|
|
494
|
+
const actions = round.agentActions?.length ?? 0;
|
|
495
|
+
const events = round.systemEvents?.length ?? 0;
|
|
496
|
+
console.log(` [round ${round.round}] ${actions} actions, ${events} events`);
|
|
497
|
+
});
|
|
498
|
+
adapter.on("complete", () => {
|
|
499
|
+
console.log(`\n Simulation complete. ${roundCount} rounds processed.`);
|
|
500
|
+
console.log(` Dashboard: http://localhost:${runPort}`);
|
|
501
|
+
if (noViewer)
|
|
502
|
+
process.exit(0);
|
|
503
|
+
});
|
|
504
|
+
adapter.on("error", (err) => {
|
|
505
|
+
console.error(` Simulator error: ${err.message}`);
|
|
506
|
+
});
|
|
507
|
+
adapter.start().then(() => {
|
|
508
|
+
console.log(` [2/3] Simulator started.`);
|
|
509
|
+
console.log(` [3/3] Streaming governed output...\n`);
|
|
510
|
+
}).catch((err) => {
|
|
511
|
+
console.error(` Failed to start simulator: ${err.message}`);
|
|
512
|
+
process.exit(1);
|
|
513
|
+
});
|
|
514
|
+
// Open viewer unless --no-viewer
|
|
515
|
+
if (!noViewer) {
|
|
516
|
+
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
517
|
+
(0, child_process_1.exec)(`${openCmd} ${url}`, () => { });
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
await new Promise(() => { }); // block forever
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
case "world-from-doc": {
|
|
524
|
+
// Generate a world file from a plain-English document
|
|
525
|
+
const docPath = args[1];
|
|
526
|
+
if (!docPath) {
|
|
527
|
+
console.error("\n Usage: npx nv-sim world-from-doc <file>\n");
|
|
528
|
+
console.error(" Reads a document (.md, .txt, .pdf) and generates a world definition.\n");
|
|
529
|
+
console.error(" Examples:");
|
|
530
|
+
console.error(" npx nv-sim world-from-doc policy.md");
|
|
531
|
+
console.error(" npx nv-sim world-from-doc regulations.txt --output my-world.json");
|
|
532
|
+
console.error(" cat rules.txt | npx nv-sim world-from-doc -\n");
|
|
533
|
+
process.exit(1);
|
|
534
|
+
}
|
|
535
|
+
const fs = await Promise.resolve().then(() => __importStar(require("fs")));
|
|
536
|
+
const path = await Promise.resolve().then(() => __importStar(require("path")));
|
|
537
|
+
let docText;
|
|
538
|
+
if (docPath === "-") {
|
|
539
|
+
// Read from stdin
|
|
540
|
+
const chunks = [];
|
|
541
|
+
for await (const chunk of process.stdin) {
|
|
542
|
+
chunks.push(Buffer.from(chunk));
|
|
543
|
+
}
|
|
544
|
+
docText = Buffer.concat(chunks).toString("utf-8");
|
|
287
545
|
}
|
|
288
546
|
else {
|
|
289
|
-
const
|
|
290
|
-
if (!
|
|
291
|
-
console.error(
|
|
547
|
+
const resolved = path.resolve(docPath);
|
|
548
|
+
if (!fs.existsSync(resolved)) {
|
|
549
|
+
console.error(`\n Error: File not found: ${resolved}\n`);
|
|
292
550
|
process.exit(1);
|
|
293
551
|
}
|
|
294
|
-
|
|
295
|
-
scenario: template.scenario,
|
|
296
|
-
stakeholders: template.stakeholders,
|
|
297
|
-
assumptions: template.assumptions,
|
|
298
|
-
constraints: template.constraints,
|
|
299
|
-
depth: template.depth,
|
|
300
|
-
swarm: template.swarm,
|
|
301
|
-
};
|
|
302
|
-
const paths = [
|
|
303
|
-
{
|
|
304
|
-
id: "path_primary", label: "Primary Response",
|
|
305
|
-
description: "Most likely course of action",
|
|
306
|
-
projected_outcome: "Moderate disruption", probability: 0.6,
|
|
307
|
-
risk: "high", tradeoffs: ["Speed vs. thoroughness"],
|
|
308
|
-
benefits_stakeholders: template.stakeholders.filter(s => s.disposition === "supportive").map(s => s.id),
|
|
309
|
-
harms_stakeholders: template.stakeholders.filter(s => s.disposition === "hostile").map(s => s.id),
|
|
310
|
-
},
|
|
311
|
-
{
|
|
312
|
-
id: "path_defensive", label: "Defensive Posture",
|
|
313
|
-
description: "Conservative approach", projected_outcome: "Reduced damage",
|
|
314
|
-
probability: 0.7, risk: "moderate", tradeoffs: ["Safety vs. opportunity"],
|
|
315
|
-
benefits_stakeholders: template.stakeholders.filter(s => s.disposition !== "hostile").map(s => s.id),
|
|
316
|
-
harms_stakeholders: [],
|
|
317
|
-
},
|
|
318
|
-
];
|
|
319
|
-
comparisonResult = await (0, governedSimulation_1.runGovernedComparison)(request, template.world.inline_definition, paths);
|
|
552
|
+
docText = fs.readFileSync(resolved, "utf-8");
|
|
320
553
|
}
|
|
321
|
-
console.log(
|
|
322
|
-
|
|
554
|
+
console.log(`\n NV-SIM — World File Generator\n`);
|
|
555
|
+
console.log(` Reading: ${docPath === "-" ? "stdin" : docPath}`);
|
|
556
|
+
console.log(" " + "=".repeat(60));
|
|
557
|
+
// Parse the document into a world definition
|
|
558
|
+
const lines = docText.split("\n").map(l => l.trim()).filter(l => l.length > 0);
|
|
559
|
+
const worldId = args.includes("--id") ? args[args.indexOf("--id") + 1] : path.basename(docPath, path.extname(docPath)).replace(/\s+/g, "_").toLowerCase();
|
|
560
|
+
// Extract thesis (first paragraph or heading)
|
|
561
|
+
let thesis = "";
|
|
562
|
+
const invariants = [];
|
|
563
|
+
const gates = [];
|
|
564
|
+
const stateVars = [];
|
|
565
|
+
let invCount = 0;
|
|
566
|
+
let gateCount = 0;
|
|
567
|
+
for (const line of lines) {
|
|
568
|
+
const lower = line.toLowerCase();
|
|
569
|
+
// Skip markdown headers but use them for context
|
|
570
|
+
if (line.startsWith("#")) {
|
|
571
|
+
if (!thesis)
|
|
572
|
+
thesis = line.replace(/^#+\s*/, "");
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
// First non-header line as thesis if not set
|
|
576
|
+
if (!thesis && line.length > 10) {
|
|
577
|
+
thesis = line;
|
|
578
|
+
continue;
|
|
579
|
+
}
|
|
580
|
+
// Detect rules: lines starting with block/prevent/limit/require/allow etc
|
|
581
|
+
if (/^(block|prevent|prohibit|ban|stop|forbid|no\b|don.t|limit|cap|restrict)/i.test(lower)) {
|
|
582
|
+
invCount++;
|
|
583
|
+
invariants.push({
|
|
584
|
+
id: `INV-${String(invCount).padStart(3, "0")}`,
|
|
585
|
+
description: line.replace(/^[-*•]\s*/, ""),
|
|
586
|
+
enforceable: true,
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
else if (/^(require|must|shall|ensure|mandate)/i.test(lower)) {
|
|
590
|
+
invCount++;
|
|
591
|
+
invariants.push({
|
|
592
|
+
id: `INV-${String(invCount).padStart(3, "0")}`,
|
|
593
|
+
description: line.replace(/^[-*•]\s*/, ""),
|
|
594
|
+
enforceable: true,
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
else if (/^(allow|permit|enable)/i.test(lower)) {
|
|
598
|
+
invCount++;
|
|
599
|
+
invariants.push({
|
|
600
|
+
id: `INV-${String(invCount).padStart(3, "0")}`,
|
|
601
|
+
description: line.replace(/^[-*•]\s*/, ""),
|
|
602
|
+
enforceable: false,
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
else if (/^(warn|alert|flag|monitor|watch)/i.test(lower)) {
|
|
606
|
+
gateCount++;
|
|
607
|
+
gates.push({
|
|
608
|
+
id: `GATE-${String(gateCount).padStart(3, "0")}`,
|
|
609
|
+
label: line.replace(/^[-*•]\s*/, ""),
|
|
610
|
+
condition: lower,
|
|
611
|
+
severity: /critical|extreme|emergency/i.test(lower) ? "critical" : "warning",
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
else if (/^[-*•]\s*/.test(line)) {
|
|
615
|
+
// Bullet points are probably rules
|
|
616
|
+
invCount++;
|
|
617
|
+
invariants.push({
|
|
618
|
+
id: `INV-${String(invCount).padStart(3, "0")}`,
|
|
619
|
+
description: line.replace(/^[-*•]\s*/, ""),
|
|
620
|
+
enforceable: true,
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
if (!thesis)
|
|
625
|
+
thesis = "Governance rules from " + (docPath === "-" ? "document" : docPath);
|
|
626
|
+
const worldDef = {
|
|
627
|
+
thesis,
|
|
628
|
+
state_variables: stateVars,
|
|
629
|
+
invariants,
|
|
630
|
+
gates,
|
|
631
|
+
};
|
|
632
|
+
// Wrap in SavedWorld format so enforce can consume it directly
|
|
633
|
+
const { createSavedWorld: createWorld } = await Promise.resolve().then(() => __importStar(require("./worldStorage")));
|
|
634
|
+
const savedWorld = createWorld(worldId, worldDef, "document", {
|
|
635
|
+
description: `Generated from ${docPath === "-" ? "stdin" : docPath}`,
|
|
636
|
+
});
|
|
637
|
+
// Output
|
|
638
|
+
const outputPath = args.includes("--output") ? args[args.indexOf("--output") + 1] : null;
|
|
639
|
+
const json = JSON.stringify(savedWorld, null, 2);
|
|
640
|
+
if (outputPath) {
|
|
641
|
+
fs.writeFileSync(outputPath, json, "utf-8");
|
|
642
|
+
console.log(`\n Generated: ${outputPath}`);
|
|
643
|
+
}
|
|
644
|
+
else {
|
|
645
|
+
console.log("\n" + json);
|
|
646
|
+
}
|
|
647
|
+
console.log(`\n Summary:`);
|
|
648
|
+
console.log(` Thesis: ${thesis}`);
|
|
649
|
+
console.log(` Invariants: ${invariants.length}`);
|
|
650
|
+
console.log(` Gates: ${gates.length}`);
|
|
651
|
+
console.log(`\n This world file is saved for reuse.`);
|
|
652
|
+
console.log(` You don't need this step — enforce accepts .txt directly:`);
|
|
653
|
+
console.log(` npx nv-sim enforce trading ${docPath === "-" ? "policy.txt" : docPath}`);
|
|
654
|
+
if (outputPath) {
|
|
655
|
+
console.log(`\n But since you saved it, you can also:`);
|
|
656
|
+
console.log(` npx nv-sim enforce trading ${outputPath}`);
|
|
657
|
+
}
|
|
658
|
+
console.log("");
|
|
323
659
|
break;
|
|
324
660
|
}
|
|
325
661
|
case "preset": {
|
|
@@ -350,6 +686,864 @@ async function main() {
|
|
|
350
686
|
console.log(" Usage: npx nv-sim preset <preset_id>\n");
|
|
351
687
|
break;
|
|
352
688
|
}
|
|
689
|
+
// ============================================
|
|
690
|
+
// WORLD SAVE / LOAD / LIST
|
|
691
|
+
// ============================================
|
|
692
|
+
case "world:save": {
|
|
693
|
+
const sourcePreset = args[1];
|
|
694
|
+
const outputPath = args[2] || `${sourcePreset || "world"}.nv-world.json`;
|
|
695
|
+
const nameArg = args.find(a => a.startsWith("--name="))?.slice(7);
|
|
696
|
+
if (!sourcePreset) {
|
|
697
|
+
console.error(" Usage: npx nv-sim world:save <preset|file.json> [output.nv-world.json] [--name=My World]");
|
|
698
|
+
console.error(" Available presets: trading, strait_of_hormuz, gas_price_spike, ai_regulation_crisis");
|
|
699
|
+
process.exit(1);
|
|
700
|
+
}
|
|
701
|
+
try {
|
|
702
|
+
const { resolveWorld } = await Promise.resolve().then(() => __importStar(require("./worldComparison")));
|
|
703
|
+
const { createSavedWorld, saveWorldToFile } = await Promise.resolve().then(() => __importStar(require("./worldStorage")));
|
|
704
|
+
const resolved = resolveWorld(sourcePreset);
|
|
705
|
+
const name = nameArg || resolved.title;
|
|
706
|
+
const saved = createSavedWorld(name, resolved.world, sourcePreset, {
|
|
707
|
+
description: `Saved from CLI: ${resolved.title}`,
|
|
708
|
+
});
|
|
709
|
+
await saveWorldToFile(saved, outputPath);
|
|
710
|
+
console.log(`\n World saved: ${outputPath}`);
|
|
711
|
+
console.log(` Name: ${saved.name}`);
|
|
712
|
+
console.log(` Thesis: ${saved.world.thesis}`);
|
|
713
|
+
console.log(` Rules: ${saved.world.invariants.length} invariants, ${(saved.world.gates ?? []).length} gates`);
|
|
714
|
+
console.log(` ID: ${saved.id}\n`);
|
|
715
|
+
}
|
|
716
|
+
catch (err) {
|
|
717
|
+
console.error(` Failed to save world: ${err instanceof Error ? err.message : err}`);
|
|
718
|
+
process.exit(1);
|
|
719
|
+
}
|
|
720
|
+
break;
|
|
721
|
+
}
|
|
722
|
+
case "world:load": {
|
|
723
|
+
const filePath = args[1];
|
|
724
|
+
if (!filePath) {
|
|
725
|
+
console.error(" Usage: npx nv-sim world:load <file.nv-world.json>");
|
|
726
|
+
process.exit(1);
|
|
727
|
+
}
|
|
728
|
+
try {
|
|
729
|
+
const { loadWorldFromFile } = await Promise.resolve().then(() => __importStar(require("./worldStorage")));
|
|
730
|
+
const world = await loadWorldFromFile(filePath);
|
|
731
|
+
console.log(`\n World loaded: ${filePath}`);
|
|
732
|
+
console.log(` Name: ${world.name}`);
|
|
733
|
+
console.log(` Thesis: ${world.world.thesis}`);
|
|
734
|
+
console.log(` Base: ${world.basePreset}`);
|
|
735
|
+
console.log(` Rules: ${world.world.invariants.length} invariants, ${(world.world.gates ?? []).length} gates`);
|
|
736
|
+
console.log(` Created: ${world.createdAt}`);
|
|
737
|
+
console.log(` ID: ${world.id}\n`);
|
|
738
|
+
console.log(" INVARIANTS:");
|
|
739
|
+
for (const inv of world.world.invariants) {
|
|
740
|
+
console.log(` [${inv.enforceable ? "ENFORCED" : "ADVISORY"}] ${inv.description}`);
|
|
741
|
+
}
|
|
742
|
+
if (world.world.gates?.length) {
|
|
743
|
+
console.log("\n GATES:");
|
|
744
|
+
for (const gate of world.world.gates) {
|
|
745
|
+
console.log(` [${gate.severity.toUpperCase()}] ${gate.label}: ${gate.condition}`);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
console.log();
|
|
749
|
+
}
|
|
750
|
+
catch (err) {
|
|
751
|
+
console.error(` Failed to load world: ${err instanceof Error ? err.message : err}`);
|
|
752
|
+
process.exit(1);
|
|
753
|
+
}
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
case "world:list": {
|
|
757
|
+
const { getAvailableWorlds, explainWorldGovernance } = await Promise.resolve().then(() => __importStar(require("./worldComparison")));
|
|
758
|
+
const worlds = getAvailableWorlds();
|
|
759
|
+
console.log(`\n NV-SIM — Available Worlds\n`);
|
|
760
|
+
console.log(" " + "=".repeat(60));
|
|
761
|
+
for (const w of worlds) {
|
|
762
|
+
console.log(`\n ${w.id}`);
|
|
763
|
+
console.log(` ${w.title}`);
|
|
764
|
+
console.log(` ${w.thesis.slice(0, 80)}${w.thesis.length > 80 ? "..." : ""}`);
|
|
765
|
+
console.log(` ${w.invariantCount} rules, ${w.gateCount} gates`);
|
|
766
|
+
}
|
|
767
|
+
console.log(`\n Total: ${worlds.length} worlds available\n`);
|
|
768
|
+
console.log(" Use: npx nv-sim worlds <worldA> <worldB> to compare");
|
|
769
|
+
console.log(" Use: npx nv-sim world:save <preset> to save as JSON\n");
|
|
770
|
+
break;
|
|
771
|
+
}
|
|
772
|
+
case "world:compare": {
|
|
773
|
+
// Compare two saved world files
|
|
774
|
+
const fileA = args[1];
|
|
775
|
+
const fileB = args[2];
|
|
776
|
+
if (!fileA || !fileB) {
|
|
777
|
+
console.error(" Usage: npx nv-sim world:compare <worldA.json> <worldB.json>");
|
|
778
|
+
process.exit(1);
|
|
779
|
+
}
|
|
780
|
+
try {
|
|
781
|
+
const { loadWorldFromFile, saveWorldToStorage } = await Promise.resolve().then(() => __importStar(require("./worldStorage")));
|
|
782
|
+
const worldA = await loadWorldFromFile(fileA);
|
|
783
|
+
const worldB = await loadWorldFromFile(fileB);
|
|
784
|
+
// Temporarily register in storage so resolveWorld can find them
|
|
785
|
+
saveWorldToStorage(worldA);
|
|
786
|
+
saveWorldToStorage(worldB);
|
|
787
|
+
console.log(`\n NV-SIM — World File Comparison\n`);
|
|
788
|
+
console.log(` World A: ${worldA.name} (${fileA})`);
|
|
789
|
+
console.log(` World B: ${worldB.name} (${fileB})`);
|
|
790
|
+
console.log(" " + "=".repeat(60));
|
|
791
|
+
const compResult = await (0, worldComparison_1.runWorldComparison)(worldA.id, worldB.id, {
|
|
792
|
+
onProgress: (label, phase) => console.log(` ${label}: ${phase}...`),
|
|
793
|
+
});
|
|
794
|
+
const { generateComparisonImpact } = await Promise.resolve().then(() => __importStar(require("./worldComparison")));
|
|
795
|
+
const impact = generateComparisonImpact(compResult);
|
|
796
|
+
printWorldComparisonResults(compResult, impact);
|
|
797
|
+
}
|
|
798
|
+
catch (err) {
|
|
799
|
+
console.error(` Comparison failed: ${err instanceof Error ? err.message : err}`);
|
|
800
|
+
process.exit(1);
|
|
801
|
+
}
|
|
802
|
+
break;
|
|
803
|
+
}
|
|
804
|
+
// ============================================
|
|
805
|
+
// PRIME RADIANT — Full Policy Enforcement System
|
|
806
|
+
// ============================================
|
|
807
|
+
case "radiant":
|
|
808
|
+
case "prime": {
|
|
809
|
+
const presetId = (args[1] && !args[1].startsWith("--")) ? args[1] : undefined;
|
|
810
|
+
const mode = args.includes("--compare") ? "compare" : args.includes("--world") ? "world" : "simulate";
|
|
811
|
+
console.log(`\n PRIME RADIANT — Policy Enforcement System\n`);
|
|
812
|
+
console.log(` "govern() controls actions. governDynamics() controls outcomes."\n`);
|
|
813
|
+
console.log(" " + "=".repeat(60));
|
|
814
|
+
const { createPrimeRadiant, PRIME_RADIANT_PRESETS } = await Promise.resolve().then(() => __importStar(require("./primeRadiant")));
|
|
815
|
+
// Resolve preset or use default
|
|
816
|
+
const presetKey = presetId && (presetId in PRIME_RADIANT_PRESETS)
|
|
817
|
+
? presetId
|
|
818
|
+
: "university_crisis";
|
|
819
|
+
const preset = PRIME_RADIANT_PRESETS[presetKey];
|
|
820
|
+
const narrativeEvents = (0, narrativeInjection_1.parseInjectArgs)(args);
|
|
821
|
+
console.log(` Preset: ${presetKey}`);
|
|
822
|
+
const radiant = createPrimeRadiant({
|
|
823
|
+
scenario: preset.scenario,
|
|
824
|
+
policyText: preset.policyText,
|
|
825
|
+
stakeholders: preset.stakeholders,
|
|
826
|
+
narrativeEvents: narrativeEvents.length > 0 ? narrativeEvents : undefined,
|
|
827
|
+
});
|
|
828
|
+
if (mode === "world") {
|
|
829
|
+
// MODE 1: Build world
|
|
830
|
+
console.log(` Mode: WORLD BUILDER\n`);
|
|
831
|
+
const world = radiant.buildWorld();
|
|
832
|
+
console.log(` Policy Health: ${world.health.healthScore}/100`);
|
|
833
|
+
console.log(` Total Rules: ${world.coverageReport.totalRules}`);
|
|
834
|
+
console.log(` Enforced: ${world.coverageReport.enforcedRules}`);
|
|
835
|
+
console.log(` Advisory: ${world.coverageReport.advisoryRules}`);
|
|
836
|
+
console.log(` Dynamics: ${world.coverageReport.dynamicsRulesDetected}`);
|
|
837
|
+
console.log(` Thesis: ${world.world.thesis}`);
|
|
838
|
+
if (world.coverageReport.uncoveredCritical.length > 0) {
|
|
839
|
+
console.log(`\n UNCOVERED CRITICAL VARIABLES:`);
|
|
840
|
+
for (const v of world.coverageReport.uncoveredCritical) {
|
|
841
|
+
console.log(` - ${v}`);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
console.log(`\n INVARIANTS:`);
|
|
845
|
+
for (const inv of world.world.invariants) {
|
|
846
|
+
console.log(` [${inv.enforceable ? "ENFORCED" : "ADVISORY"}] ${inv.description}`);
|
|
847
|
+
}
|
|
848
|
+
if (world.world.gates && world.world.gates.length > 0) {
|
|
849
|
+
console.log(`\n GATES:`);
|
|
850
|
+
for (const gate of world.world.gates) {
|
|
851
|
+
console.log(` [${gate.severity.toUpperCase()}] ${gate.label}`);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
else if (mode === "compare") {
|
|
856
|
+
// MODE 3: Decision Intelligence
|
|
857
|
+
console.log(` Mode: DECISION INTELLIGENCE\n`);
|
|
858
|
+
const options = preset.policyOptions;
|
|
859
|
+
console.log(` Comparing ${options.length} policy options...\n`);
|
|
860
|
+
for (const opt of options) {
|
|
861
|
+
console.log(` ${opt.id.padEnd(20)} ${opt.label}`);
|
|
862
|
+
}
|
|
863
|
+
console.log();
|
|
864
|
+
const result = await radiant.compareOptions(options);
|
|
865
|
+
// Print decision brief
|
|
866
|
+
console.log(result.decisionBrief);
|
|
867
|
+
// Print dynamics details
|
|
868
|
+
console.log(`\n DYNAMICS GOVERNANCE`);
|
|
869
|
+
console.log(" " + "-".repeat(50));
|
|
870
|
+
for (const optResult of result.optionResults) {
|
|
871
|
+
const d = optResult.simulation.dynamicsGovernance;
|
|
872
|
+
console.log(` ${optResult.optionLabel}:`);
|
|
873
|
+
console.log(` Interventions: ${d.totalInterventions} (propagation: ${d.propagationLimits}, amplification: ${d.amplificationDampens}, cascade: ${d.cascadeBreakers}, trust: ${d.trustBoosts}, cooling: ${d.coolingPeriods})`);
|
|
874
|
+
console.log(` Peak outrage: ${(d.peakOutrage * 100).toFixed(0)}% | Peak polarization: ${(d.peakPolarization * 100).toFixed(0)}% | Avg trust: ${(d.averageTrust * 100).toFixed(0)}%`);
|
|
875
|
+
}
|
|
876
|
+
// Print recommendation
|
|
877
|
+
console.log(`\n RECOMMENDATION: ${result.recommendation.optionLabel}`);
|
|
878
|
+
console.log(` Confidence: ${(result.recommendation.confidence * 100).toFixed(0)}%`);
|
|
879
|
+
console.log(` ${result.recommendation.rationale}`);
|
|
880
|
+
}
|
|
881
|
+
else {
|
|
882
|
+
// MODE 2: Governed Simulation
|
|
883
|
+
console.log(` Mode: GOVERNED SIMULATION\n`);
|
|
884
|
+
console.log(` Running dual-layer governance...`);
|
|
885
|
+
console.log(` Layer A: govern() — per-action, per-agent`);
|
|
886
|
+
console.log(` Layer B: governDynamics() — per-round, system-level\n`);
|
|
887
|
+
const result = await radiant.runGovernedSimulation();
|
|
888
|
+
const g = result.governed;
|
|
889
|
+
const b = result.baseline;
|
|
890
|
+
const d = result.delta;
|
|
891
|
+
// System state timeline
|
|
892
|
+
console.log(` STATE EVOLUTION`);
|
|
893
|
+
console.log(" " + "-".repeat(60));
|
|
894
|
+
console.log(` ${"Round".padEnd(8)} ${"Trust".padEnd(10)} ${"Outrage".padEnd(10)} ${"Polar.".padEnd(10)} ${"Cascade".padEnd(10)} ${"Trajectory"}`);
|
|
895
|
+
for (const snap of g.stateTimeline) {
|
|
896
|
+
const round = g.rounds.find(r => r.round === snap.round);
|
|
897
|
+
console.log(` ${String(snap.round).padEnd(8)} ${(snap.trust * 100).toFixed(0).padStart(4)}% ${(snap.outrage * 100).toFixed(0).padStart(4)}% ${(snap.polarization * 100).toFixed(0).padStart(4)}% ${(snap.cascadeRisk * 100).toFixed(0).padStart(4)}% ${round?.dynamicsTrajectory ?? "-"}`);
|
|
898
|
+
}
|
|
899
|
+
// Action governance
|
|
900
|
+
console.log(`\n ACTION GOVERNANCE (Layer A)`);
|
|
901
|
+
console.log(" " + "-".repeat(50));
|
|
902
|
+
const ag = g.actionGovernance;
|
|
903
|
+
console.log(` Evaluations: ${ag.totalEvaluations}`);
|
|
904
|
+
console.log(` Allowed: ${ag.allowed} | Blocked: ${ag.blocked} | Modified: ${ag.modified} | Paused: ${ag.paused}`);
|
|
905
|
+
console.log(` Avg reduction: ${(ag.avgReduction * 100).toFixed(0)}% | Rules fired: ${ag.rulesFired}`);
|
|
906
|
+
// Dynamics governance
|
|
907
|
+
console.log(`\n DYNAMICS GOVERNANCE (Layer B)`);
|
|
908
|
+
console.log(" " + "-".repeat(50));
|
|
909
|
+
const dg = g.dynamicsGovernance;
|
|
910
|
+
console.log(` Total interventions: ${dg.totalInterventions}`);
|
|
911
|
+
console.log(` Propagation limits: ${dg.propagationLimits}`);
|
|
912
|
+
console.log(` Amplification damps: ${dg.amplificationDampens}`);
|
|
913
|
+
console.log(` Cascade breakers: ${dg.cascadeBreakers}`);
|
|
914
|
+
console.log(` Trust boosts: ${dg.trustBoosts}`);
|
|
915
|
+
console.log(` Cooling periods: ${dg.coolingPeriods}`);
|
|
916
|
+
console.log(` Peak outrage: ${(dg.peakOutrage * 100).toFixed(0)}%`);
|
|
917
|
+
console.log(` Peak polarization: ${(dg.peakPolarization * 100).toFixed(0)}%`);
|
|
918
|
+
console.log(` Peak cascade risk: ${(dg.peakCascadeRisk * 100).toFixed(0)}%`);
|
|
919
|
+
console.log(` Average trust: ${(dg.averageTrust * 100).toFixed(0)}%`);
|
|
920
|
+
// Delta
|
|
921
|
+
console.log(`\n GOVERNANCE IMPACT (vs ungoverned baseline)`);
|
|
922
|
+
console.log(" " + "=".repeat(50));
|
|
923
|
+
console.log(` Trust: ${d.trustDelta > 0 ? "+" : ""}${(d.trustDelta * 100).toFixed(0)} points (${(b.finalState.trust * 100).toFixed(0)}% → ${(g.finalState.trust * 100).toFixed(0)}%)`);
|
|
924
|
+
console.log(` Polarization: ${d.polarizationDelta < 0 ? "" : "+"}${(d.polarizationDelta * 100).toFixed(0)} points (${(b.finalState.polarization * 100).toFixed(0)}% → ${(g.finalState.polarization * 100).toFixed(0)}%)`);
|
|
925
|
+
console.log(` Outrage: ${d.outrageDelta < 0 ? "" : "+"}${(d.outrageDelta * 100).toFixed(0)} points (${(b.finalState.outrage * 100).toFixed(0)}% → ${(g.finalState.outrage * 100).toFixed(0)}%)`);
|
|
926
|
+
console.log(` Cascade risk: ${d.cascadeRiskDelta < 0 ? "" : "+"}${(d.cascadeRiskDelta * 100).toFixed(0)} points (${(b.finalState.cascadeRisk * 100).toFixed(0)}% → ${(g.finalState.cascadeRisk * 100).toFixed(0)}%)`);
|
|
927
|
+
console.log(` System health: ${d.healthDelta > 0 ? "+" : ""}${d.healthDelta} (${b.systemHealthScore}/100 → ${g.systemHealthScore}/100)`);
|
|
928
|
+
console.log(` Trajectory: ${d.trajectoryShift}`);
|
|
929
|
+
console.log(` Effectiveness: ${(d.governanceEffectiveness * 100).toFixed(0)}%`);
|
|
930
|
+
// Inflection points
|
|
931
|
+
if (g.inflectionPoints.length > 0) {
|
|
932
|
+
console.log(`\n INFLECTION POINTS`);
|
|
933
|
+
console.log(" " + "-".repeat(50));
|
|
934
|
+
for (const ip of g.inflectionPoints) {
|
|
935
|
+
console.log(` ${ip}`);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
// Narrative
|
|
939
|
+
console.log(`\n NARRATIVE`);
|
|
940
|
+
console.log(" " + "-".repeat(50));
|
|
941
|
+
const words = result.narrative.split(" ");
|
|
942
|
+
let line = " ";
|
|
943
|
+
for (const word of words) {
|
|
944
|
+
if (line.length + word.length > 72) {
|
|
945
|
+
console.log(line);
|
|
946
|
+
line = " " + word;
|
|
947
|
+
}
|
|
948
|
+
else {
|
|
949
|
+
line += (line.trim() ? " " : "") + word;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
if (line.trim())
|
|
953
|
+
console.log(line);
|
|
954
|
+
}
|
|
955
|
+
console.log(`\n ${"=".repeat(60)}`);
|
|
956
|
+
console.log(` govern() controls actions.`);
|
|
957
|
+
console.log(` governDynamics() controls outcomes.`);
|
|
958
|
+
console.log(` ${"=".repeat(60)}`);
|
|
959
|
+
console.log(`\n Design rules. Run reality. See what changes.`);
|
|
960
|
+
console.log(` neuroverse-simulations | @neuroverseos\n`);
|
|
961
|
+
break;
|
|
962
|
+
}
|
|
963
|
+
// ============================================
|
|
964
|
+
// MIROFISH — Governed Agent Simulation
|
|
965
|
+
// ============================================
|
|
966
|
+
case "mirofish": {
|
|
967
|
+
console.log(`\n MIROFISH SIMULATION — Governed by NeuroVerse\n`);
|
|
968
|
+
console.log(` MiroFish + NeuroVerse Governance Layer`);
|
|
969
|
+
console.log(` MiroFish generates emergent agent behavior.`);
|
|
970
|
+
console.log(` NeuroVerse enforces rules, constraints, and system stability in real time.\n`);
|
|
971
|
+
console.log(" " + "=".repeat(60));
|
|
972
|
+
const { runMiroFishComparison } = await Promise.resolve().then(() => __importStar(require("../adapters/mirofish")));
|
|
973
|
+
const mfMode = args.includes("--compare") ? "compare" : "governed";
|
|
974
|
+
if (mfMode === "compare") {
|
|
975
|
+
console.log(` Mode: GOVERNED vs UNGOVERNED COMPARISON\n`);
|
|
976
|
+
console.log(` Running simulation...`);
|
|
977
|
+
const comparison = runMiroFishComparison();
|
|
978
|
+
const gov = comparison.governed;
|
|
979
|
+
const ungov = comparison.ungoverned;
|
|
980
|
+
const gs = gov.metrics.systemState;
|
|
981
|
+
const us = ungov.metrics.systemState;
|
|
982
|
+
console.log(`\n Scenario: ${comparison.scenario}`);
|
|
983
|
+
console.log(" " + "=".repeat(60));
|
|
984
|
+
// Metric comparison
|
|
985
|
+
console.log(`\n ${"Metric".padEnd(30)} ${"Governed".padEnd(15)} ${"Ungoverned".padEnd(15)} ${"Delta"}`);
|
|
986
|
+
console.log(" " + "-".repeat(75));
|
|
987
|
+
const mfMetrics = [
|
|
988
|
+
["Trust", gs.trust, us.trust],
|
|
989
|
+
["Polarization", gs.polarization, us.polarization],
|
|
990
|
+
["Outrage", gs.outrage, us.outrage],
|
|
991
|
+
["Cascade Risk", gs.cascadeRisk, us.cascadeRisk],
|
|
992
|
+
["Amplification", gs.amplification, us.amplification],
|
|
993
|
+
];
|
|
994
|
+
for (const [label, gv, uv] of mfMetrics) {
|
|
995
|
+
const delta = gv - uv;
|
|
996
|
+
const deltaStr = `${delta > 0 ? "+" : ""}${(delta * 100).toFixed(0)}`;
|
|
997
|
+
console.log(` ${label.padEnd(30)} ${(gv * 100).toFixed(0).padStart(5)}% ${(uv * 100).toFixed(0).padStart(5)}% ${deltaStr.padStart(5)}`);
|
|
998
|
+
}
|
|
999
|
+
console.log(`\n ${"".padEnd(30)} ${"Governed".padEnd(15)} ${"Ungoverned"}`);
|
|
1000
|
+
console.log(" " + "-".repeat(60));
|
|
1001
|
+
console.log(` ${"Verdict".padEnd(30)} ${gov.verdict.padEnd(15)} ${ungov.verdict}`);
|
|
1002
|
+
console.log(` ${"Actions Blocked".padEnd(30)} ${String(gov.totalBlocked).padEnd(15)} ${0}`);
|
|
1003
|
+
console.log(` ${"Actions Modified".padEnd(30)} ${String(gov.totalModified).padEnd(15)} ${0}`);
|
|
1004
|
+
console.log(` ${"Trajectory".padEnd(30)} ${gov.metrics.trajectory.padEnd(15)} ${ungov.metrics.trajectory}`);
|
|
1005
|
+
// State timeline
|
|
1006
|
+
console.log(`\n STATE EVOLUTION (Trust)`);
|
|
1007
|
+
console.log(" " + "-".repeat(60));
|
|
1008
|
+
console.log(` ${"Round".padEnd(8)} ${"Governed".padEnd(15)} ${"Ungoverned".padEnd(15)} ${"Gap"}`);
|
|
1009
|
+
for (let i = 0; i < gov.timeline.length; i++) {
|
|
1010
|
+
const gt = gov.timeline[i].systemState.trust;
|
|
1011
|
+
const ut = ungov.timeline[i].systemState.trust;
|
|
1012
|
+
const gap = gt - ut;
|
|
1013
|
+
console.log(` ${String(i + 1).padEnd(8)} ${(gt * 100).toFixed(0).padStart(5)}% ${(ut * 100).toFixed(0).padStart(5)}% ${(gap > 0 ? "+" : "") + (gap * 100).toFixed(0).padStart(4)}`);
|
|
1014
|
+
}
|
|
1015
|
+
// Science state comparison
|
|
1016
|
+
const govSci = gov.metrics.scienceState;
|
|
1017
|
+
const ungovSci = ungov.metrics.scienceState;
|
|
1018
|
+
console.log(`\n SYSTEM ASSESSMENT`);
|
|
1019
|
+
console.log(" " + "-".repeat(60));
|
|
1020
|
+
console.log(` Governed: ${govSci.overallAssessment}`);
|
|
1021
|
+
console.log(` Ungoverned: ${ungovSci.overallAssessment}`);
|
|
1022
|
+
console.log(`\n This simulation was generated by MiroFish.`);
|
|
1023
|
+
console.log(` NeuroVerse governance altered the system trajectory in real time.`);
|
|
1024
|
+
}
|
|
1025
|
+
else {
|
|
1026
|
+
// Single governed run
|
|
1027
|
+
console.log(` Mode: GOVERNED SIMULATION\n`);
|
|
1028
|
+
const { createMiroFishWrapper, generateDemoSimulation } = await Promise.resolve().then(() => __importStar(require("../adapters/mirofish")));
|
|
1029
|
+
const demo = generateDemoSimulation();
|
|
1030
|
+
const wrapper = createMiroFishWrapper({ enabled: true });
|
|
1031
|
+
console.log(` Scenario: ${demo.scenario}\n`);
|
|
1032
|
+
for (let i = 0; i < demo.rounds.length; i++) {
|
|
1033
|
+
const round = demo.rounds[i];
|
|
1034
|
+
let blocked = 0;
|
|
1035
|
+
let modified = 0;
|
|
1036
|
+
const approved = [];
|
|
1037
|
+
for (const action of round) {
|
|
1038
|
+
const result = wrapper.interceptAction(action);
|
|
1039
|
+
if (result.wasBlocked)
|
|
1040
|
+
blocked++;
|
|
1041
|
+
else if (result.wasModified)
|
|
1042
|
+
modified++;
|
|
1043
|
+
if (!result.wasBlocked)
|
|
1044
|
+
approved.push(result.governed ?? action);
|
|
1045
|
+
}
|
|
1046
|
+
const cycleResult = wrapper.completeCycle({ cycle: i + 1, actions: approved });
|
|
1047
|
+
const m = wrapper.getMetrics();
|
|
1048
|
+
const flags = blocked > 0 ? ` [${blocked} blocked]` : "";
|
|
1049
|
+
console.log(` Round ${String(i + 1).padEnd(3)} | trust: ${(m.systemState.trust * 100).toFixed(0).padStart(3)}% | cascade: ${(m.systemState.cascadeRisk * 100).toFixed(0).padStart(3)}% | ${cycleResult.trajectory}${flags}`);
|
|
1050
|
+
}
|
|
1051
|
+
const final = wrapper.getMetrics();
|
|
1052
|
+
console.log(`\n FINAL STATE`);
|
|
1053
|
+
console.log(" " + "=".repeat(50));
|
|
1054
|
+
console.log(` Trust: ${(final.systemState.trust * 100).toFixed(0)}%`);
|
|
1055
|
+
console.log(` Cascade Risk: ${(final.systemState.cascadeRisk * 100).toFixed(0)}%`);
|
|
1056
|
+
console.log(` Blocked: ${final.actionStats.blocked}`);
|
|
1057
|
+
console.log(` Modified: ${final.actionStats.modified}`);
|
|
1058
|
+
console.log(` Assessment: ${final.scienceState.overallAssessment}`);
|
|
1059
|
+
}
|
|
1060
|
+
console.log(`\n ${"=".repeat(60)}`);
|
|
1061
|
+
console.log(` Governed MiroFish Simulation | NeuroVerse Governance Layer`);
|
|
1062
|
+
console.log(` ${"=".repeat(60)}`);
|
|
1063
|
+
console.log(`\n neuroverse-simulations | @neuroverseos\n`);
|
|
1064
|
+
break;
|
|
1065
|
+
}
|
|
1066
|
+
// ============================================
|
|
1067
|
+
// SCIENCE — Governed Scientific Discovery
|
|
1068
|
+
// ============================================
|
|
1069
|
+
case "science": {
|
|
1070
|
+
console.log(`\n SCIENCECLAW SIMULATION — Governed by NeuroVerse\n`);
|
|
1071
|
+
console.log(` Powered by ScienceClaw | Governed by NeuroVerse`);
|
|
1072
|
+
console.log(` ScienceClaw generates autonomous scientific discovery.`);
|
|
1073
|
+
console.log(` NeuroVerse enforces reproducibility, provenance, and research integrity.\n`);
|
|
1074
|
+
console.log(" " + "=".repeat(60));
|
|
1075
|
+
const { createScienceClawAdapter, generateDemoInvestigation } = await Promise.resolve().then(() => __importStar(require("../adapters/scienceclaw")));
|
|
1076
|
+
const { SCIENCE_METRICS, interpretScienceState } = await Promise.resolve().then(() => __importStar(require("./metrics/science.metrics")));
|
|
1077
|
+
const demo = generateDemoInvestigation();
|
|
1078
|
+
const mode = args.includes("--compare") ? "compare" : "simulate";
|
|
1079
|
+
if (mode === "compare") {
|
|
1080
|
+
// Governed vs ungoverned comparison
|
|
1081
|
+
console.log(` Mode: GOVERNED vs UNGOVERNED COMPARISON\n`);
|
|
1082
|
+
// Run governed
|
|
1083
|
+
console.log(` Running GOVERNED investigation...`);
|
|
1084
|
+
const governed = createScienceClawAdapter();
|
|
1085
|
+
const govResult = governed.runGovernedInvestigation(demo.artifactCycles, demo.matchesByCycle);
|
|
1086
|
+
// Run ungoverned (empty policy)
|
|
1087
|
+
console.log(` Running UNGOVERNED investigation...`);
|
|
1088
|
+
const ungoverned = createScienceClawAdapter({ policyText: "" });
|
|
1089
|
+
const ungovResult = ungoverned.runGovernedInvestigation(demo.artifactCycles, demo.matchesByCycle);
|
|
1090
|
+
// Print comparison
|
|
1091
|
+
console.log(`\n COMPARISON: Governed vs Ungoverned Discovery`);
|
|
1092
|
+
console.log(" " + "=".repeat(60));
|
|
1093
|
+
console.log(` ${"Metric".padEnd(30)} ${"Governed".padEnd(15)} ${"Ungoverned".padEnd(15)} ${"Delta"}`);
|
|
1094
|
+
console.log(" " + "-".repeat(75));
|
|
1095
|
+
const metrics = [
|
|
1096
|
+
["Trust (Reproducibility)", govResult.finalState.trust, ungovResult.finalState.trust],
|
|
1097
|
+
["Polarization (Fragmentation)", govResult.finalState.polarization, ungovResult.finalState.polarization],
|
|
1098
|
+
["Outrage (Publication Pressure)", govResult.finalState.outrage, ungovResult.finalState.outrage],
|
|
1099
|
+
["Cascade Risk (False Positives)", govResult.finalState.cascadeRisk, ungovResult.finalState.cascadeRisk],
|
|
1100
|
+
["Amplification (Citation Echo)", govResult.finalState.amplification, ungovResult.finalState.amplification],
|
|
1101
|
+
];
|
|
1102
|
+
for (const [label, gov, ungov] of metrics) {
|
|
1103
|
+
const delta = gov - ungov;
|
|
1104
|
+
const deltaStr = `${delta > 0 ? "+" : ""}${(delta * 100).toFixed(0)}`;
|
|
1105
|
+
console.log(` ${label.padEnd(30)} ${(gov * 100).toFixed(0).padStart(5)}% ${(ungov * 100).toFixed(0).padStart(5)}% ${deltaStr.padStart(5)}`);
|
|
1106
|
+
}
|
|
1107
|
+
console.log(`\n ${"".padEnd(30)} ${"Governed".padEnd(15)} ${"Ungoverned"}`);
|
|
1108
|
+
console.log(" " + "-".repeat(60));
|
|
1109
|
+
console.log(` ${"Verdict".padEnd(30)} ${govResult.verdict.padEnd(15)} ${ungovResult.verdict}`);
|
|
1110
|
+
console.log(` ${"Cycles".padEnd(30)} ${String(govResult.totalCycles).padEnd(15)} ${ungovResult.totalCycles}`);
|
|
1111
|
+
console.log(` ${"Artifacts Blocked".padEnd(30)} ${String(govResult.actionGovernance.blocked).padEnd(15)} ${ungovResult.actionGovernance.blocked}`);
|
|
1112
|
+
console.log(` ${"Interventions".padEnd(30)} ${String(govResult.dynamicsGovernance.totalInterventions).padEnd(15)} ${ungovResult.dynamicsGovernance.totalInterventions}`);
|
|
1113
|
+
// Science state interpretation — side by side
|
|
1114
|
+
const sciState = govResult.finalScienceState;
|
|
1115
|
+
const ungovSciState = ungovResult.finalScienceState;
|
|
1116
|
+
console.log(`\n SCIENCE STATE`);
|
|
1117
|
+
console.log(" " + "-".repeat(70));
|
|
1118
|
+
console.log(` ${"".padEnd(30)} ${"Governed".padEnd(20)} ${"Ungoverned"}`);
|
|
1119
|
+
console.log(" " + "-".repeat(70));
|
|
1120
|
+
console.log(` ${"Hypothesis Fragmentation".padEnd(30)} ${sciState.hypothesisFragmentation.padEnd(20)} ${ungovSciState.hypothesisFragmentation}`);
|
|
1121
|
+
console.log(` ${"Publication Pressure".padEnd(30)} ${sciState.publicationPressure.padEnd(20)} ${ungovSciState.publicationPressure}`);
|
|
1122
|
+
console.log(` ${"Reproducibility".padEnd(30)} ${sciState.reproducibilityConfidence.padEnd(20)} ${ungovSciState.reproducibilityConfidence}`);
|
|
1123
|
+
console.log(` ${"Citation Health".padEnd(30)} ${sciState.citationHealth.padEnd(20)} ${ungovSciState.citationHealth}`);
|
|
1124
|
+
console.log(` ${"False Positive Risk".padEnd(30)} ${sciState.falsePositiveRisk.padEnd(20)} ${ungovSciState.falsePositiveRisk}`);
|
|
1125
|
+
console.log(` ${"Discovery Velocity".padEnd(30)} ${sciState.discoveryVelocity.padEnd(20)} ${ungovSciState.discoveryVelocity}`);
|
|
1126
|
+
console.log(`\n Governed: ${sciState.overallAssessment}`);
|
|
1127
|
+
console.log(` Ungoverned: ${ungovSciState.overallAssessment}`);
|
|
1128
|
+
console.log(`\n This simulation was generated by ScienceClaw.`);
|
|
1129
|
+
console.log(` NeuroVerse governance altered the research trajectory in real time.`);
|
|
1130
|
+
}
|
|
1131
|
+
else {
|
|
1132
|
+
// Single governed investigation
|
|
1133
|
+
console.log(` Mode: GOVERNED INVESTIGATION\n`);
|
|
1134
|
+
console.log(` Running governed investigation (${demo.artifactCycles.length} artifact cycles)...\n`);
|
|
1135
|
+
const adapter = createScienceClawAdapter({
|
|
1136
|
+
onCycleComplete: (result) => {
|
|
1137
|
+
const state = result.scienceState;
|
|
1138
|
+
const flags = result.riskFlags.length > 0 ? ` [${result.riskFlags.length} flags]` : "";
|
|
1139
|
+
console.log(` Cycle ${String(result.cycle).padEnd(3)} | approved: ${result.artifactsApproved} blocked: ${result.artifactsBlocked} | ${result.dynamics.trajectory}${flags}`);
|
|
1140
|
+
},
|
|
1141
|
+
onConvergence: (cycle, assessment) => {
|
|
1142
|
+
console.log(`\n >>> CONVERGENCE at cycle ${cycle}: ${assessment}`);
|
|
1143
|
+
},
|
|
1144
|
+
onHalt: (reason, cycle) => {
|
|
1145
|
+
console.log(`\n >>> HALTED at cycle ${cycle}: ${reason}`);
|
|
1146
|
+
},
|
|
1147
|
+
});
|
|
1148
|
+
const result = adapter.runGovernedInvestigation(demo.artifactCycles, demo.matchesByCycle);
|
|
1149
|
+
// State timeline
|
|
1150
|
+
console.log(`\n STATE EVOLUTION`);
|
|
1151
|
+
console.log(" " + "-".repeat(70));
|
|
1152
|
+
console.log(` ${"Cycle".padEnd(8)} ${"Trust".padEnd(10)} ${"Fragment".padEnd(10)} ${"Pressure".padEnd(10)} ${"Cascade".padEnd(10)} ${"Trajectory"}`);
|
|
1153
|
+
for (const snap of result.stateTimeline) {
|
|
1154
|
+
const round = result.cycles.find(c => c.cycle === snap.round);
|
|
1155
|
+
console.log(` ${String(snap.round).padEnd(8)} ${(snap.trust * 100).toFixed(0).padStart(4)}% ${(snap.polarization * 100).toFixed(0).padStart(4)}% ${(snap.outrage * 100).toFixed(0).padStart(4)}% ${(snap.cascadeRisk * 100).toFixed(0).padStart(4)}% ${round?.dynamics.trajectory ?? "-"}`);
|
|
1156
|
+
}
|
|
1157
|
+
// Summary
|
|
1158
|
+
console.log(`\n INVESTIGATION SUMMARY`);
|
|
1159
|
+
console.log(" " + "=".repeat(50));
|
|
1160
|
+
console.log(` Verdict: ${result.verdict.toUpperCase()}`);
|
|
1161
|
+
console.log(` Cycles: ${result.totalCycles}`);
|
|
1162
|
+
console.log(` Artifacts: ${result.actionGovernance.totalEvaluations} evaluated`);
|
|
1163
|
+
console.log(` Approved: ${result.actionGovernance.approved}`);
|
|
1164
|
+
console.log(` Blocked: ${result.actionGovernance.blocked}`);
|
|
1165
|
+
console.log(` Modified: ${result.actionGovernance.modified}`);
|
|
1166
|
+
console.log(` Interventions: ${result.dynamicsGovernance.totalInterventions}`);
|
|
1167
|
+
console.log(` Propagation: ${result.dynamicsGovernance.propagationLimits}`);
|
|
1168
|
+
console.log(` Amplification: ${result.dynamicsGovernance.amplificationDampens}`);
|
|
1169
|
+
console.log(` Cascade Break: ${result.dynamicsGovernance.cascadeBreakers}`);
|
|
1170
|
+
console.log(` Trust Boost: ${result.dynamicsGovernance.trustBoosts}`);
|
|
1171
|
+
console.log(` Cooling: ${result.dynamicsGovernance.coolingPeriods}`);
|
|
1172
|
+
// Final science state
|
|
1173
|
+
console.log(`\n FINAL SCIENCE STATE`);
|
|
1174
|
+
console.log(" " + "-".repeat(50));
|
|
1175
|
+
const sciState = result.finalScienceState;
|
|
1176
|
+
console.log(` ${sciState.overallAssessment}`);
|
|
1177
|
+
console.log(` Reproducibility: ${sciState.reproducibilityConfidence}`);
|
|
1178
|
+
console.log(` Citation Health: ${sciState.citationHealth}`);
|
|
1179
|
+
console.log(` False Positives: ${sciState.falsePositiveRisk}`);
|
|
1180
|
+
}
|
|
1181
|
+
console.log(`\n ${"=".repeat(60)}`);
|
|
1182
|
+
console.log(` Powered by ScienceClaw. Governed by NeuroVerse.`);
|
|
1183
|
+
console.log(` ${"=".repeat(60)}`);
|
|
1184
|
+
console.log(`\n neuroverse-simulations | @neuroverseos\n`);
|
|
1185
|
+
break;
|
|
1186
|
+
}
|
|
1187
|
+
case "enforce": {
|
|
1188
|
+
// ==============================================
|
|
1189
|
+
// POLICY ENFORCEMENT — Iterative Governance Lab
|
|
1190
|
+
//
|
|
1191
|
+
// "Design rules. Run reality. See what changes."
|
|
1192
|
+
//
|
|
1193
|
+
// Same scenario, different rules, measurable divergence.
|
|
1194
|
+
// ==============================================
|
|
1195
|
+
const { createEnforcementSession, formatEnforcementReport, exportEnforcementReportJSON, formatGuidedNextSteps, formatPolicyDiagnostics, formatRuleImpactAttribution, detectSystemArchetype, createSavedExperiment, formatMultiPatchComparison, loadExperimentLibrary, formatExperimentLineage, formatSimilarExperiments, formatBestKnownStrategy, governedDetectArchetype, governedSynthesizeStrategy, governedFindSimilar } = await Promise.resolve().then(() => __importStar(require("./policyEnforcement")));
|
|
1196
|
+
const { createSavedWorld, forkWorld, loadWorldFromFile } = await Promise.resolve().then(() => __importStar(require("./worldStorage")));
|
|
1197
|
+
const { parseRulesFromText, validatePolicy, policyToWorld, applyQuickFix } = await Promise.resolve().then(() => __importStar(require("./policyEngine")));
|
|
1198
|
+
const presetArg = (args[1] && !args[1].startsWith("--")) ? args[1] : "trading";
|
|
1199
|
+
const outputJson = args.includes("--json");
|
|
1200
|
+
const outputFile = args.find(a => a.startsWith("--output="))?.split("=")[1];
|
|
1201
|
+
// Support multiple --patch flags: --patch POL-001 --patch POL-002
|
|
1202
|
+
const patchDiagIds = [];
|
|
1203
|
+
for (let i = 0; i < args.length; i++) {
|
|
1204
|
+
if (args[i] === "--patch" && args[i + 1] && !args[i + 1].startsWith("--")) {
|
|
1205
|
+
patchDiagIds.push(args[i + 1]);
|
|
1206
|
+
}
|
|
1207
|
+
else if (args[i].startsWith("--patch=")) {
|
|
1208
|
+
patchDiagIds.push(args[i].split("=")[1]);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
const patchDiagId = patchDiagIds[0];
|
|
1212
|
+
const compareMode = args.includes("--compare");
|
|
1213
|
+
const saveExperiment = args.includes("--save");
|
|
1214
|
+
const saveLabel = args.find(a => a.startsWith("--save="))?.split("=")[1];
|
|
1215
|
+
// Accept .json world files AND .txt/.md policy documents
|
|
1216
|
+
const inputFiles = args.filter(a => (a.endsWith(".json") || a.endsWith(".txt") || a.endsWith(".md")) && a !== outputFile);
|
|
1217
|
+
const worldFiles = inputFiles.filter(a => a.endsWith(".json"));
|
|
1218
|
+
const policyDocFiles = inputFiles.filter(a => a.endsWith(".txt") || a.endsWith(".md"));
|
|
1219
|
+
console.log(`\n POLICY ENFORCEMENT SYSTEM`);
|
|
1220
|
+
console.log(` ${"=".repeat(60)}`);
|
|
1221
|
+
console.log(` Design rules. Run reality. See what changes.\n`);
|
|
1222
|
+
console.log(` NeuroVerse is a control layer. You define the rules.`);
|
|
1223
|
+
console.log(` The simulation shows what happens when those rules are enforced.\n`);
|
|
1224
|
+
// Resolve the base scenario
|
|
1225
|
+
let baseRequest;
|
|
1226
|
+
let basePaths;
|
|
1227
|
+
let baseWorldDef;
|
|
1228
|
+
let scenarioTitle;
|
|
1229
|
+
if (presetArg === "trading" || presetArg === "flash_crash") {
|
|
1230
|
+
baseRequest = governedSimulation_1.TRADING_DEMO.scenario;
|
|
1231
|
+
basePaths = [...governedSimulation_1.TRADING_DEMO.paths];
|
|
1232
|
+
baseWorldDef = governedSimulation_1.TRADING_DEMO.world;
|
|
1233
|
+
scenarioTitle = "Flash Crash — Algorithmic Cascade";
|
|
1234
|
+
}
|
|
1235
|
+
else {
|
|
1236
|
+
const template = scenarioCapsule_1.SCENARIO_TEMPLATES[presetArg];
|
|
1237
|
+
if (!template || !template.world?.inline_definition) {
|
|
1238
|
+
console.error(` Unknown preset: ${presetArg}`);
|
|
1239
|
+
console.error(` Available: trading, ${Object.keys(scenarioCapsule_1.SCENARIO_TEMPLATES).join(", ")}`);
|
|
1240
|
+
process.exit(1);
|
|
1241
|
+
}
|
|
1242
|
+
baseRequest = {
|
|
1243
|
+
scenario: template.scenario,
|
|
1244
|
+
stakeholders: template.stakeholders,
|
|
1245
|
+
assumptions: template.assumptions,
|
|
1246
|
+
constraints: template.constraints,
|
|
1247
|
+
depth: "full",
|
|
1248
|
+
swarm: { enabled: true, rounds: 5, reaction_model: "mixed" },
|
|
1249
|
+
};
|
|
1250
|
+
basePaths = [
|
|
1251
|
+
{
|
|
1252
|
+
id: "path_primary",
|
|
1253
|
+
label: "Primary Response",
|
|
1254
|
+
description: "The most likely course of action given the scenario",
|
|
1255
|
+
projected_outcome: "Moderate disruption with cascading effects",
|
|
1256
|
+
probability: 0.6,
|
|
1257
|
+
risk: "high",
|
|
1258
|
+
tradeoffs: ["Speed vs. thoroughness", "Short-term vs. long-term"],
|
|
1259
|
+
benefits_stakeholders: template.stakeholders.filter((s) => s.disposition === "supportive").map((s) => s.id),
|
|
1260
|
+
harms_stakeholders: template.stakeholders.filter((s) => s.disposition === "hostile").map((s) => s.id),
|
|
1261
|
+
},
|
|
1262
|
+
{
|
|
1263
|
+
id: "path_defensive",
|
|
1264
|
+
label: "Defensive Posture",
|
|
1265
|
+
description: "Conservative approach prioritizing stability over opportunity",
|
|
1266
|
+
projected_outcome: "Reduced damage but slower recovery",
|
|
1267
|
+
probability: 0.7,
|
|
1268
|
+
risk: "moderate",
|
|
1269
|
+
tradeoffs: ["Safety vs. opportunity cost", "Coordination cost vs. independence"],
|
|
1270
|
+
benefits_stakeholders: template.stakeholders.filter((s) => s.disposition !== "hostile").map((s) => s.id),
|
|
1271
|
+
harms_stakeholders: [],
|
|
1272
|
+
},
|
|
1273
|
+
];
|
|
1274
|
+
baseWorldDef = template.world.inline_definition;
|
|
1275
|
+
scenarioTitle = template.title;
|
|
1276
|
+
}
|
|
1277
|
+
console.log(` Scenario: ${scenarioTitle}`);
|
|
1278
|
+
// Create session
|
|
1279
|
+
const session = createEnforcementSession(scenarioTitle, baseRequest, basePaths);
|
|
1280
|
+
// Convert policy documents (.txt/.md) to world files
|
|
1281
|
+
const convertedWorlds = [];
|
|
1282
|
+
if (policyDocFiles.length > 0) {
|
|
1283
|
+
console.log(` Converting ${policyDocFiles.length} policy document(s) to world files...\n`);
|
|
1284
|
+
for (const docFile of policyDocFiles) {
|
|
1285
|
+
try {
|
|
1286
|
+
let docText = fs.readFileSync(docFile, "utf-8");
|
|
1287
|
+
// --patch: auto-apply a quick fix before converting
|
|
1288
|
+
if (patchDiagId) {
|
|
1289
|
+
const preParsed = parseRulesFromText(docText);
|
|
1290
|
+
const preHealth = validatePolicy(preParsed);
|
|
1291
|
+
const targetDiag = preHealth.diagnostics.find(d => d.id === patchDiagId);
|
|
1292
|
+
if (targetDiag?.quickFix) {
|
|
1293
|
+
console.log(` Applying fix ${patchDiagId}: ${targetDiag.quickFix.label}`);
|
|
1294
|
+
docText = applyQuickFix(docText, targetDiag.quickFix);
|
|
1295
|
+
console.log(` Patched. Running with fixed rules.\n`);
|
|
1296
|
+
}
|
|
1297
|
+
else if (targetDiag) {
|
|
1298
|
+
console.log(` ${patchDiagId} found but has no quick fix available.\n`);
|
|
1299
|
+
}
|
|
1300
|
+
else {
|
|
1301
|
+
console.log(` ${patchDiagId} not found in diagnostics for ${docFile}.\n`);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
const parsed = parseRulesFromText(docText);
|
|
1305
|
+
const health = validatePolicy(parsed);
|
|
1306
|
+
const worldDef = policyToWorld(parsed);
|
|
1307
|
+
const docName = docFile.replace(/^.*[\\/]/, "").replace(/\.\w+$/, "");
|
|
1308
|
+
const world = createSavedWorld(docName, worldDef, presetArg, { description: `Generated from ${docFile}` });
|
|
1309
|
+
console.log(` ${docFile} → "${docName}"`);
|
|
1310
|
+
console.log(` World: ${worldDef.invariants.length} invariants, ${worldDef.gates.length} gates`);
|
|
1311
|
+
// GitHub-style policy review — show diagnostics with quick fixes
|
|
1312
|
+
console.log(formatPolicyDiagnostics(health, parsed, docFile));
|
|
1313
|
+
// If errors would block simulation, warn but continue
|
|
1314
|
+
if (!health.canSimulate) {
|
|
1315
|
+
console.error(` ✗ ${docFile} has blocking errors — skipping.`);
|
|
1316
|
+
console.error(` Fix the issues above and run again.\n`);
|
|
1317
|
+
continue;
|
|
1318
|
+
}
|
|
1319
|
+
convertedWorlds.push(world);
|
|
1320
|
+
}
|
|
1321
|
+
catch (e) {
|
|
1322
|
+
console.error(` Failed to convert ${docFile}: ${e.message}`);
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
// Build ordered list of worlds to test: JSON files first, then converted docs
|
|
1327
|
+
const worldsToRun = [];
|
|
1328
|
+
for (const jsonFile of worldFiles) {
|
|
1329
|
+
try {
|
|
1330
|
+
const w = await loadWorldFromFile(jsonFile);
|
|
1331
|
+
worldsToRun.push({ label: jsonFile, world: w });
|
|
1332
|
+
}
|
|
1333
|
+
catch (e) {
|
|
1334
|
+
console.error(` Failed to load ${jsonFile}: ${e.message}`);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
for (const cw of convertedWorlds) {
|
|
1338
|
+
worldsToRun.push({ label: cw.name, world: cw });
|
|
1339
|
+
}
|
|
1340
|
+
// If user provided files (JSON or docs), run them. Otherwise, run progressive rule sets.
|
|
1341
|
+
if (worldsToRun.length > 0) {
|
|
1342
|
+
console.log(` Running ${worldsToRun.length} world(s)...\n`);
|
|
1343
|
+
for (let i = 0; i < worldsToRun.length; i++) {
|
|
1344
|
+
try {
|
|
1345
|
+
const world = worldsToRun[i].world;
|
|
1346
|
+
console.log(` Run ${i + 1}: "${world.name}" (${world.world.invariants.length} rules, ${(world.world.gates ?? []).length} gates)`);
|
|
1347
|
+
const run = await session.run(world);
|
|
1348
|
+
console.log(` → Stability: ${(run.result.governed.metrics.stabilityScore * 100).toFixed(0)}% Collapse: ${(run.result.governed.metrics.collapseProbability * 100).toFixed(0)}% Effectiveness: ${(run.result.comparison.governanceEffectiveness * 100).toFixed(0)}%`);
|
|
1349
|
+
}
|
|
1350
|
+
catch (e) {
|
|
1351
|
+
console.error(` Failed to run "${worldsToRun[i].label}": ${e.message}`);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
else {
|
|
1356
|
+
// Progressive enforcement: no rules → light rules → full rules
|
|
1357
|
+
console.log(` Running progressive enforcement (3 iterations)...\n`);
|
|
1358
|
+
// Run 1: No rules (baseline world)
|
|
1359
|
+
const noRulesWorld = createSavedWorld("No Rules", { thesis: baseWorldDef.thesis, state_variables: baseWorldDef.state_variables ?? [], invariants: [], gates: [] }, presetArg, { description: "Baseline — no governance rules applied" });
|
|
1360
|
+
console.log(` Run 1: "No Rules" (0 invariants, 0 gates)`);
|
|
1361
|
+
const run1 = await session.run(noRulesWorld);
|
|
1362
|
+
console.log(` → Stability: ${(run1.result.governed.metrics.stabilityScore * 100).toFixed(0)}% Collapse: ${(run1.result.governed.metrics.collapseProbability * 100).toFixed(0)}% Effectiveness: ${(run1.result.comparison.governanceEffectiveness * 100).toFixed(0)}%`);
|
|
1363
|
+
// Run 2: Light rules (pick first 2 invariants)
|
|
1364
|
+
const lightInvariants = baseWorldDef.invariants.slice(0, 2);
|
|
1365
|
+
const lightWorld = createSavedWorld("Light Governance", { thesis: baseWorldDef.thesis, state_variables: baseWorldDef.state_variables ?? [], invariants: lightInvariants, gates: [] }, presetArg, { description: "Partial rules — testing minimal governance" });
|
|
1366
|
+
console.log(` Run 2: "Light Governance" (${lightInvariants.length} invariants, 0 gates)`);
|
|
1367
|
+
const run2 = await session.run(lightWorld);
|
|
1368
|
+
console.log(` → Stability: ${(run2.result.governed.metrics.stabilityScore * 100).toFixed(0)}% Collapse: ${(run2.result.governed.metrics.collapseProbability * 100).toFixed(0)}% Effectiveness: ${(run2.result.comparison.governanceEffectiveness * 100).toFixed(0)}%`);
|
|
1369
|
+
// Run 3: Full rules
|
|
1370
|
+
const fullWorld = createSavedWorld("Full Governance", baseWorldDef, presetArg, { description: "All rules active — full governance enforcement" });
|
|
1371
|
+
console.log(` Run 3: "Full Governance" (${baseWorldDef.invariants.length} invariants, ${(baseWorldDef.gates ?? []).length} gates)`);
|
|
1372
|
+
const run3 = await session.run(fullWorld);
|
|
1373
|
+
console.log(` → Stability: ${(run3.result.governed.metrics.stabilityScore * 100).toFixed(0)}% Collapse: ${(run3.result.governed.metrics.collapseProbability * 100).toFixed(0)}% Effectiveness: ${(run3.result.comparison.governanceEffectiveness * 100).toFixed(0)}%`);
|
|
1374
|
+
}
|
|
1375
|
+
// Generate report
|
|
1376
|
+
const report = session.generateReport();
|
|
1377
|
+
if (outputJson || outputFile) {
|
|
1378
|
+
const json = exportEnforcementReportJSON(report);
|
|
1379
|
+
if (outputFile) {
|
|
1380
|
+
fs.writeFileSync(outputFile, json, "utf-8");
|
|
1381
|
+
console.log(`\n Report saved to: ${outputFile}`);
|
|
1382
|
+
}
|
|
1383
|
+
else {
|
|
1384
|
+
console.log(json);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
else {
|
|
1388
|
+
console.log(formatEnforcementReport(report));
|
|
1389
|
+
// Behavioral analysis — what agents did differently under governance
|
|
1390
|
+
for (const run of session.runs) {
|
|
1391
|
+
console.log(`\n ── Behavioral Analysis: Run ${run.iteration} (${run.world.name}) ──`);
|
|
1392
|
+
console.log((0, behavioralAnalysis_1.formatBehavioralAnalysis)(run.result.behavioralAnalysis));
|
|
1393
|
+
}
|
|
1394
|
+
// Rule impact attribution — show which rules shaped the outcome
|
|
1395
|
+
const attribution = formatRuleImpactAttribution(report);
|
|
1396
|
+
if (attribution) {
|
|
1397
|
+
console.log(attribution);
|
|
1398
|
+
}
|
|
1399
|
+
// System archetype insight — governed AI detects system patterns
|
|
1400
|
+
const archetypeGov = await governedDetectArchetype(report);
|
|
1401
|
+
const archetypeInsight = archetypeGov.result;
|
|
1402
|
+
if (archetypeInsight) {
|
|
1403
|
+
console.log(archetypeInsight);
|
|
1404
|
+
// Show governance trace for archetype detection
|
|
1405
|
+
console.log(` ┌─ Governed AI ────────────────────────────────┐`);
|
|
1406
|
+
console.log(` │ Actor: ${archetypeGov.actor.padEnd(40)}│`);
|
|
1407
|
+
console.log(` │ Action: ${"detect_archetype".padEnd(39)}│`);
|
|
1408
|
+
console.log(` │ Constraints: ${String(archetypeGov.trace.constraints.length).padEnd(34)}│`);
|
|
1409
|
+
console.log(` │ Passed: ${String(archetypeGov.trace.passed).padEnd(39)}│`);
|
|
1410
|
+
console.log(` └──────────────────────────────────────────────┘`);
|
|
1411
|
+
}
|
|
1412
|
+
// Load experiment library for knowledge features
|
|
1413
|
+
const experimentLibrary = loadExperimentLibrary();
|
|
1414
|
+
const bestRun = report.runs[report.divergence.bestIteration - 1];
|
|
1415
|
+
const currentMetrics = bestRun
|
|
1416
|
+
? { stability: bestRun.metrics.stabilityScore, effectiveness: bestRun.comparison.governanceEffectiveness }
|
|
1417
|
+
: { stability: 0, effectiveness: 0 };
|
|
1418
|
+
// Find similar experiments + best known strategy — ALL governed
|
|
1419
|
+
if (experimentLibrary.length > 0 && bestRun) {
|
|
1420
|
+
const runArchetype = archetypeInsight
|
|
1421
|
+
? (archetypeInsight.match(/behaves like: (.+)/)?.[1] ?? null)
|
|
1422
|
+
: null;
|
|
1423
|
+
// Governed similarity search
|
|
1424
|
+
const similarGov = await governedFindSimilar(runArchetype, currentMetrics, experimentLibrary);
|
|
1425
|
+
if (similarGov.result) {
|
|
1426
|
+
console.log(similarGov.result);
|
|
1427
|
+
console.log(` ┌─ Governed AI ────────────────────────────────┐`);
|
|
1428
|
+
console.log(` │ Actor: ${similarGov.actor.padEnd(40)}│`);
|
|
1429
|
+
console.log(` │ Action: ${"compare_experiments".padEnd(39)}│`);
|
|
1430
|
+
console.log(` │ Constraints: ${String(similarGov.trace.constraints.length).padEnd(34)}│`);
|
|
1431
|
+
console.log(` │ Passed: ${String(similarGov.trace.passed).padEnd(39)}│`);
|
|
1432
|
+
console.log(` └──────────────────────────────────────────────┘`);
|
|
1433
|
+
}
|
|
1434
|
+
// Governed strategy synthesis
|
|
1435
|
+
const strategyGov = await governedSynthesizeStrategy(runArchetype, currentMetrics, experimentLibrary);
|
|
1436
|
+
if (strategyGov.result) {
|
|
1437
|
+
console.log(strategyGov.result);
|
|
1438
|
+
console.log(` ┌─ Governed AI ────────────────────────────────┐`);
|
|
1439
|
+
console.log(` │ Actor: ${strategyGov.actor.padEnd(40)}│`);
|
|
1440
|
+
console.log(` │ Action: ${"synthesize_strategy".padEnd(39)}│`);
|
|
1441
|
+
console.log(` │ Constraints: ${String(strategyGov.trace.constraints.length).padEnd(34)}│`);
|
|
1442
|
+
console.log(` │ Passed: ${String(strategyGov.trace.passed).padEnd(39)}│`);
|
|
1443
|
+
console.log(` └──────────────────────────────────────────────┘`);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
// --compare: show side-by-side before/after when used with --patch
|
|
1447
|
+
if (compareMode && patchDiagId && report.runs.length >= 1) {
|
|
1448
|
+
const run = report.runs[report.runs.length - 1];
|
|
1449
|
+
const baseStab = report.runs.length > 1 ? report.runs[0].metrics.stabilityScore : 0.5;
|
|
1450
|
+
const baseEff = report.runs.length > 1 ? report.runs[0].comparison.governanceEffectiveness : 0;
|
|
1451
|
+
const baseCollapse = report.runs.length > 1 ? report.runs[0].metrics.collapseProbability : 0.15;
|
|
1452
|
+
// Multi-patch comparison
|
|
1453
|
+
if (patchDiagIds.length > 1) {
|
|
1454
|
+
// Build comparison data from available runs
|
|
1455
|
+
const patchResults = patchDiagIds.map((pid, idx) => {
|
|
1456
|
+
const patchRun = idx < report.runs.length ? report.runs[idx] : run;
|
|
1457
|
+
return {
|
|
1458
|
+
patchId: pid,
|
|
1459
|
+
stability: patchRun.metrics.stabilityScore,
|
|
1460
|
+
effectiveness: patchRun.comparison.governanceEffectiveness,
|
|
1461
|
+
collapse: patchRun.metrics.collapseProbability,
|
|
1462
|
+
};
|
|
1463
|
+
});
|
|
1464
|
+
console.log(formatMultiPatchComparison(patchResults, {
|
|
1465
|
+
stability: baseStab,
|
|
1466
|
+
effectiveness: baseEff,
|
|
1467
|
+
collapse: baseCollapse,
|
|
1468
|
+
}));
|
|
1469
|
+
}
|
|
1470
|
+
else {
|
|
1471
|
+
// Single patch comparison
|
|
1472
|
+
console.log(" BEFORE vs AFTER (--compare)");
|
|
1473
|
+
console.log(" " + "-".repeat(70));
|
|
1474
|
+
console.log(` Patch applied: ${patchDiagId}`);
|
|
1475
|
+
console.log("");
|
|
1476
|
+
console.log(" Metric Before (baseline) After (patched)");
|
|
1477
|
+
console.log(" " + "─".repeat(60));
|
|
1478
|
+
console.log(` Stability ${(baseStab * 100).toFixed(0).padStart(3)}% ${(run.metrics.stabilityScore * 100).toFixed(0).padStart(3)}%`);
|
|
1479
|
+
console.log(` Effectiveness ${(baseEff * 100).toFixed(0).padStart(3)}% ${(run.comparison.governanceEffectiveness * 100).toFixed(0).padStart(3)}%`);
|
|
1480
|
+
console.log(` Collapse risk ${(baseCollapse * 100).toFixed(0).padStart(3)}% ${(run.metrics.collapseProbability * 100).toFixed(0).padStart(3)}%`);
|
|
1481
|
+
const stabDelta = run.metrics.stabilityScore - baseStab;
|
|
1482
|
+
const effDelta = run.comparison.governanceEffectiveness - baseEff;
|
|
1483
|
+
console.log("");
|
|
1484
|
+
console.log(` Net change: ${stabDelta >= 0 ? "+" : ""}${(stabDelta * 100).toFixed(0)} stability, ${effDelta >= 0 ? "+" : ""}${(effDelta * 100).toFixed(0)} effectiveness`);
|
|
1485
|
+
if (stabDelta > 0 && effDelta > 0) {
|
|
1486
|
+
console.log(" The fix improved both dimensions. Apply it permanently.");
|
|
1487
|
+
}
|
|
1488
|
+
else if (stabDelta > 0 && effDelta <= 0) {
|
|
1489
|
+
console.log(" Stability improved but effectiveness didn't. The fix may be too conservative.");
|
|
1490
|
+
}
|
|
1491
|
+
else if (stabDelta <= 0 && effDelta > 0) {
|
|
1492
|
+
console.log(" Effectiveness improved but stability dropped. The fix may need guardrails.");
|
|
1493
|
+
}
|
|
1494
|
+
console.log("");
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
// --save: persist this experiment with lineage tracking
|
|
1498
|
+
if (saveExperiment || saveLabel) {
|
|
1499
|
+
const rulesFile = policyDocFiles.length > 0 ? policyDocFiles[0] : null;
|
|
1500
|
+
// Find parent experiment — most recent experiment for same scenario
|
|
1501
|
+
const parentExp = experimentLibrary.length > 0
|
|
1502
|
+
? experimentLibrary.filter(e => e.scenario === report.scenario).pop() ?? null
|
|
1503
|
+
: null;
|
|
1504
|
+
const experiment = createSavedExperiment(report, rulesFile, patchDiagIds, parentExp);
|
|
1505
|
+
const savePath = saveLabel
|
|
1506
|
+
? `experiments/${saveLabel}.json`
|
|
1507
|
+
: `experiments/${experiment.id}.json`;
|
|
1508
|
+
try {
|
|
1509
|
+
fs.mkdirSync("experiments", { recursive: true });
|
|
1510
|
+
fs.writeFileSync(savePath, JSON.stringify(experiment, null, 2));
|
|
1511
|
+
console.log("");
|
|
1512
|
+
console.log(" EXPERIMENT SAVED");
|
|
1513
|
+
console.log(" " + "-".repeat(70));
|
|
1514
|
+
console.log(` Saved to: ${savePath}`);
|
|
1515
|
+
console.log(` ID: ${experiment.id}`);
|
|
1516
|
+
console.log(` Scenario: ${experiment.scenario}`);
|
|
1517
|
+
console.log(` Generation: ${experiment.lineage.generation}`);
|
|
1518
|
+
console.log(` Stability: ${(experiment.metrics.stability * 100).toFixed(0)}% Effectiveness: ${(experiment.metrics.effectiveness * 100).toFixed(0)}%`);
|
|
1519
|
+
if (experiment.archetype) {
|
|
1520
|
+
console.log(` Archetype: ${experiment.archetype}`);
|
|
1521
|
+
}
|
|
1522
|
+
if (experiment.lineage.parentId) {
|
|
1523
|
+
const imp = experiment.lineage.improvementFromParent;
|
|
1524
|
+
console.log(` Derived from: ${experiment.lineage.parentId}`);
|
|
1525
|
+
console.log(` Improvement: ${imp.stability >= 0 ? "+" : ""}${(imp.stability * 100).toFixed(0)} stability, ${imp.effectiveness >= 0 ? "+" : ""}${(imp.effectiveness * 100).toFixed(0)} effectiveness`);
|
|
1526
|
+
if (experiment.lineage.patchesFromParent.length > 0) {
|
|
1527
|
+
console.log(` Patches applied: ${experiment.lineage.patchesFromParent.join(", ")}`);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
// Show lineage chain
|
|
1531
|
+
const updatedLibrary = [...experimentLibrary, experiment];
|
|
1532
|
+
console.log(formatExperimentLineage(experiment, updatedLibrary));
|
|
1533
|
+
console.log(" Compare experiments later:");
|
|
1534
|
+
console.log(` npx nv-sim enforce trading --compare-experiments ${savePath}`);
|
|
1535
|
+
console.log("");
|
|
1536
|
+
}
|
|
1537
|
+
catch {
|
|
1538
|
+
console.log(`\n Could not save experiment to ${savePath}`);
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
// Show guided next steps (skip for JSON output)
|
|
1542
|
+
const usedCustomFiles = inputFiles.length > 0;
|
|
1543
|
+
console.log(await formatGuidedNextSteps(report, usedCustomFiles));
|
|
1544
|
+
}
|
|
1545
|
+
break;
|
|
1546
|
+
}
|
|
353
1547
|
case "help":
|
|
354
1548
|
case "--help":
|
|
355
1549
|
case "-h":
|
|
@@ -362,13 +1556,44 @@ async function main() {
|
|
|
362
1556
|
|
|
363
1557
|
COMMANDS:
|
|
364
1558
|
|
|
365
|
-
compare [preset]
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
1559
|
+
compare [preset] Baseline vs governed comparison (the killer demo)
|
|
1560
|
+
--inject event@round[,event@round,...]
|
|
1561
|
+
scenario <id> Run a named stress scenario
|
|
1562
|
+
--compare to test across multiple worlds
|
|
1563
|
+
scenarios List all available scenarios
|
|
1564
|
+
worlds <a> <b> Same agents, different rule environments
|
|
1565
|
+
enforce [preset] Policy enforcement lab — iterative rule testing
|
|
1566
|
+
Run same scenario with different rules, see divergence
|
|
1567
|
+
--json to output JSON report
|
|
1568
|
+
--output=file.json to save report
|
|
1569
|
+
Pass world files: nv-sim enforce trading a.json b.json
|
|
1570
|
+
chaos [preset] Stress test — find the breaking point
|
|
1571
|
+
visualize Interactive scenario control platform
|
|
1572
|
+
serve | govern Start local governance runtime
|
|
1573
|
+
--port N (default: 3456)
|
|
1574
|
+
run <simulator> Run external simulator with governance
|
|
1575
|
+
e.g., nv-sim run mirofish
|
|
1576
|
+
radiant [preset] Prime Radiant — full policy enforcement system
|
|
1577
|
+
Dual-layer: govern() + governDynamics()
|
|
1578
|
+
--world MODE 1: build & validate world
|
|
1579
|
+
--compare MODE 3: decision intelligence (N options)
|
|
1580
|
+
(default) MODE 2: governed simulation with comparison
|
|
1581
|
+
mirofish MiroFish agent simulation with governance
|
|
1582
|
+
--compare Governed vs ungoverned comparison
|
|
1583
|
+
science Science mode — governed autonomous discovery
|
|
1584
|
+
--compare Governed vs ungoverned comparison
|
|
1585
|
+
world-from-doc <file> Generate world rules from a document
|
|
1586
|
+
--output file.json --id my-world
|
|
1587
|
+
analyze <file> Analyze a simulation from file or stdin
|
|
1588
|
+
presets List available preset scenarios
|
|
1589
|
+
|
|
1590
|
+
WORLD MANAGEMENT:
|
|
1591
|
+
|
|
1592
|
+
world:save <preset> [output.json] Save a world as JSON file
|
|
1593
|
+
--name="My World Name"
|
|
1594
|
+
world:load <file.json> Inspect a saved world file
|
|
1595
|
+
world:list List all available worlds
|
|
1596
|
+
world:compare <a.json> <b.json> Compare two saved world files
|
|
372
1597
|
|
|
373
1598
|
PRESETS:
|
|
374
1599
|
|
|
@@ -379,15 +1604,51 @@ async function main() {
|
|
|
379
1604
|
|
|
380
1605
|
EXAMPLES:
|
|
381
1606
|
|
|
382
|
-
npx nv-sim compare #
|
|
383
|
-
npx nv-sim
|
|
384
|
-
npx nv-sim chaos
|
|
385
|
-
npx nv-sim visualize #
|
|
386
|
-
npx nv-sim
|
|
1607
|
+
npx nv-sim compare # Baseline vs governed
|
|
1608
|
+
npx nv-sim worlds trading strait_of_hormuz # Compare two rule environments
|
|
1609
|
+
npx nv-sim chaos --runs 500 # Stress test (500 runs)
|
|
1610
|
+
npx nv-sim visualize # Live viewer in browser
|
|
1611
|
+
npx nv-sim serve # Start local governance runtime
|
|
1612
|
+
npx nv-sim run mirofish # Run MiroFish with governance
|
|
1613
|
+
npx nv-sim compare strait_of_hormuz # Geopolitical demo
|
|
1614
|
+
npx nv-sim compare --inject tanker_explosion@3 # With narrative shock
|
|
1615
|
+
npx nv-sim compare --inject rate_cut@3,sanctions@5
|
|
1616
|
+
npx nv-sim scenario taiwan_crisis # Named scenario
|
|
1617
|
+
npx nv-sim scenario bank_run --compare # Cross-world comparison
|
|
1618
|
+
npx nv-sim scenarios # List all scenarios
|
|
387
1619
|
npx nv-sim analyze simulation.json
|
|
388
|
-
npx nv-sim
|
|
1620
|
+
npx nv-sim world-from-doc policy.md # Generate world from document
|
|
1621
|
+
npx nv-sim world-from-doc rules.txt --output world.json
|
|
1622
|
+
npx nv-sim world:save trading my-world.json # Save world to file
|
|
1623
|
+
npx nv-sim world:load my-world.json # Inspect a saved world
|
|
1624
|
+
npx nv-sim world:compare a.json b.json # Compare two world files
|
|
389
1625
|
|
|
390
|
-
|
|
1626
|
+
POLICY ENFORCEMENT:
|
|
1627
|
+
|
|
1628
|
+
npx nv-sim enforce # Progressive: no rules → light → full
|
|
1629
|
+
npx nv-sim enforce strait_of_hormuz # Same, with geopolitical preset
|
|
1630
|
+
npx nv-sim enforce trading a.json b.json # Compare custom world files
|
|
1631
|
+
npx nv-sim enforce --output=report.json # Save report as JSON
|
|
1632
|
+
|
|
1633
|
+
PRIME RADIANT:
|
|
1634
|
+
|
|
1635
|
+
npx nv-sim radiant # Full governed simulation
|
|
1636
|
+
npx nv-sim radiant university_crisis # University crisis preset
|
|
1637
|
+
npx nv-sim radiant financial_crisis --compare # Decision intelligence mode
|
|
1638
|
+
npx nv-sim radiant geopolitical_crisis --world # World builder mode
|
|
1639
|
+
npx nv-sim radiant scientific_discovery # Science discovery preset
|
|
1640
|
+
|
|
1641
|
+
MIROFISH MODE:
|
|
1642
|
+
|
|
1643
|
+
npx nv-sim mirofish # Governed agent simulation
|
|
1644
|
+
npx nv-sim mirofish --compare # Governed vs ungoverned comparison
|
|
1645
|
+
|
|
1646
|
+
SCIENCE MODE:
|
|
1647
|
+
|
|
1648
|
+
npx nv-sim science # Governed investigation demo
|
|
1649
|
+
npx nv-sim science --compare # Governed vs ungoverned comparison
|
|
1650
|
+
|
|
1651
|
+
Design rules. Run reality. See what changes.
|
|
391
1652
|
`);
|
|
392
1653
|
break;
|
|
393
1654
|
}
|
|
@@ -480,12 +1741,103 @@ function printComparisonResults(result, worldId) {
|
|
|
480
1741
|
console.log(` World viability: ${gs.finalViability}${gs.worldCollapsed ? " (COLLAPSED)" : ""}`);
|
|
481
1742
|
console.log(` Agents: ${result.baseline.swarm.rounds[0]?.reactions.length ?? 0}`);
|
|
482
1743
|
console.log(` Rounds: ${result.baseline.swarm.rounds.length}`);
|
|
1744
|
+
// Narrative impacts
|
|
1745
|
+
if (result.narrativeImpacts && result.narrativeImpacts.length > 0) {
|
|
1746
|
+
console.log(`\n NARRATIVE IMPACTS`);
|
|
1747
|
+
console.log(" " + "-".repeat(50));
|
|
1748
|
+
for (const ni of result.narrativeImpacts) {
|
|
1749
|
+
console.log(` EVENT: "${ni.event.headline}" (${ni.event.severity})`);
|
|
1750
|
+
for (const shift of ni.agentShifts) {
|
|
1751
|
+
const arrow = shift.impactShift > 0 ? "\u2191" : shift.impactShift < 0 ? "\u2193" : "=";
|
|
1752
|
+
console.log(` ${arrow} ${shift.stakeholder_id}: impact ${shift.impactShift > 0 ? "+" : ""}${shift.impactShift.toFixed(3)}, confidence ${shift.confidenceShift > 0 ? "+" : ""}${shift.confidenceShift.toFixed(3)}`);
|
|
1753
|
+
}
|
|
1754
|
+
for (const effect of ni.systemEffects) {
|
|
1755
|
+
console.log(` > ${effect}`);
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
// Behavioral analysis — what agents did differently
|
|
1760
|
+
console.log((0, behavioralAnalysis_1.formatBehavioralAnalysis)(result.behavioralAnalysis));
|
|
483
1761
|
// Key message
|
|
484
1762
|
console.log(`\n ${"=".repeat(60)}`);
|
|
485
1763
|
console.log(` NeuroVerse doesn't just stop bad actions.`);
|
|
486
1764
|
console.log(` It changes the structure of the system itself.`);
|
|
487
1765
|
console.log(` ${"=".repeat(60)}`);
|
|
488
|
-
console.log(`\n
|
|
1766
|
+
console.log(`\n Design rules. Run reality. See what changes.`);
|
|
1767
|
+
console.log(` neuroverse-simulations | @neuroverseos\n`);
|
|
1768
|
+
}
|
|
1769
|
+
// ============================================
|
|
1770
|
+
// WORLD COMPARISON OUTPUT
|
|
1771
|
+
// ============================================
|
|
1772
|
+
function printWorldComparisonResults(r, impact) {
|
|
1773
|
+
const a = r.worldA;
|
|
1774
|
+
const b = r.worldB;
|
|
1775
|
+
const d = r.delta;
|
|
1776
|
+
console.log(`\n WORLD A — ${a.id}`);
|
|
1777
|
+
console.log(" " + "=".repeat(50));
|
|
1778
|
+
console.log(` Thesis: ${a.thesis}`);
|
|
1779
|
+
console.log(` Invariants: ${a.invariantCount} | Gates: ${a.gateCount}`);
|
|
1780
|
+
console.log(` Trajectory: ${a.trajectory.toUpperCase()}`);
|
|
1781
|
+
console.log(` Stability: ${(a.metrics.stabilityScore * 100).toFixed(0)}%`);
|
|
1782
|
+
console.log(` Collapse probability: ${(a.metrics.collapseProbability * 100).toFixed(0)}%`);
|
|
1783
|
+
console.log(` Peak volatility: ${(a.metrics.maxVolatility * 100).toFixed(0)}%`);
|
|
1784
|
+
console.log(` Coalition risks: ${a.metrics.coalitionRisks}`);
|
|
1785
|
+
console.log(`\n WORLD B — ${b.id}`);
|
|
1786
|
+
console.log(" " + "=".repeat(50));
|
|
1787
|
+
console.log(` Thesis: ${b.thesis}`);
|
|
1788
|
+
console.log(` Invariants: ${b.invariantCount} | Gates: ${b.gateCount}`);
|
|
1789
|
+
console.log(` Trajectory: ${b.trajectory.toUpperCase()}`);
|
|
1790
|
+
console.log(` Stability: ${(b.metrics.stabilityScore * 100).toFixed(0)}%`);
|
|
1791
|
+
console.log(` Collapse probability: ${(b.metrics.collapseProbability * 100).toFixed(0)}%`);
|
|
1792
|
+
console.log(` Peak volatility: ${(b.metrics.maxVolatility * 100).toFixed(0)}%`);
|
|
1793
|
+
console.log(` Coalition risks: ${b.metrics.coalitionRisks}`);
|
|
1794
|
+
console.log(`\n DELTA`);
|
|
1795
|
+
console.log(" " + "=".repeat(50));
|
|
1796
|
+
const stabArrow = d.stabilityDiff > 0 ? "A more stable" : d.stabilityDiff < 0 ? "B more stable" : "equal";
|
|
1797
|
+
console.log(` Stability: ${d.stabilityDiff > 0 ? "+" : ""}${d.stabilityDiff.toFixed(1)} pp (${stabArrow})`);
|
|
1798
|
+
console.log(` Volatility: ${d.volatilityDiff > 0 ? "+" : ""}${d.volatilityDiff.toFixed(1)} pp`);
|
|
1799
|
+
console.log(` Coalition risk: ${d.coalitionRiskDiff > 0 ? "+" : ""}${d.coalitionRiskDiff}`);
|
|
1800
|
+
console.log(` Collapse: ${d.collapseDiff > 0 ? "+" : ""}${d.collapseDiff.toFixed(1)} pp`);
|
|
1801
|
+
console.log(`\n GOVERNANCE ENGINE`);
|
|
1802
|
+
console.log(" " + "-".repeat(50));
|
|
1803
|
+
console.log(` World A: ${a.governanceStats.engineLoaded ? "@neuroverseos/governance" : "heuristic"} — ${a.governanceStats.totalEvaluations} evals (${a.governanceStats.verdicts.allow} allow, ${a.governanceStats.verdicts.block} block, ${a.governanceStats.verdicts.pause} pause)`);
|
|
1804
|
+
console.log(` World B: ${b.governanceStats.engineLoaded ? "@neuroverseos/governance" : "heuristic"} — ${b.governanceStats.totalEvaluations} evals (${b.governanceStats.verdicts.allow} allow, ${b.governanceStats.verdicts.block} block, ${b.governanceStats.verdicts.pause} pause)`);
|
|
1805
|
+
// Impact analysis (when available)
|
|
1806
|
+
if (impact) {
|
|
1807
|
+
console.log(`\n IMPACT ANALYSIS`);
|
|
1808
|
+
console.log(" " + "=".repeat(50));
|
|
1809
|
+
console.log(` Stability delta: ${impact.stabilityDelta}`);
|
|
1810
|
+
console.log(` Cascade risk delta: ${impact.cascadeRiskDelta}`);
|
|
1811
|
+
console.log(` Volatility delta: ${impact.volatilityDelta}`);
|
|
1812
|
+
console.log(` Interventions A: ${impact.totalInterventionsA} (${impact.blockedActionsA} blocked)`);
|
|
1813
|
+
console.log(` Interventions B: ${impact.totalInterventionsB} (${impact.blockedActionsB} blocked)`);
|
|
1814
|
+
console.log(`\n KEY FINDINGS:`);
|
|
1815
|
+
for (const finding of impact.keyFindings) {
|
|
1816
|
+
console.log(` • ${finding}`);
|
|
1817
|
+
}
|
|
1818
|
+
console.log(`\n Powered by ${impact.poweredBy}`);
|
|
1819
|
+
}
|
|
1820
|
+
// Narrative
|
|
1821
|
+
console.log(`\n ANALYSIS`);
|
|
1822
|
+
console.log(" " + "=".repeat(50));
|
|
1823
|
+
const words = d.narrative.split(" ");
|
|
1824
|
+
let line = " ";
|
|
1825
|
+
for (const word of words) {
|
|
1826
|
+
if (line.length + word.length > 72) {
|
|
1827
|
+
console.log(line);
|
|
1828
|
+
line = " " + word;
|
|
1829
|
+
}
|
|
1830
|
+
else {
|
|
1831
|
+
line += (line.trim() ? " " : "") + word;
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
if (line.trim())
|
|
1835
|
+
console.log(line);
|
|
1836
|
+
console.log(`\n ${"=".repeat(60)}`);
|
|
1837
|
+
console.log(` Same agents. Different rules.`);
|
|
1838
|
+
console.log(` The world shapes the outcome.`);
|
|
1839
|
+
console.log(` ${"=".repeat(60)}`);
|
|
1840
|
+
console.log(`\n Design rules. Run reality. See what changes.`);
|
|
489
1841
|
console.log(` neuroverse-simulations | @neuroverseos\n`);
|
|
490
1842
|
}
|
|
491
1843
|
// ============================================
|
|
@@ -551,252 +1903,9 @@ function printChaosResults(r) {
|
|
|
551
1903
|
}
|
|
552
1904
|
console.log(` Tested with nv-sim chaos (${r.runsCompleted} runs, ${(r.durationMs / 1000).toFixed(1)}s)`);
|
|
553
1905
|
console.log(` ${"=".repeat(60)}`);
|
|
554
|
-
console.log(`\n
|
|
1906
|
+
console.log(`\n Design rules. Run reality. See what changes.`);
|
|
555
1907
|
console.log(` neuroverse-simulations | @neuroverseos\n`);
|
|
556
1908
|
}
|
|
557
|
-
// ============================================
|
|
558
|
-
// LOCAL VISUALIZER
|
|
559
|
-
// ============================================
|
|
560
|
-
async function startVisualizer(data, scenarioId) {
|
|
561
|
-
const html = buildVisualizerHtml(data, scenarioId);
|
|
562
|
-
const server = http.createServer((_req, res) => {
|
|
563
|
-
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
564
|
-
res.end(html);
|
|
565
|
-
});
|
|
566
|
-
const port = 3456;
|
|
567
|
-
server.listen(port, () => {
|
|
568
|
-
const url = `http://localhost:${port}`;
|
|
569
|
-
console.log(` Visualizer running at ${url}\n`);
|
|
570
|
-
console.log(" Press Ctrl+C to stop.\n");
|
|
571
|
-
// Try to open browser
|
|
572
|
-
const { exec } = require("child_process");
|
|
573
|
-
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
574
|
-
exec(`${openCmd} ${url}`, () => { });
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
|
-
function buildVisualizerHtml(data, scenarioId) {
|
|
578
|
-
const rounds = data.baseline.swarm.rounds;
|
|
579
|
-
const governedRounds = data.governed.swarm.rounds;
|
|
580
|
-
// Build per-round data for charts
|
|
581
|
-
const roundData = rounds.map((r, i) => {
|
|
582
|
-
const gr = governedRounds[i];
|
|
583
|
-
const blAvg = r.reactions.reduce((s, rx) => s + rx.impact, 0) / r.reactions.length;
|
|
584
|
-
const gvAvg = gr ? gr.reactions.reduce((s, rx) => s + rx.impact, 0) / gr.reactions.length : 0;
|
|
585
|
-
const blVol = Math.max(...r.reactions.map(rx => Math.abs(rx.impact)));
|
|
586
|
-
const gvVol = gr ? Math.max(...gr.reactions.map(rx => Math.abs(rx.impact))) : 0;
|
|
587
|
-
return { round: i, blAvg, gvAvg, blVol, gvVol };
|
|
588
|
-
});
|
|
589
|
-
// Agent data
|
|
590
|
-
const agents = rounds[0]?.reactions.map(r => r.stakeholder_id) ?? [];
|
|
591
|
-
const agentTimelines = agents.map(agentId => ({
|
|
592
|
-
id: agentId,
|
|
593
|
-
baseline: rounds.map(r => {
|
|
594
|
-
const rx = r.reactions.find(a => a.stakeholder_id === agentId);
|
|
595
|
-
return rx ? rx.impact : 0;
|
|
596
|
-
}),
|
|
597
|
-
governed: governedRounds.map(r => {
|
|
598
|
-
const rx = r.reactions.find(a => a.stakeholder_id === agentId);
|
|
599
|
-
return rx ? rx.impact : 0;
|
|
600
|
-
}),
|
|
601
|
-
}));
|
|
602
|
-
// Governance interventions per round
|
|
603
|
-
const dynamics = governedRounds.map(r => r.emergent_dynamics ?? []);
|
|
604
|
-
const jsonData = JSON.stringify({ roundData, agentTimelines, dynamics, scenarioId, data });
|
|
605
|
-
return `<!DOCTYPE html>
|
|
606
|
-
<html lang="en">
|
|
607
|
-
<head>
|
|
608
|
-
<meta charset="UTF-8">
|
|
609
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
610
|
-
<title>NV-SIM Visualizer — ${scenarioId}</title>
|
|
611
|
-
<style>
|
|
612
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
613
|
-
body { font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace; background: #0a0a0a; color: #e0e0e0; padding: 24px; }
|
|
614
|
-
h1 { font-size: 18px; color: #fff; margin-bottom: 4px; }
|
|
615
|
-
.subtitle { color: #888; font-size: 13px; margin-bottom: 24px; }
|
|
616
|
-
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px; }
|
|
617
|
-
.card { background: #141414; border: 1px solid #222; border-radius: 8px; padding: 16px; }
|
|
618
|
-
.card h2 { font-size: 13px; color: #888; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 12px; }
|
|
619
|
-
.metric { display: flex; justify-content: space-between; padding: 4px 0; font-size: 13px; }
|
|
620
|
-
.metric .label { color: #999; }
|
|
621
|
-
.metric .value { color: #fff; font-weight: 600; }
|
|
622
|
-
.metric .value.good { color: #4ade80; }
|
|
623
|
-
.metric .value.bad { color: #f87171; }
|
|
624
|
-
.metric .value.neutral { color: #fbbf24; }
|
|
625
|
-
canvas { width: 100% !important; height: 200px !important; }
|
|
626
|
-
.full-width { grid-column: 1 / -1; }
|
|
627
|
-
.agent-row { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px solid #1a1a1a; font-size: 12px; }
|
|
628
|
-
.agent-name { width: 160px; color: #999; flex-shrink: 0; }
|
|
629
|
-
.bar-container { flex: 1; display: flex; gap: 2px; align-items: center; }
|
|
630
|
-
.bar { height: 20px; border-radius: 3px; min-width: 1px; transition: width 0.3s; }
|
|
631
|
-
.bar.baseline { background: #ef4444; opacity: 0.6; }
|
|
632
|
-
.bar.governed { background: #4ade80; opacity: 0.8; }
|
|
633
|
-
.dynamics-list { font-size: 12px; color: #999; }
|
|
634
|
-
.dynamics-list .round-label { color: #fbbf24; font-weight: 600; }
|
|
635
|
-
.dynamics-list p { padding: 3px 0; }
|
|
636
|
-
.tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; margin: 2px; }
|
|
637
|
-
.tag.allow { background: #052e16; color: #4ade80; }
|
|
638
|
-
.tag.block { background: #2d0606; color: #f87171; }
|
|
639
|
-
.tag.pause { background: #2d2006; color: #fbbf24; }
|
|
640
|
-
.footer { text-align: center; color: #444; font-size: 12px; padding: 24px 0; }
|
|
641
|
-
.sparkline { display: flex; align-items: flex-end; gap: 1px; height: 40px; }
|
|
642
|
-
.spark-bar { flex: 1; border-radius: 2px 2px 0 0; min-width: 3px; }
|
|
643
|
-
</style>
|
|
644
|
-
</head>
|
|
645
|
-
<body>
|
|
646
|
-
<h1>NV-SIM Visualizer</h1>
|
|
647
|
-
<div class="subtitle">${scenarioId} — Baseline vs Governed Comparison</div>
|
|
648
|
-
|
|
649
|
-
<div class="grid">
|
|
650
|
-
<div class="card">
|
|
651
|
-
<h2>Simulation A — Baseline (No Governance)</h2>
|
|
652
|
-
<div id="baseline-metrics"></div>
|
|
653
|
-
</div>
|
|
654
|
-
<div class="card">
|
|
655
|
-
<h2>Simulation B — Governed (World Rules)</h2>
|
|
656
|
-
<div id="governed-metrics"></div>
|
|
657
|
-
</div>
|
|
658
|
-
|
|
659
|
-
<div class="card">
|
|
660
|
-
<h2>Impact Timeline — Average Impact Per Round</h2>
|
|
661
|
-
<canvas id="impactChart"></canvas>
|
|
662
|
-
</div>
|
|
663
|
-
<div class="card">
|
|
664
|
-
<h2>Volatility Timeline — Peak Volatility Per Round</h2>
|
|
665
|
-
<canvas id="volatilityChart"></canvas>
|
|
666
|
-
</div>
|
|
667
|
-
|
|
668
|
-
<div class="card full-width">
|
|
669
|
-
<h2>Agent Behavior — Baseline vs Governed (Final Round)</h2>
|
|
670
|
-
<div id="agent-bars"></div>
|
|
671
|
-
</div>
|
|
672
|
-
|
|
673
|
-
<div class="card">
|
|
674
|
-
<h2>Governance Interventions</h2>
|
|
675
|
-
<div id="dynamics" class="dynamics-list"></div>
|
|
676
|
-
</div>
|
|
677
|
-
<div class="card">
|
|
678
|
-
<h2>Governance Engine Stats</h2>
|
|
679
|
-
<div id="engine-stats"></div>
|
|
680
|
-
</div>
|
|
681
|
-
</div>
|
|
682
|
-
|
|
683
|
-
<div class="footer">
|
|
684
|
-
nv-sim visualize — local simulation inspector<br>
|
|
685
|
-
neuroverse-simulations | @neuroverseos
|
|
686
|
-
</div>
|
|
687
|
-
|
|
688
|
-
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.4/dist/chart.umd.min.js"><\/script>
|
|
689
|
-
<script>
|
|
690
|
-
const SIM = ${jsonData};
|
|
691
|
-
|
|
692
|
-
// Metrics
|
|
693
|
-
function renderMetrics(containerId, metrics, trajectory) {
|
|
694
|
-
const el = document.getElementById(containerId);
|
|
695
|
-
const rows = [
|
|
696
|
-
['Trajectory', trajectory.toUpperCase(), trajectory === 'converging' || trajectory === 'stabilizing' ? 'good' : trajectory === 'escalating' ? 'bad' : 'neutral'],
|
|
697
|
-
['Collapse Probability', (metrics.collapseProbability * 100).toFixed(0) + '%', metrics.collapseProbability < 0.2 ? 'good' : metrics.collapseProbability > 0.5 ? 'bad' : 'neutral'],
|
|
698
|
-
['Stability', (metrics.stabilityScore * 100).toFixed(0) + '%', metrics.stabilityScore > 0.7 ? 'good' : metrics.stabilityScore < 0.4 ? 'bad' : 'neutral'],
|
|
699
|
-
['Peak Volatility', (metrics.maxVolatility * 100).toFixed(0) + '%', metrics.maxVolatility < 0.4 ? 'good' : metrics.maxVolatility > 0.7 ? 'bad' : 'neutral'],
|
|
700
|
-
['Coalition Risks', metrics.coalitionRisks, metrics.coalitionRisks === 0 ? 'good' : 'bad'],
|
|
701
|
-
['Polarization Events', metrics.polarizationEvents, metrics.polarizationEvents === 0 ? 'good' : 'neutral'],
|
|
702
|
-
];
|
|
703
|
-
el.innerHTML = rows.map(([label, value, cls]) =>
|
|
704
|
-
'<div class="metric"><span class="label">' + label + '</span><span class="value ' + cls + '">' + value + '</span></div>'
|
|
705
|
-
).join('');
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
renderMetrics('baseline-metrics', SIM.data.baseline.metrics, SIM.data.baseline.swarm.trajectory);
|
|
709
|
-
renderMetrics('governed-metrics', SIM.data.governed.metrics, SIM.data.governed.swarm.trajectory);
|
|
710
|
-
|
|
711
|
-
// Charts
|
|
712
|
-
const labels = SIM.roundData.map(d => 'R' + d.round);
|
|
713
|
-
|
|
714
|
-
if (typeof Chart !== 'undefined') {
|
|
715
|
-
new Chart(document.getElementById('impactChart'), {
|
|
716
|
-
type: 'line',
|
|
717
|
-
data: {
|
|
718
|
-
labels,
|
|
719
|
-
datasets: [
|
|
720
|
-
{ label: 'Baseline', data: SIM.roundData.map(d => d.blAvg), borderColor: '#ef4444', backgroundColor: 'rgba(239,68,68,0.1)', fill: true, tension: 0.3 },
|
|
721
|
-
{ label: 'Governed', data: SIM.roundData.map(d => d.gvAvg), borderColor: '#4ade80', backgroundColor: 'rgba(74,222,128,0.1)', fill: true, tension: 0.3 },
|
|
722
|
-
]
|
|
723
|
-
},
|
|
724
|
-
options: {
|
|
725
|
-
responsive: true,
|
|
726
|
-
plugins: { legend: { labels: { color: '#888', font: { family: 'monospace' } } } },
|
|
727
|
-
scales: {
|
|
728
|
-
x: { ticks: { color: '#666' }, grid: { color: '#1a1a1a' } },
|
|
729
|
-
y: { ticks: { color: '#666' }, grid: { color: '#1a1a1a' }, min: -1, max: 1 }
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
});
|
|
733
|
-
|
|
734
|
-
new Chart(document.getElementById('volatilityChart'), {
|
|
735
|
-
type: 'bar',
|
|
736
|
-
data: {
|
|
737
|
-
labels,
|
|
738
|
-
datasets: [
|
|
739
|
-
{ label: 'Baseline', data: SIM.roundData.map(d => d.blVol), backgroundColor: 'rgba(239,68,68,0.6)' },
|
|
740
|
-
{ label: 'Governed', data: SIM.roundData.map(d => d.gvVol), backgroundColor: 'rgba(74,222,128,0.6)' },
|
|
741
|
-
]
|
|
742
|
-
},
|
|
743
|
-
options: {
|
|
744
|
-
responsive: true,
|
|
745
|
-
plugins: { legend: { labels: { color: '#888', font: { family: 'monospace' } } } },
|
|
746
|
-
scales: {
|
|
747
|
-
x: { ticks: { color: '#666' }, grid: { color: '#1a1a1a' } },
|
|
748
|
-
y: { ticks: { color: '#666' }, grid: { color: '#1a1a1a' }, min: 0, max: 1 }
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
});
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
// Agent bars (final round comparison)
|
|
755
|
-
const agentBars = document.getElementById('agent-bars');
|
|
756
|
-
const lastRoundIdx = SIM.agentTimelines[0]?.baseline.length - 1 || 0;
|
|
757
|
-
agentBars.innerHTML = SIM.agentTimelines.map(agent => {
|
|
758
|
-
const blImpact = agent.baseline[lastRoundIdx] || 0;
|
|
759
|
-
const gvImpact = agent.governed[lastRoundIdx] || 0;
|
|
760
|
-
const blWidth = Math.abs(blImpact) * 100;
|
|
761
|
-
const gvWidth = Math.abs(gvImpact) * 100;
|
|
762
|
-
const blColor = blImpact >= 0 ? '#4ade80' : '#ef4444';
|
|
763
|
-
const gvColor = gvImpact >= 0 ? '#4ade80' : '#3b82f6';
|
|
764
|
-
return '<div class="agent-row">' +
|
|
765
|
-
'<span class="agent-name">' + agent.id + '</span>' +
|
|
766
|
-
'<div class="bar-container">' +
|
|
767
|
-
'<div class="bar" style="width:' + blWidth + '%;background:' + blColor + ';opacity:0.4" title="Baseline: ' + blImpact.toFixed(2) + '"></div>' +
|
|
768
|
-
'</div>' +
|
|
769
|
-
'<div class="bar-container">' +
|
|
770
|
-
'<div class="bar" style="width:' + gvWidth + '%;background:' + gvColor + '" title="Governed: ' + gvImpact.toFixed(2) + '"></div>' +
|
|
771
|
-
'</div>' +
|
|
772
|
-
'</div>';
|
|
773
|
-
}).join('');
|
|
774
|
-
|
|
775
|
-
// Dynamics
|
|
776
|
-
const dynamicsEl = document.getElementById('dynamics');
|
|
777
|
-
dynamicsEl.innerHTML = SIM.dynamics.map((roundDyn, i) =>
|
|
778
|
-
roundDyn.length > 0
|
|
779
|
-
? '<p><span class="round-label">Round ' + i + ':</span> ' + roundDyn.join('; ') + '</p>'
|
|
780
|
-
: ''
|
|
781
|
-
).filter(Boolean).join('') || '<p>No interventions triggered.</p>';
|
|
782
|
-
|
|
783
|
-
// Engine stats
|
|
784
|
-
const gs = SIM.data.governanceStats;
|
|
785
|
-
const engineEl = document.getElementById('engine-stats');
|
|
786
|
-
engineEl.innerHTML = [
|
|
787
|
-
['Engine', gs.engineLoaded ? '@neuroverseos/governance' : 'heuristic fallback', gs.engineLoaded ? 'good' : 'neutral'],
|
|
788
|
-
['Guard Evaluations', gs.totalEvaluations, ''],
|
|
789
|
-
['Verdicts', '<span class="tag allow">' + gs.verdicts.allow + ' allow</span><span class="tag block">' + gs.verdicts.block + ' block</span><span class="tag pause">' + gs.verdicts.pause + ' pause</span>', ''],
|
|
790
|
-
['Rules Fired', gs.rulesFired, ''],
|
|
791
|
-
['World Viability', gs.finalViability + (gs.worldCollapsed ? ' (COLLAPSED)' : ''), gs.worldCollapsed ? 'bad' : 'good'],
|
|
792
|
-
['Invariants Checked', gs.invariantsChecked, ''],
|
|
793
|
-
].map(([label, value, cls]) =>
|
|
794
|
-
'<div class="metric"><span class="label">' + label + '</span><span class="value ' + cls + '">' + value + '</span></div>'
|
|
795
|
-
).join('');
|
|
796
|
-
<\/script>
|
|
797
|
-
</body>
|
|
798
|
-
</html>`;
|
|
799
|
-
}
|
|
800
1909
|
main().catch((err) => {
|
|
801
1910
|
console.error("Error:", err.message);
|
|
802
1911
|
process.exit(1);
|