@neuroverseos/nv-sim 0.1.6 → 0.1.9
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 +374 -123
- package/dist/assets/index-B64NuIXu.css +1 -0
- package/dist/assets/{index-CHmUN8s0.js → index-BMkPevVr.js} +105 -105
- package/dist/assets/{reportEngine-BVdQ2_nW.js → reportEngine-D2ZrMny8.js} +1 -1
- package/dist/engine/chaosEngine.js +3 -9
- package/dist/engine/cli.js +34 -104
- package/dist/engine/index.js +2 -3
- package/dist/engine/liveVisualizer.js +1530 -230
- package/dist/engine/narrativeInjection.js +78 -89
- package/dist/engine/policyEngine.js +171 -58
- package/dist/engine/scenarioCapsule.js +73 -129
- package/dist/engine/scenarioLibrary.js +52 -131
- package/dist/engine/worldComparison.js +12 -25
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/dist/assets/index-DWgMnB7I.css +0 -1
|
@@ -127,126 +127,115 @@ function injectNarrative(reactions, event, stakeholders) {
|
|
|
127
127
|
// PRESET NARRATIVE EVENTS
|
|
128
128
|
// ============================================
|
|
129
129
|
exports.NARRATIVE_PRESETS = {
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
id: "
|
|
133
|
-
headline: "
|
|
134
|
-
severity: "
|
|
135
|
-
targets: ["
|
|
130
|
+
// Social Simulation
|
|
131
|
+
viral_misinfo: {
|
|
132
|
+
id: "viral_misinfo",
|
|
133
|
+
headline: "Viral misinformation post spreads rapidly — no sources cited",
|
|
134
|
+
severity: "major",
|
|
135
|
+
targets: ["Content Creators", "Community Members", "Influencers", "Platform"],
|
|
136
136
|
direction: "negative",
|
|
137
137
|
propagation: "viral",
|
|
138
|
-
category: "
|
|
138
|
+
category: "social",
|
|
139
139
|
},
|
|
140
|
-
|
|
141
|
-
id: "
|
|
142
|
-
headline: "
|
|
140
|
+
influencer_stance_change: {
|
|
141
|
+
id: "influencer_stance_change",
|
|
142
|
+
headline: "Key influencer reverses stance — followers split",
|
|
143
143
|
severity: "major",
|
|
144
|
-
targets: ["
|
|
145
|
-
direction: "
|
|
146
|
-
propagation: "viral",
|
|
147
|
-
category: "monetary",
|
|
148
|
-
},
|
|
149
|
-
bank_collapse: {
|
|
150
|
-
id: "bank_collapse",
|
|
151
|
-
headline: "Major bank reports insolvency — contagion fears",
|
|
152
|
-
severity: "extreme",
|
|
153
|
-
targets: ["Institutional", "Retail", "Financial", "Market Makers"],
|
|
154
|
-
direction: "negative",
|
|
144
|
+
targets: ["Influencers", "Community Members", "Observers"],
|
|
145
|
+
direction: "mixed",
|
|
155
146
|
propagation: "viral",
|
|
156
|
-
category: "
|
|
147
|
+
category: "social",
|
|
157
148
|
},
|
|
158
|
-
|
|
159
|
-
id: "
|
|
160
|
-
headline: "
|
|
149
|
+
algorithm_change: {
|
|
150
|
+
id: "algorithm_change",
|
|
151
|
+
headline: "Platform algorithm change — viral threshold shifts overnight",
|
|
161
152
|
severity: "moderate",
|
|
162
|
-
targets: ["
|
|
163
|
-
direction: "
|
|
153
|
+
targets: ["Content Creators", "Influencers", "Platform", "Community Members"],
|
|
154
|
+
direction: "mixed",
|
|
164
155
|
propagation: "normal",
|
|
165
|
-
category: "
|
|
156
|
+
category: "social",
|
|
166
157
|
},
|
|
167
|
-
|
|
168
|
-
id: "
|
|
169
|
-
headline: "
|
|
158
|
+
external_news_event: {
|
|
159
|
+
id: "external_news_event",
|
|
160
|
+
headline: "Breaking external news event floods the platform",
|
|
170
161
|
severity: "major",
|
|
171
|
-
targets: ["
|
|
162
|
+
targets: ["Content Creators", "Community Members", "Influencers", "Observers"],
|
|
172
163
|
direction: "negative",
|
|
173
|
-
propagation: "
|
|
174
|
-
category: "
|
|
164
|
+
propagation: "viral",
|
|
165
|
+
category: "social",
|
|
175
166
|
},
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
headline: "China begins military exercises near Taiwan",
|
|
167
|
+
coordinated_campaign: {
|
|
168
|
+
id: "coordinated_campaign",
|
|
169
|
+
headline: "Coordinated posting campaign detected — same content from multiple agents",
|
|
180
170
|
severity: "major",
|
|
181
|
-
targets: ["
|
|
171
|
+
targets: ["Bad Actors", "Community Members", "Platform"],
|
|
182
172
|
direction: "negative",
|
|
183
|
-
propagation: "
|
|
184
|
-
category: "
|
|
173
|
+
propagation: "normal",
|
|
174
|
+
category: "social",
|
|
185
175
|
},
|
|
186
|
-
|
|
187
|
-
id: "
|
|
188
|
-
headline: "
|
|
176
|
+
whistleblower_post: {
|
|
177
|
+
id: "whistleblower_post",
|
|
178
|
+
headline: "Whistleblower post surfaces with sourced evidence — shifts discourse",
|
|
189
179
|
severity: "major",
|
|
190
|
-
targets: ["
|
|
180
|
+
targets: ["Community Members", "Influencers", "Observers", "Platform"],
|
|
191
181
|
direction: "positive",
|
|
192
|
-
propagation: "
|
|
193
|
-
category: "
|
|
182
|
+
propagation: "viral",
|
|
183
|
+
category: "social",
|
|
184
|
+
},
|
|
185
|
+
// Science / Research
|
|
186
|
+
search_literature: {
|
|
187
|
+
id: "search_literature",
|
|
188
|
+
headline: "Agent searches PubMed for peer-reviewed sources",
|
|
189
|
+
severity: "minor",
|
|
190
|
+
targets: ["Research Agent", "Peer Reviewers"],
|
|
191
|
+
direction: "positive",
|
|
192
|
+
propagation: "slow",
|
|
193
|
+
category: "research",
|
|
194
194
|
},
|
|
195
|
-
|
|
196
|
-
id: "
|
|
197
|
-
headline: "
|
|
195
|
+
analyze_findings: {
|
|
196
|
+
id: "analyze_findings",
|
|
197
|
+
headline: "Agent analyzes findings and extracts key mechanisms",
|
|
198
198
|
severity: "moderate",
|
|
199
|
-
targets: ["
|
|
199
|
+
targets: ["Research Agent", "Peer Reviewers"],
|
|
200
200
|
direction: "positive",
|
|
201
|
-
propagation: "
|
|
202
|
-
category: "
|
|
201
|
+
propagation: "slow",
|
|
202
|
+
category: "research",
|
|
203
203
|
},
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
category: "political",
|
|
204
|
+
cross_reference: {
|
|
205
|
+
id: "cross_reference",
|
|
206
|
+
headline: "Agent cross-references sources for consistency",
|
|
207
|
+
severity: "moderate",
|
|
208
|
+
targets: ["Research Agent", "Peer Reviewers", "Journal Editors"],
|
|
209
|
+
direction: "positive",
|
|
210
|
+
propagation: "slow",
|
|
211
|
+
category: "research",
|
|
213
212
|
},
|
|
214
|
-
|
|
215
|
-
id: "
|
|
216
|
-
headline: "
|
|
213
|
+
unsupported_claim: {
|
|
214
|
+
id: "unsupported_claim",
|
|
215
|
+
headline: "Agent attempts to publish claim without sufficient sources",
|
|
217
216
|
severity: "major",
|
|
218
|
-
targets: ["
|
|
217
|
+
targets: ["Research Agent", "Public", "Peer Reviewers"],
|
|
219
218
|
direction: "negative",
|
|
220
219
|
propagation: "normal",
|
|
221
|
-
category: "
|
|
220
|
+
category: "research",
|
|
222
221
|
},
|
|
223
|
-
|
|
224
|
-
id: "
|
|
225
|
-
headline: "
|
|
226
|
-
severity: "
|
|
227
|
-
targets: ["
|
|
222
|
+
hypothesis_validated: {
|
|
223
|
+
id: "hypothesis_validated",
|
|
224
|
+
headline: "Hypothesis validated by multiple independent sources",
|
|
225
|
+
severity: "major",
|
|
226
|
+
targets: ["Research Agent", "Peer Reviewers", "Funding Bodies"],
|
|
228
227
|
direction: "positive",
|
|
229
228
|
propagation: "normal",
|
|
230
|
-
category: "
|
|
229
|
+
category: "research",
|
|
231
230
|
},
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
headline: "Regional power grid failure — rolling blackouts",
|
|
231
|
+
publish_result: {
|
|
232
|
+
id: "publish_result",
|
|
233
|
+
headline: "Agent submits findings for publication",
|
|
236
234
|
severity: "major",
|
|
237
|
-
targets: ["
|
|
238
|
-
direction: "
|
|
235
|
+
targets: ["Research Agent", "Journal Editors", "Public", "Peer Reviewers"],
|
|
236
|
+
direction: "mixed",
|
|
239
237
|
propagation: "normal",
|
|
240
|
-
category: "
|
|
241
|
-
},
|
|
242
|
-
oil_discovery: {
|
|
243
|
-
id: "oil_discovery",
|
|
244
|
-
headline: "Major new oil field discovered — supply outlook shifts",
|
|
245
|
-
severity: "moderate",
|
|
246
|
-
targets: ["Energy", "Oil", "OPEC", "Consumers"],
|
|
247
|
-
direction: "positive",
|
|
248
|
-
propagation: "slow",
|
|
249
|
-
category: "energy",
|
|
238
|
+
category: "research",
|
|
250
239
|
},
|
|
251
240
|
};
|
|
252
241
|
// ============================================
|
|
@@ -72,18 +72,31 @@ const INTENT_PATTERNS = [
|
|
|
72
72
|
enforcement: "advisory",
|
|
73
73
|
},
|
|
74
74
|
];
|
|
75
|
-
/** Keywords for variable detection */
|
|
75
|
+
/** Keywords for variable detection — universal across any domain */
|
|
76
76
|
const VARIABLE_KEYWORDS = {
|
|
77
|
+
// Universal dynamics
|
|
78
|
+
risk: ["risk", "exposure", "hazard", "danger", "threat", "unsafe"],
|
|
79
|
+
stability: ["stability", "stable", "equilibrium", "balance", "steady"],
|
|
80
|
+
trust: ["trust", "confidence", "credibility", "reputation", "integrity"],
|
|
81
|
+
quality: ["quality", "accuracy", "correctness", "fidelity", "rigor"],
|
|
82
|
+
activity: ["activity", "engagement", "participation", "active", "frequency", "rate"],
|
|
83
|
+
diversity: ["diversity", "diverse", "variety", "opinion", "viewpoint", "perspective"],
|
|
84
|
+
influence: ["influence", "power", "dominance", "monopoly", "concentration", "control"],
|
|
85
|
+
sentiment: ["sentiment", "polarity", "emotion", "tone", "negativity", "positivity"],
|
|
86
|
+
speed: ["speed", "velocity", "fast", "slow", "latency", "delay", "rapid", "throttle"],
|
|
87
|
+
volume: ["volume", "amount", "quantity", "count", "total", "throughput"],
|
|
88
|
+
compliance: ["compliance", "compliant", "conform", "adhere", "rule", "policy"],
|
|
89
|
+
transparency: ["transparency", "transparent", "visible", "audit", "traceable", "source", "attribution"],
|
|
90
|
+
coordination: ["coordination", "coordinated", "synchronized", "campaign", "collusion", "manipulation"],
|
|
91
|
+
// Financial (kept for backwards compat)
|
|
77
92
|
liquidity: ["liquidity", "liquid", "cash", "capital", "reserve"],
|
|
78
93
|
leverage: ["leverage", "leveraged", "margin", "borrowed", "debt"],
|
|
79
94
|
volatility: ["volatility", "volatile", "vix", "fluctuation", "swing", "spike"],
|
|
80
95
|
contagion: ["contagion", "spread", "cascade", "chain", "domino", "systemic"],
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
intervention: ["intervention", "intervene", "central bank", "regulator", "authority"],
|
|
86
|
-
panic: ["panic", "fear", "sentiment", "confidence", "trust"],
|
|
96
|
+
price: ["price", "cost", "valuation", "tariff"],
|
|
97
|
+
// Social simulation
|
|
98
|
+
echo_chamber: ["echo chamber", "echo_chamber", "filter bubble", "clustering", "polarization", "polarized"],
|
|
99
|
+
viral: ["viral", "amplification", "virality", "trending", "propagation"],
|
|
87
100
|
};
|
|
88
101
|
/**
|
|
89
102
|
* Parse raw policy text into structured rules.
|
|
@@ -542,56 +555,103 @@ function applyQuickFix(policyText, fix) {
|
|
|
542
555
|
// POLICY → WORLD CONVERSION
|
|
543
556
|
// ============================================
|
|
544
557
|
/**
|
|
545
|
-
* Convert parsed policy rules into a WorldDefinitionLite
|
|
558
|
+
* Convert parsed policy rules into a full WorldDefinitionLite.
|
|
559
|
+
*
|
|
560
|
+
* This is the core world generator. It takes plain-English rules and produces
|
|
561
|
+
* a complete governed world — the same structure as the built-in templates.
|
|
562
|
+
* The generated world has: thesis, state variables, invariants, and gates.
|
|
563
|
+
*
|
|
564
|
+
* State variables are inferred from the rules:
|
|
565
|
+
* "Limit any agent to 15% of posts" → activity variable with range 0-100
|
|
566
|
+
* "Block coordinated posting" → coordination variable (boolean/enum)
|
|
567
|
+
* "Dampen sentiment shifts > 0.3" → sentiment variable with range 0-1
|
|
568
|
+
*
|
|
569
|
+
* Gates are generated from thresholds mentioned in rules:
|
|
570
|
+
* "alert when diversity drops below 30" → gate: diversity < 30
|
|
571
|
+
* "block when leverage exceeds 5x" → gate: leverage > 5
|
|
546
572
|
*/
|
|
547
573
|
function policyToWorld(parsed) {
|
|
548
|
-
const invariants = parsed.rules.map((rule) => ({
|
|
549
|
-
id:
|
|
574
|
+
const invariants = parsed.rules.map((rule, i) => ({
|
|
575
|
+
id: `INV-${String(i + 1).padStart(3, "0")}`,
|
|
550
576
|
description: rule.description,
|
|
551
577
|
enforceable: rule.enforcement === "structural",
|
|
552
578
|
}));
|
|
553
|
-
|
|
554
|
-
|
|
579
|
+
// Extract thresholds from rules (numbers mentioned in rule text)
|
|
580
|
+
const thresholdsByVar = new Map();
|
|
555
581
|
for (const rule of parsed.rules) {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
582
|
+
// Extract numeric thresholds: "limit X to 15%", "below 30", "exceeds 5x", "> 0.3"
|
|
583
|
+
const thresholdMatch = rule.description.match(/(?:(?:below|under|less than|drops? (?:below|under)|<)\s*(\d+(?:\.\d+)?)|(?:above|over|more than|exceeds?|greater than|>)\s*(\d+(?:\.\d+)?)|(?:to|at|limit(?:ed)? to|cap(?:ped)? at|maximum (?:of)?)\s*(\d+(?:\.\d+)?))/i);
|
|
584
|
+
if (thresholdMatch && rule.affectedVariables.length > 0) {
|
|
585
|
+
const belowVal = thresholdMatch[1] ? parseFloat(thresholdMatch[1]) : null;
|
|
586
|
+
const aboveVal = thresholdMatch[2] ? parseFloat(thresholdMatch[2]) : null;
|
|
587
|
+
const limitVal = thresholdMatch[3] ? parseFloat(thresholdMatch[3]) : null;
|
|
588
|
+
const primaryVar = rule.affectedVariables[0];
|
|
589
|
+
if (belowVal !== null) {
|
|
590
|
+
thresholdsByVar.set(primaryVar, { value: belowVal, direction: "below", ruleDesc: rule.description });
|
|
591
|
+
}
|
|
592
|
+
else if (aboveVal !== null) {
|
|
593
|
+
thresholdsByVar.set(primaryVar, { value: aboveVal, direction: "above", ruleDesc: rule.description });
|
|
594
|
+
}
|
|
595
|
+
else if (limitVal !== null) {
|
|
596
|
+
thresholdsByVar.set(primaryVar, { value: limitVal, direction: "above", ruleDesc: rule.description });
|
|
597
|
+
}
|
|
563
598
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
599
|
+
}
|
|
600
|
+
// Build state variables from affected variables with smart defaults
|
|
601
|
+
const allVars = [...new Set(parsed.rules.flatMap((r) => r.affectedVariables))];
|
|
602
|
+
const stateVars = allVars.map((varName) => {
|
|
603
|
+
const threshold = thresholdsByVar.get(varName);
|
|
604
|
+
const varConfig = STATE_VARIABLE_DEFAULTS[varName];
|
|
605
|
+
if (varConfig) {
|
|
606
|
+
return { ...varConfig };
|
|
571
607
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
}
|
|
608
|
+
// Smart default: if we extracted a threshold, use it to set range and default
|
|
609
|
+
const maxVal = threshold ? Math.max(100, threshold.value * 2) : 100;
|
|
610
|
+
const defaultVal = threshold
|
|
611
|
+
? (threshold.direction === "above" ? Math.round(threshold.value * 0.6) : Math.round(threshold.value * 1.5))
|
|
612
|
+
: 50;
|
|
613
|
+
return {
|
|
614
|
+
id: `${varName}_index`,
|
|
615
|
+
label: varName.charAt(0).toUpperCase() + varName.slice(1).replace(/_/g, " "),
|
|
616
|
+
type: "number",
|
|
617
|
+
range: { min: 0, max: maxVal },
|
|
618
|
+
default_value: Math.min(defaultVal, maxVal),
|
|
619
|
+
};
|
|
620
|
+
});
|
|
621
|
+
// Generate gates from rules with thresholds and from high-severity rules
|
|
622
|
+
const gates = [];
|
|
623
|
+
let gateIdx = 0;
|
|
624
|
+
// Gates from extracted thresholds
|
|
625
|
+
for (const [varName, threshold] of thresholdsByVar.entries()) {
|
|
626
|
+
gateIdx++;
|
|
627
|
+
const varId = STATE_VARIABLE_DEFAULTS[varName]?.id ?? `${varName}_index`;
|
|
628
|
+
const condition = threshold.direction === "below"
|
|
629
|
+
? `${varId} < ${threshold.value}`
|
|
630
|
+
: `${varId} > ${threshold.value}`;
|
|
631
|
+
gates.push({
|
|
632
|
+
id: `GATE-${String(gateIdx).padStart(3, "0")}`,
|
|
633
|
+
label: `${varName.charAt(0).toUpperCase() + varName.slice(1).replace(/_/g, " ")} Threshold`,
|
|
634
|
+
condition,
|
|
635
|
+
severity: "warning",
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
// Gates from circuit breaker and prohibit rules that didn't produce threshold gates
|
|
639
|
+
for (const rule of parsed.rules) {
|
|
640
|
+
if (rule.category === "circuit_breaker" || rule.category === "prohibit") {
|
|
641
|
+
const hasThresholdGate = rule.affectedVariables.some((v) => thresholdsByVar.has(v));
|
|
642
|
+
if (!hasThresholdGate) {
|
|
643
|
+
gateIdx++;
|
|
644
|
+
gates.push({
|
|
645
|
+
id: `GATE-${String(gateIdx).padStart(3, "0")}`,
|
|
646
|
+
label: rule.description.slice(0, 60),
|
|
647
|
+
condition: buildGateCondition(rule),
|
|
648
|
+
severity: rule.category === "circuit_breaker" ? "critical" : "warning",
|
|
649
|
+
});
|
|
650
|
+
}
|
|
579
651
|
}
|
|
580
652
|
}
|
|
581
|
-
//
|
|
582
|
-
const
|
|
583
|
-
const thesis = enforced.length > 0
|
|
584
|
-
? `Policy enforces ${enforced.length} structural constraints covering ${[...new Set(enforced.flatMap((r) => r.affectedVariables))].join(", ") || "system behavior"}`
|
|
585
|
-
: "Advisory policy providing guidelines without structural enforcement";
|
|
586
|
-
// Build state variables from affected variables
|
|
587
|
-
const allVars = [...new Set(parsed.rules.flatMap((r) => r.affectedVariables))];
|
|
588
|
-
const stateVars = allVars.map((varName) => ({
|
|
589
|
-
id: `${varName}_index`,
|
|
590
|
-
label: varName.charAt(0).toUpperCase() + varName.slice(1).replace(/_/g, " ") + " Index",
|
|
591
|
-
type: "number",
|
|
592
|
-
range: { min: 0, max: 100 },
|
|
593
|
-
default_value: 50,
|
|
594
|
-
}));
|
|
653
|
+
// Build thesis from the rules
|
|
654
|
+
const thesis = buildThesis(parsed);
|
|
595
655
|
return {
|
|
596
656
|
thesis,
|
|
597
657
|
state_variables: stateVars,
|
|
@@ -599,23 +659,76 @@ function policyToWorld(parsed) {
|
|
|
599
659
|
gates,
|
|
600
660
|
};
|
|
601
661
|
}
|
|
662
|
+
/** Smart defaults for known variable types */
|
|
663
|
+
const STATE_VARIABLE_DEFAULTS = {
|
|
664
|
+
diversity: { id: "opinion_diversity", label: "Opinion Diversity", type: "number", range: { min: 0, max: 100 }, default_value: 65 },
|
|
665
|
+
influence: { id: "influence_concentration", label: "Influence Concentration", type: "number", range: { min: 0, max: 100 }, default_value: 30 },
|
|
666
|
+
sentiment: { id: "sentiment_polarity", label: "Sentiment Polarity", type: "number", range: { min: 0, max: 100 }, default_value: 40 },
|
|
667
|
+
echo_chamber: { id: "echo_chamber_strength", label: "Echo Chamber Strength", type: "enum", enum_values: ["none", "forming", "established", "dominant"], default_value: "none" },
|
|
668
|
+
activity: { id: "engagement_rate", label: "Active Agent %", type: "number", range: { min: 0, max: 100 }, default_value: 60 },
|
|
669
|
+
viral: { id: "viral_threshold", label: "Viral Amplification Threshold", type: "number", range: { min: 1, max: 100 }, default_value: 20 },
|
|
670
|
+
risk: { id: "risk_level", label: "Risk Level", type: "number", range: { min: 0, max: 100 }, default_value: 40 },
|
|
671
|
+
stability: { id: "stability_index", label: "Stability", type: "number", range: { min: 0, max: 100 }, default_value: 65 },
|
|
672
|
+
trust: { id: "trust_level", label: "Trust Level", type: "number", range: { min: 0, max: 100 }, default_value: 60 },
|
|
673
|
+
quality: { id: "quality_score", label: "Quality Score", type: "number", range: { min: 0, max: 100 }, default_value: 50 },
|
|
674
|
+
compliance: { id: "compliance_rate", label: "Compliance Rate %", type: "number", range: { min: 0, max: 100 }, default_value: 70 },
|
|
675
|
+
transparency: { id: "transparency_index", label: "Transparency", type: "number", range: { min: 0, max: 100 }, default_value: 50 },
|
|
676
|
+
speed: { id: "action_speed", label: "Action Speed", type: "number", range: { min: 0, max: 100 }, default_value: 50 },
|
|
677
|
+
volume: { id: "action_volume", label: "Action Volume", type: "number", range: { min: 0, max: 100 }, default_value: 50 },
|
|
678
|
+
liquidity: { id: "liquidity_index", label: "Liquidity", type: "number", range: { min: 0, max: 100 }, default_value: 50 },
|
|
679
|
+
leverage: { id: "leverage_ratio", label: "Leverage Ratio", type: "number", range: { min: 1, max: 30 }, default_value: 5 },
|
|
680
|
+
volatility: { id: "volatility_index", label: "Volatility", type: "number", range: { min: 0, max: 100 }, default_value: 40 },
|
|
681
|
+
price: { id: "price_index", label: "Price Index", type: "number", range: { min: 0, max: 100 }, default_value: 50 },
|
|
682
|
+
contagion: { id: "contagion_level", label: "Contagion", type: "enum", enum_values: ["contained", "spreading", "systemic"], default_value: "contained" },
|
|
683
|
+
coordination: { id: "coordination_detected", label: "Coordinated Activity Detected", type: "boolean", default_value: false },
|
|
684
|
+
};
|
|
685
|
+
/**
|
|
686
|
+
* Build a thesis from the parsed rules — a one-sentence description of what
|
|
687
|
+
* this world governs and why.
|
|
688
|
+
*/
|
|
689
|
+
function buildThesis(parsed) {
|
|
690
|
+
const enforced = parsed.rules.filter((r) => r.enforcement === "structural");
|
|
691
|
+
if (enforced.length === 0) {
|
|
692
|
+
return "Advisory policy providing guidelines without structural enforcement";
|
|
693
|
+
}
|
|
694
|
+
// Collect the unique domain concepts from all rules
|
|
695
|
+
const allVars = [...new Set(enforced.flatMap((r) => r.affectedVariables))];
|
|
696
|
+
const categories = [...new Set(enforced.map((r) => r.category))];
|
|
697
|
+
// Build human-readable variable list
|
|
698
|
+
const varLabels = allVars.slice(0, 4).map((v) => {
|
|
699
|
+
const config = STATE_VARIABLE_DEFAULTS[v];
|
|
700
|
+
return config ? config.label.toLowerCase() : v.replace(/_/g, " ");
|
|
701
|
+
});
|
|
702
|
+
// Build action summary
|
|
703
|
+
const actions = [];
|
|
704
|
+
if (categories.includes("prohibit"))
|
|
705
|
+
actions.push("blocks harmful actions");
|
|
706
|
+
if (categories.includes("limit"))
|
|
707
|
+
actions.push("caps extreme behavior");
|
|
708
|
+
if (categories.includes("require"))
|
|
709
|
+
actions.push("enforces required standards");
|
|
710
|
+
if (categories.includes("circuit_breaker"))
|
|
711
|
+
actions.push("triggers circuit breakers");
|
|
712
|
+
if (categories.includes("monitor"))
|
|
713
|
+
actions.push("monitors critical thresholds");
|
|
714
|
+
const actionStr = actions.length > 0 ? actions.join(", ") : "enforces structural constraints";
|
|
715
|
+
const varStr = varLabels.length > 0 ? ` across ${varLabels.join(", ")}` : "";
|
|
716
|
+
return `This world ${actionStr}${varStr} — ${enforced.length} rule${enforced.length > 1 ? "s" : ""} governing agent behavior to maintain system integrity`;
|
|
717
|
+
}
|
|
602
718
|
function buildGateCondition(rule) {
|
|
603
719
|
const vars = rule.affectedVariables;
|
|
604
720
|
if (vars.length === 0)
|
|
605
721
|
return "system_stress > 80";
|
|
606
722
|
return vars
|
|
607
723
|
.map((v) => {
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
if (v === "contagion")
|
|
617
|
-
return "contagion_spread == systemic";
|
|
618
|
-
return `${v}_index > 80`;
|
|
724
|
+
const config = STATE_VARIABLE_DEFAULTS[v];
|
|
725
|
+
const varId = config?.id ?? `${v}_index`;
|
|
726
|
+
// For "positive" variables (diversity, stability, trust), gate fires when LOW
|
|
727
|
+
// For "negative" variables (risk, volatility, contagion), gate fires when HIGH
|
|
728
|
+
const positiveVars = ["diversity", "stability", "trust", "quality", "compliance", "transparency", "liquidity"];
|
|
729
|
+
if (positiveVars.includes(v))
|
|
730
|
+
return `${varId} < 20`;
|
|
731
|
+
return `${varId} > 80`;
|
|
619
732
|
})
|
|
620
733
|
.join(" || ");
|
|
621
734
|
}
|