@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
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MiroFish Adapter — Governance Wrapper for MiroFish Simulations
|
|
4
|
+
*
|
|
5
|
+
* "MiroFish shows what could happen. NeuroVerse ensures what happens makes sense."
|
|
6
|
+
*
|
|
7
|
+
* This adapter wraps MiroFish's simulation loop with dual-layer governance.
|
|
8
|
+
* It does NOT fork or modify MiroFish — it intercepts inputs, actions, and outputs.
|
|
9
|
+
*
|
|
10
|
+
* Architecture:
|
|
11
|
+
* MiroFish runs as-is
|
|
12
|
+
* NeuroVerse wraps:
|
|
13
|
+
* - agent actions → govern(action) [Layer A]
|
|
14
|
+
* - system state → governDynamics(state) [Layer B]
|
|
15
|
+
* - outputs → science metrics + verdicts
|
|
16
|
+
*
|
|
17
|
+
* Hook points (where NeuroVerse intercepts):
|
|
18
|
+
* 1. Agent execution: action = agent.act() → govern(action) → commit
|
|
19
|
+
* 2. Round completion: state = step(actions) → governDynamics(state)
|
|
20
|
+
* 3. Artifact creation: artifact = produce() → governArtifact(artifact)
|
|
21
|
+
*
|
|
22
|
+
* Usage:
|
|
23
|
+
* const wrapper = createMiroFishWrapper({
|
|
24
|
+
* policyText: SCIENCE_POLICY_TEXT,
|
|
25
|
+
* onIntervention: (event) => emitToUI(event),
|
|
26
|
+
* })
|
|
27
|
+
*
|
|
28
|
+
* // In MiroFish's loop:
|
|
29
|
+
* wrapper.interceptAction(agentId, action)
|
|
30
|
+
* wrapper.completeCycle(cycleState)
|
|
31
|
+
* const metrics = wrapper.getMetrics()
|
|
32
|
+
*/
|
|
33
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
+
exports.createMiroFishWrapper = createMiroFishWrapper;
|
|
35
|
+
exports.generateDemoSimulation = generateDemoSimulation;
|
|
36
|
+
exports.runMiroFishComparison = runMiroFishComparison;
|
|
37
|
+
const govern_1 = require("../runtime/govern");
|
|
38
|
+
const dynamicsGovernance_1 = require("../engine/dynamicsGovernance");
|
|
39
|
+
const science_metrics_1 = require("../engine/metrics/science.metrics");
|
|
40
|
+
// ============================================
|
|
41
|
+
// ACTION CONVERSION
|
|
42
|
+
// ============================================
|
|
43
|
+
function simulatorActionToAgentAction(action) {
|
|
44
|
+
return {
|
|
45
|
+
agentId: action.agentId,
|
|
46
|
+
type: action.type,
|
|
47
|
+
description: action.description,
|
|
48
|
+
magnitude: action.magnitude,
|
|
49
|
+
context: {
|
|
50
|
+
originalImpact: action.impact,
|
|
51
|
+
confidence: action.confidence,
|
|
52
|
+
trigger: action.trigger,
|
|
53
|
+
...action.metadata,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function simulatorActionsToReactions(actions) {
|
|
58
|
+
return actions.map((action) => ({
|
|
59
|
+
stakeholder_id: action.agentId,
|
|
60
|
+
reaction: action.description,
|
|
61
|
+
confidence: action.confidence,
|
|
62
|
+
impact: action.impact,
|
|
63
|
+
trigger: action.trigger ?? "simulation_cycle",
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
// ============================================
|
|
67
|
+
// FACTORY: createMiroFishWrapper()
|
|
68
|
+
// ============================================
|
|
69
|
+
function createMiroFishWrapper(config = {}) {
|
|
70
|
+
const policyText = config.policyText ?? science_metrics_1.SCIENCE_POLICY_TEXT;
|
|
71
|
+
let _enabled = config.enabled ?? true;
|
|
72
|
+
const actionGov = (0, govern_1.createGovernor)({
|
|
73
|
+
policyText,
|
|
74
|
+
sensitivity: 0.5,
|
|
75
|
+
});
|
|
76
|
+
const dynamicsGov = (0, dynamicsGovernance_1.createDynamicsGovernor)(policyText, { ...science_metrics_1.SCIENCE_INITIAL_STATE, ...config.initialState });
|
|
77
|
+
let cycleCount = 0;
|
|
78
|
+
const actionStats = { total: 0, allowed: 0, blocked: 0, modified: 0, paused: 0 };
|
|
79
|
+
const recentInterventions = [];
|
|
80
|
+
// --- Intercept single action (Layer A) ---
|
|
81
|
+
function interceptAction(action) {
|
|
82
|
+
actionStats.total++;
|
|
83
|
+
if (!_enabled) {
|
|
84
|
+
actionStats.allowed++;
|
|
85
|
+
return {
|
|
86
|
+
original: action,
|
|
87
|
+
verdict: { status: "ALLOW", reason: "Governance disabled", action: simulatorActionToAgentAction(action), rulesFired: [], confidence: 1, timestamp: Date.now() },
|
|
88
|
+
governed: action,
|
|
89
|
+
wasModified: false,
|
|
90
|
+
wasBlocked: false,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const agentAction = simulatorActionToAgentAction(action);
|
|
94
|
+
const currentState = dynamicsGov.state;
|
|
95
|
+
const worldState = {
|
|
96
|
+
volatility: currentState.outrage * 100,
|
|
97
|
+
liquidity: currentState.trust * 100,
|
|
98
|
+
polarization: currentState.polarization * 100,
|
|
99
|
+
cascade_risk: currentState.cascadeRisk * 100,
|
|
100
|
+
};
|
|
101
|
+
const verdict = actionGov.evaluate(agentAction, worldState);
|
|
102
|
+
switch (verdict.status) {
|
|
103
|
+
case "ALLOW":
|
|
104
|
+
actionStats.allowed++;
|
|
105
|
+
break;
|
|
106
|
+
case "BLOCK":
|
|
107
|
+
actionStats.blocked++;
|
|
108
|
+
break;
|
|
109
|
+
case "MODIFY":
|
|
110
|
+
actionStats.modified++;
|
|
111
|
+
break;
|
|
112
|
+
case "PAUSE":
|
|
113
|
+
actionStats.paused++;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
let governed;
|
|
117
|
+
let wasModified = false;
|
|
118
|
+
let wasBlocked = false;
|
|
119
|
+
if (verdict.status === "BLOCK") {
|
|
120
|
+
governed = null;
|
|
121
|
+
wasBlocked = true;
|
|
122
|
+
recentInterventions.unshift({
|
|
123
|
+
cycle: cycleCount,
|
|
124
|
+
type: "block",
|
|
125
|
+
agentId: action.agentId,
|
|
126
|
+
description: `Blocked: ${action.type} from ${action.agentId} — ${verdict.reason}`,
|
|
127
|
+
magnitude: action.magnitude,
|
|
128
|
+
metric: "action",
|
|
129
|
+
before: action.magnitude,
|
|
130
|
+
after: 0,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
else if (verdict.status === "MODIFY" && verdict.action) {
|
|
134
|
+
const ratio = verdict.action.magnitude / Math.max(0.001, action.magnitude);
|
|
135
|
+
governed = {
|
|
136
|
+
...action,
|
|
137
|
+
magnitude: verdict.action.magnitude,
|
|
138
|
+
impact: action.impact * ratio,
|
|
139
|
+
};
|
|
140
|
+
wasModified = true;
|
|
141
|
+
recentInterventions.unshift({
|
|
142
|
+
cycle: cycleCount,
|
|
143
|
+
type: "modify",
|
|
144
|
+
agentId: action.agentId,
|
|
145
|
+
description: `Modified: ${action.type} from ${action.agentId} — magnitude reduced`,
|
|
146
|
+
magnitude: verdict.action.magnitude,
|
|
147
|
+
metric: "magnitude",
|
|
148
|
+
before: action.magnitude,
|
|
149
|
+
after: verdict.action.magnitude,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else if (verdict.status === "PAUSE") {
|
|
153
|
+
governed = {
|
|
154
|
+
...action,
|
|
155
|
+
magnitude: action.magnitude * 0.5,
|
|
156
|
+
impact: action.impact * 0.5,
|
|
157
|
+
};
|
|
158
|
+
wasModified = true;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
governed = action;
|
|
162
|
+
}
|
|
163
|
+
// Keep only recent interventions
|
|
164
|
+
if (recentInterventions.length > 50) {
|
|
165
|
+
recentInterventions.length = 50;
|
|
166
|
+
}
|
|
167
|
+
const result = {
|
|
168
|
+
original: action,
|
|
169
|
+
verdict,
|
|
170
|
+
governed,
|
|
171
|
+
wasModified,
|
|
172
|
+
wasBlocked,
|
|
173
|
+
};
|
|
174
|
+
config.onAction?.(result);
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
// --- Complete cycle (Layer B) ---
|
|
178
|
+
function completeCycle(state) {
|
|
179
|
+
cycleCount = state.cycle;
|
|
180
|
+
if (!_enabled) {
|
|
181
|
+
// Still track state but don't intervene
|
|
182
|
+
const reactions = simulatorActionsToReactions(state.actions);
|
|
183
|
+
const result = dynamicsGov.governRound(reactions, state.cycle);
|
|
184
|
+
// Without governance, system degrades naturally
|
|
185
|
+
dynamicsGov.mutateState((st) => {
|
|
186
|
+
st.trust = Math.max(0.05, st.trust - 0.04);
|
|
187
|
+
st.cascadeRisk = Math.min(1, st.cascadeRisk + 0.05);
|
|
188
|
+
st.polarization = Math.min(1, st.polarization + 0.03);
|
|
189
|
+
st.outrage = Math.min(1, st.outrage + 0.02);
|
|
190
|
+
});
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
const reactions = simulatorActionsToReactions(state.actions);
|
|
194
|
+
// Apply simulator-reported metrics if available
|
|
195
|
+
if (state.systemMetrics) {
|
|
196
|
+
dynamicsGov.mutateState((st) => {
|
|
197
|
+
if (state.systemMetrics.trust !== undefined) {
|
|
198
|
+
st.trust = st.trust * 0.7 + state.systemMetrics.trust * 0.3;
|
|
199
|
+
}
|
|
200
|
+
if (state.systemMetrics.polarization !== undefined) {
|
|
201
|
+
st.polarization = st.polarization * 0.7 + state.systemMetrics.polarization * 0.3;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
const result = dynamicsGov.governRound(reactions, state.cycle);
|
|
206
|
+
// Feed governance activity into state (blocked actions improve system health)
|
|
207
|
+
const blockFraction = actionStats.blocked / Math.max(1, actionStats.total);
|
|
208
|
+
if (blockFraction > 0.1) {
|
|
209
|
+
dynamicsGov.mutateState((st) => {
|
|
210
|
+
st.trust = Math.min(1, st.trust + blockFraction * 0.06);
|
|
211
|
+
st.cascadeRisk = Math.max(0, st.cascadeRisk - blockFraction * 0.08);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
// Map dynamics interventions to wrapper events
|
|
215
|
+
for (const intervention of result.interventions) {
|
|
216
|
+
const typeMap = {
|
|
217
|
+
PROPAGATION_LIMIT: "slow",
|
|
218
|
+
AMPLIFICATION_DAMPEN: "slow",
|
|
219
|
+
CASCADE_BREAKER: "break",
|
|
220
|
+
COOLING_PERIOD: "cool",
|
|
221
|
+
TRUST_BOOST: "boost",
|
|
222
|
+
VISIBILITY_SHIFT: "boost",
|
|
223
|
+
FEEDBACK_DAMPEN: "slow",
|
|
224
|
+
};
|
|
225
|
+
recentInterventions.unshift({
|
|
226
|
+
cycle: state.cycle,
|
|
227
|
+
type: typeMap[intervention.type] ?? "slow",
|
|
228
|
+
agentId: "system",
|
|
229
|
+
description: intervention.description.length > 120
|
|
230
|
+
? intervention.description.slice(0, 120) + "..."
|
|
231
|
+
: intervention.description,
|
|
232
|
+
magnitude: intervention.magnitude,
|
|
233
|
+
metric: intervention.effect.metric,
|
|
234
|
+
before: intervention.effect.before,
|
|
235
|
+
after: intervention.effect.after,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
if (recentInterventions.length > 50) {
|
|
239
|
+
recentInterventions.length = 50;
|
|
240
|
+
}
|
|
241
|
+
// Notify UI
|
|
242
|
+
config.onStateChange?.(result.systemState);
|
|
243
|
+
for (const intervention of result.interventions) {
|
|
244
|
+
const typeMap = {
|
|
245
|
+
PROPAGATION_LIMIT: "slow",
|
|
246
|
+
AMPLIFICATION_DAMPEN: "slow",
|
|
247
|
+
CASCADE_BREAKER: "break",
|
|
248
|
+
COOLING_PERIOD: "cool",
|
|
249
|
+
TRUST_BOOST: "boost",
|
|
250
|
+
VISIBILITY_SHIFT: "boost",
|
|
251
|
+
FEEDBACK_DAMPEN: "slow",
|
|
252
|
+
};
|
|
253
|
+
config.onIntervention?.({
|
|
254
|
+
cycle: state.cycle,
|
|
255
|
+
type: typeMap[intervention.type] ?? "slow",
|
|
256
|
+
agentId: "system",
|
|
257
|
+
description: intervention.description,
|
|
258
|
+
magnitude: intervention.magnitude,
|
|
259
|
+
metric: intervention.effect.metric,
|
|
260
|
+
before: intervention.effect.before,
|
|
261
|
+
after: intervention.effect.after,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
const metrics = getMetrics();
|
|
265
|
+
config.onCycleComplete?.(metrics);
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
// --- Get current metrics ---
|
|
269
|
+
function getMetrics() {
|
|
270
|
+
const state = dynamicsGov.state;
|
|
271
|
+
const sciState = (0, science_metrics_1.interpretScienceState)(state);
|
|
272
|
+
const stats = dynamicsGov.stats;
|
|
273
|
+
return {
|
|
274
|
+
cycle: cycleCount,
|
|
275
|
+
enabled: _enabled,
|
|
276
|
+
systemState: state,
|
|
277
|
+
scienceState: sciState,
|
|
278
|
+
actionStats: { ...actionStats },
|
|
279
|
+
dynamicsStats: stats,
|
|
280
|
+
recentInterventions: [...recentInterventions],
|
|
281
|
+
trajectory: stats.totalRounds > 0
|
|
282
|
+
? (state.cascadeRisk > 0.7 ? "critical"
|
|
283
|
+
: state.outrage > 0.5 ? "escalating"
|
|
284
|
+
: state.trust > 0.5 ? "stabilizing"
|
|
285
|
+
: "at-risk")
|
|
286
|
+
: "initializing",
|
|
287
|
+
assessment: sciState.overallAssessment,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function setEnabled(enabled) {
|
|
291
|
+
_enabled = enabled;
|
|
292
|
+
}
|
|
293
|
+
function reset() {
|
|
294
|
+
dynamicsGov.reset();
|
|
295
|
+
cycleCount = 0;
|
|
296
|
+
actionStats.total = 0;
|
|
297
|
+
actionStats.allowed = 0;
|
|
298
|
+
actionStats.blocked = 0;
|
|
299
|
+
actionStats.modified = 0;
|
|
300
|
+
actionStats.paused = 0;
|
|
301
|
+
recentInterventions.length = 0;
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
interceptAction,
|
|
305
|
+
completeCycle,
|
|
306
|
+
getMetrics,
|
|
307
|
+
setEnabled,
|
|
308
|
+
get enabled() { return _enabled; },
|
|
309
|
+
get state() { return dynamicsGov.state; },
|
|
310
|
+
get scienceState() { return (0, science_metrics_1.interpretScienceState)(dynamicsGov.state); },
|
|
311
|
+
reset,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
// ============================================
|
|
315
|
+
// DEMO: generateDemoSimulation()
|
|
316
|
+
// ============================================
|
|
317
|
+
/**
|
|
318
|
+
* Generate a realistic multi-agent simulation scenario.
|
|
319
|
+
*
|
|
320
|
+
* Models a market stress event where agents react over 10 rounds:
|
|
321
|
+
* - Rounds 1-2: Normal trading, low volatility
|
|
322
|
+
* - Rounds 3-4: Shock event, panic selling begins
|
|
323
|
+
* - Rounds 5-6: Cascade risk as agents amplify each other
|
|
324
|
+
* - Rounds 7-8: With governance: dampened. Without: spiral.
|
|
325
|
+
* - Rounds 9-10: Recovery (governed) or collapse (ungoverned)
|
|
326
|
+
*/
|
|
327
|
+
function generateDemoSimulation() {
|
|
328
|
+
const agents = [
|
|
329
|
+
{ id: "momentum_trader_1", role: "momentum_trader", volatility: 0.7 },
|
|
330
|
+
{ id: "momentum_trader_2", role: "momentum_trader", volatility: 0.6 },
|
|
331
|
+
{ id: "market_maker_1", role: "market_maker", volatility: 0.2 },
|
|
332
|
+
{ id: "hedge_fund_1", role: "hedge_fund", volatility: 0.5 },
|
|
333
|
+
{ id: "hedge_fund_2", role: "hedge_fund", volatility: 0.4 },
|
|
334
|
+
{ id: "retail_investor_1", role: "retail_investor", volatility: 0.8 },
|
|
335
|
+
{ id: "retail_investor_2", role: "retail_investor", volatility: 0.9 },
|
|
336
|
+
{ id: "algo_trader_1", role: "algorithmic_trader", volatility: 0.65 },
|
|
337
|
+
];
|
|
338
|
+
const rounds = [];
|
|
339
|
+
// Seeded pseudo-random for deterministic output
|
|
340
|
+
let seed = 42;
|
|
341
|
+
const rand = () => { seed = (seed * 16807 + 0) % 2147483647; return seed / 2147483647; };
|
|
342
|
+
for (let round = 1; round <= 10; round++) {
|
|
343
|
+
const actions = [];
|
|
344
|
+
// Market pressure curve: peaks at round 5-6
|
|
345
|
+
const pressure = round <= 2 ? 0.1 + round * 0.05
|
|
346
|
+
: round <= 4 ? 0.2 + (round - 2) * 0.2
|
|
347
|
+
: round <= 6 ? 0.6 + (round - 4) * 0.15
|
|
348
|
+
: round <= 8 ? 0.9 - (round - 6) * 0.1
|
|
349
|
+
: 0.7 - (round - 8) * 0.2;
|
|
350
|
+
for (const agent of agents) {
|
|
351
|
+
const agentPanic = pressure * agent.volatility;
|
|
352
|
+
const noise = (rand() - 0.5) * 0.3;
|
|
353
|
+
let type;
|
|
354
|
+
let description;
|
|
355
|
+
let magnitude;
|
|
356
|
+
let impact;
|
|
357
|
+
if (agentPanic + noise > 0.7) {
|
|
358
|
+
// Destabilizing action
|
|
359
|
+
const destabilizing = ["panic_sell", "aggressive_buy", "increase_leverage"];
|
|
360
|
+
type = destabilizing[Math.floor(rand() * destabilizing.length)];
|
|
361
|
+
magnitude = 0.6 + rand() * 0.4;
|
|
362
|
+
impact = -(0.3 + rand() * 0.5);
|
|
363
|
+
description = `${agent.role} executes ${type} under market stress (pressure: ${(agentPanic * 100).toFixed(0)}%)`;
|
|
364
|
+
}
|
|
365
|
+
else if (agentPanic + noise > 0.4) {
|
|
366
|
+
// Neutral action
|
|
367
|
+
const neutral = ["buy", "sell", "short", "cover"];
|
|
368
|
+
type = neutral[Math.floor(rand() * neutral.length)];
|
|
369
|
+
magnitude = 0.3 + rand() * 0.4;
|
|
370
|
+
impact = (rand() - 0.5) * 0.4;
|
|
371
|
+
description = `${agent.role} takes ${type} position amid uncertainty`;
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
// Stabilizing action
|
|
375
|
+
const stabilizing = ["hold", "hedge", "reduce_exposure"];
|
|
376
|
+
type = stabilizing[Math.floor(rand() * stabilizing.length)];
|
|
377
|
+
magnitude = 0.1 + rand() * 0.3;
|
|
378
|
+
impact = 0.1 + rand() * 0.3;
|
|
379
|
+
description = `${agent.role} ${type}s to manage risk`;
|
|
380
|
+
}
|
|
381
|
+
actions.push({
|
|
382
|
+
agentId: agent.id,
|
|
383
|
+
type,
|
|
384
|
+
description,
|
|
385
|
+
magnitude: Number(magnitude.toFixed(3)),
|
|
386
|
+
impact: Number(impact.toFixed(3)),
|
|
387
|
+
confidence: Number((0.4 + rand() * 0.5).toFixed(3)),
|
|
388
|
+
trigger: round <= 2 ? "normal_market" : round <= 4 ? "volatility_spike" : "cascade_pressure",
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
rounds.push(actions);
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
rounds,
|
|
395
|
+
scenario: "Market stress cascade — 8 agents, 10 rounds, shock at round 3",
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Run a full governed vs ungoverned comparison using the MiroFish wrapper.
|
|
400
|
+
*
|
|
401
|
+
* This is the self-contained demo: no external dependencies,
|
|
402
|
+
* no Python, no MiroFish instance needed.
|
|
403
|
+
*/
|
|
404
|
+
function runMiroFishComparison() {
|
|
405
|
+
const demo = generateDemoSimulation();
|
|
406
|
+
// --- Governed run ---
|
|
407
|
+
const govWrapper = createMiroFishWrapper({ enabled: true });
|
|
408
|
+
const govTimeline = [];
|
|
409
|
+
for (let i = 0; i < demo.rounds.length; i++) {
|
|
410
|
+
const round = demo.rounds[i];
|
|
411
|
+
const approvedActions = [];
|
|
412
|
+
for (const action of round) {
|
|
413
|
+
const result = govWrapper.interceptAction(action);
|
|
414
|
+
if (!result.wasBlocked) {
|
|
415
|
+
approvedActions.push(result.governed ?? action);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
govWrapper.completeCycle({
|
|
419
|
+
cycle: i + 1,
|
|
420
|
+
actions: approvedActions,
|
|
421
|
+
});
|
|
422
|
+
govTimeline.push(govWrapper.getMetrics());
|
|
423
|
+
}
|
|
424
|
+
const govMetrics = govWrapper.getMetrics();
|
|
425
|
+
const govState = govMetrics.systemState;
|
|
426
|
+
const govVerdict = govState.trust > 0.5 && govState.cascadeRisk < 0.3
|
|
427
|
+
? "stabilized" : govState.trust < 0.2 ? "collapsed" : "at-risk";
|
|
428
|
+
// --- Ungoverned run ---
|
|
429
|
+
const ungovWrapper = createMiroFishWrapper({ enabled: false });
|
|
430
|
+
const ungovTimeline = [];
|
|
431
|
+
for (let i = 0; i < demo.rounds.length; i++) {
|
|
432
|
+
const round = demo.rounds[i];
|
|
433
|
+
for (const action of round) {
|
|
434
|
+
ungovWrapper.interceptAction(action);
|
|
435
|
+
}
|
|
436
|
+
ungovWrapper.completeCycle({
|
|
437
|
+
cycle: i + 1,
|
|
438
|
+
actions: round,
|
|
439
|
+
});
|
|
440
|
+
ungovTimeline.push(ungovWrapper.getMetrics());
|
|
441
|
+
}
|
|
442
|
+
const ungovMetrics = ungovWrapper.getMetrics();
|
|
443
|
+
const ungovState = ungovMetrics.systemState;
|
|
444
|
+
const ungovVerdict = ungovState.trust > 0.5 && ungovState.cascadeRisk < 0.3
|
|
445
|
+
? "stabilized" : ungovState.trust < 0.2 ? "collapsed" : "at-risk";
|
|
446
|
+
return {
|
|
447
|
+
governed: {
|
|
448
|
+
metrics: govMetrics,
|
|
449
|
+
timeline: govTimeline,
|
|
450
|
+
totalBlocked: govMetrics.actionStats.blocked,
|
|
451
|
+
totalModified: govMetrics.actionStats.modified,
|
|
452
|
+
verdict: govVerdict,
|
|
453
|
+
},
|
|
454
|
+
ungoverned: {
|
|
455
|
+
metrics: ungovMetrics,
|
|
456
|
+
timeline: ungovTimeline,
|
|
457
|
+
verdict: ungovVerdict,
|
|
458
|
+
},
|
|
459
|
+
scenario: demo.scenario,
|
|
460
|
+
};
|
|
461
|
+
}
|