@neuroverseos/governance 0.3.0 → 0.3.3

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.
Files changed (126) hide show
  1. package/.well-known/ai-plugin.json +34 -9
  2. package/AGENTS.md +72 -24
  3. package/README.md +352 -237
  4. package/dist/adapters/autoresearch.cjs +1152 -3
  5. package/dist/adapters/autoresearch.d.cts +11 -3
  6. package/dist/adapters/autoresearch.d.ts +11 -3
  7. package/dist/adapters/autoresearch.js +9 -4
  8. package/dist/adapters/deep-agents.cjs +1528 -0
  9. package/dist/adapters/deep-agents.d.cts +181 -0
  10. package/dist/adapters/deep-agents.d.ts +181 -0
  11. package/dist/adapters/deep-agents.js +17 -0
  12. package/dist/adapters/express.cjs +171 -32
  13. package/dist/adapters/express.d.cts +1 -1
  14. package/dist/adapters/express.d.ts +1 -1
  15. package/dist/adapters/express.js +5 -5
  16. package/dist/adapters/index.cjs +564 -121
  17. package/dist/adapters/index.d.cts +3 -1
  18. package/dist/adapters/index.d.ts +3 -1
  19. package/dist/adapters/index.js +38 -16
  20. package/dist/adapters/langchain.cjs +217 -57
  21. package/dist/adapters/langchain.d.cts +5 -5
  22. package/dist/adapters/langchain.d.ts +5 -5
  23. package/dist/adapters/langchain.js +6 -5
  24. package/dist/adapters/openai.cjs +219 -59
  25. package/dist/adapters/openai.d.cts +5 -5
  26. package/dist/adapters/openai.d.ts +5 -5
  27. package/dist/adapters/openai.js +6 -5
  28. package/dist/adapters/openclaw.cjs +217 -57
  29. package/dist/adapters/openclaw.d.cts +6 -6
  30. package/dist/adapters/openclaw.d.ts +6 -6
  31. package/dist/adapters/openclaw.js +6 -5
  32. package/dist/add-ROOZLU62.js +314 -0
  33. package/dist/behavioral-MJO34S6Q.js +118 -0
  34. package/dist/{bootstrap-GXVDZNF7.js → bootstrap-CQRZVOXK.js} +6 -4
  35. package/dist/bootstrap-emitter-Q7UIJZ2O.js +7 -0
  36. package/dist/bootstrap-parser-EEF36XDU.js +7 -0
  37. package/dist/browser.global.js +941 -0
  38. package/dist/{build-P42YFKQV.js → build-QKOBBC23.js} +7 -5
  39. package/dist/{chunk-COT5XS4V.js → chunk-3WQLXYTP.js} +17 -35
  40. package/dist/{chunk-ER62HNGF.js → chunk-4FLICVVA.js} +17 -37
  41. package/dist/chunk-5TPFNWRU.js +215 -0
  42. package/dist/chunk-5U2MQO5P.js +57 -0
  43. package/dist/{chunk-NF5POFCI.js → chunk-6S5CFQXY.js} +6 -4
  44. package/dist/{chunk-QPASI2BR.js → chunk-A7GKPPU7.js} +49 -10
  45. package/dist/{chunk-OGL7QXZS.js → chunk-B6OXJLJ5.js} +17 -3
  46. package/dist/{chunk-2PQU3VAN.js → chunk-BNKJPUPQ.js} +17 -35
  47. package/dist/chunk-BQZMOEML.js +43 -0
  48. package/dist/chunk-CNSO6XW5.js +207 -0
  49. package/dist/{chunk-JZPQGIKR.js → chunk-CTZHONLA.js} +65 -9
  50. package/dist/chunk-D2UCV5AK.js +326 -0
  51. package/dist/{chunk-XPDMYECO.js → chunk-EMQDLDAF.js} +1 -185
  52. package/dist/{chunk-GR6DGCZ2.js → chunk-F66BVUYB.js} +3 -3
  53. package/dist/{chunk-2NICNKOM.js → chunk-G7DJ6VOD.js} +5 -4
  54. package/dist/{chunk-4A7LISES.js → chunk-IS4WUH6Y.js} +45 -6
  55. package/dist/{chunk-MWDQ4MJB.js → chunk-MH7BT4VH.js} +5 -1
  56. package/dist/chunk-O5ABKEA7.js +304 -0
  57. package/dist/chunk-PVTQQS3Y.js +186 -0
  58. package/dist/{chunk-4QXB6PEO.js → chunk-QLPTHTVB.js} +37 -16
  59. package/dist/chunk-QWGCMQQD.js +16 -0
  60. package/dist/{chunk-T5EUJQE5.js → chunk-QXBFT7NI.js} +31 -2
  61. package/dist/{chunk-PDOZHZWL.js → chunk-TG6SEF24.js} +25 -4
  62. package/dist/chunk-U6U7EJZL.js +177 -0
  63. package/dist/{chunk-4JRYGIO7.js → chunk-W7LLXRGY.js} +110 -7
  64. package/dist/{chunk-BUWWN2NX.js → chunk-ZJTDUCC2.js} +9 -7
  65. package/dist/{chunk-FYS2CBUW.js → chunk-ZWI3NIXK.js} +10 -0
  66. package/dist/cli/neuroverse.cjs +5091 -2348
  67. package/dist/cli/neuroverse.js +52 -21
  68. package/dist/cli/plan.cjs +881 -41
  69. package/dist/cli/plan.js +7 -15
  70. package/dist/cli/run.cjs +289 -34
  71. package/dist/cli/run.js +4 -4
  72. package/dist/{configure-ai-TK67ZWZL.js → configure-ai-6TZ3MCSI.js} +1 -1
  73. package/dist/decision-flow-M63D47LO.js +61 -0
  74. package/dist/demo-G43RLCPK.js +469 -0
  75. package/dist/{derive-TLIV4OOU.js → derive-FJZVIPUZ.js} +5 -4
  76. package/dist/{doctor-XPDLEYXN.js → doctor-6BC6X2VO.js} +6 -4
  77. package/dist/equity-penalties-SG5IZQ7I.js +244 -0
  78. package/dist/{explain-IDCRWMPX.js → explain-RHBU2GBR.js} +6 -25
  79. package/dist/{guard-RV65TT4L.js → guard-AJCCGZMF.js} +8 -12
  80. package/dist/{guard-contract-WZx__PmU.d.cts → guard-contract-DqFcTScd.d.cts} +117 -5
  81. package/dist/{guard-contract-WZx__PmU.d.ts → guard-contract-DqFcTScd.d.ts} +117 -5
  82. package/dist/{guard-engine-JLTUARGU.js → guard-engine-PNR6MHCM.js} +3 -3
  83. package/dist/{impact-XPECYRLH.js → impact-3XVDSCBU.js} +5 -5
  84. package/dist/{improve-GPUBKTEA.js → improve-TQP4ECSY.js} +7 -26
  85. package/dist/index.cjs +5597 -4279
  86. package/dist/index.d.cts +597 -18
  87. package/dist/index.d.ts +597 -18
  88. package/dist/index.js +134 -41
  89. package/dist/{infer-world-7GVZWFX4.js → infer-world-IFXCACJ5.js} +1 -1
  90. package/dist/{init-PKPIYHYE.js → init-FYPV4SST.js} +1 -1
  91. package/dist/{init-world-VWMQZQC7.js → init-world-TI7ARHBT.js} +1 -1
  92. package/dist/mcp-server-5Y3ZM7TV.js +13 -0
  93. package/dist/{model-adapter-BB7G4MFI.js → model-adapter-VXEKB4LS.js} +1 -1
  94. package/dist/{playground-E664U4T6.js → playground-VZBNPPBO.js} +29 -19
  95. package/dist/{redteam-Z7WREJ44.js → redteam-MZPZD3EF.js} +4 -4
  96. package/dist/session-JYOARW54.js +15 -0
  97. package/dist/shared-7RLUHNMU.js +16 -0
  98. package/dist/shared-B8dvUUD8.d.cts +60 -0
  99. package/dist/shared-Dr5Wiay8.d.ts +60 -0
  100. package/dist/{simulate-VDOYQFRO.js → simulate-LJXYBC6M.js} +8 -33
  101. package/dist/{test-OGXJK4QU.js → test-BOOR4A5F.js} +4 -4
  102. package/dist/{trace-JVF67VR3.js → trace-PKV4KX56.js} +4 -4
  103. package/dist/{validate-LLBWVPGV.js → validate-RALX7CZS.js} +2 -2
  104. package/dist/{validate-engine-UIABSIHD.js → validate-engine-7ZXFVGF2.js} +1 -1
  105. package/dist/viz/assets/index-B8SaeJZZ.js +23 -0
  106. package/dist/viz/index.html +23 -0
  107. package/dist/{world-LAXO6DOX.js → world-BIP4GZBZ.js} +9 -11
  108. package/dist/world-loader-Y6HMQH2D.js +13 -0
  109. package/dist/worlds/coding-agent.nv-world.md +211 -0
  110. package/dist/worlds/research-agent.nv-world.md +169 -0
  111. package/dist/worlds/social-media.nv-world.md +198 -0
  112. package/dist/worlds/trading-agent.nv-world.md +218 -0
  113. package/examples/social-media-sim/bridge.py +209 -0
  114. package/examples/social-media-sim/simulation.py +927 -0
  115. package/package.json +30 -4
  116. package/policies/content-moderation-rules.txt +8 -0
  117. package/policies/marketing-rules.txt +8 -0
  118. package/policies/science-research-rules.txt +11 -0
  119. package/policies/social-media-rules.txt +7 -0
  120. package/policies/strict-rules.txt +8 -0
  121. package/policies/trading-rules.txt +8 -0
  122. package/simulate.html +1567 -0
  123. package/dist/chunk-YZFATT7X.js +0 -9
  124. package/dist/mcp-server-FPVSU32Z.js +0 -13
  125. package/dist/session-EKTRSR7C.js +0 -14
  126. package/dist/world-loader-HMPTOEA2.js +0 -9
package/simulate.html ADDED
@@ -0,0 +1,1567 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>NeuroVerse Simulation Engine</title>
7
+ <style>
8
+ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;700&display=swap');
9
+
10
+ * { margin: 0; padding: 0; box-sizing: border-box; }
11
+
12
+ :root {
13
+ --green: #00ff41;
14
+ --green-dim: #00cc33;
15
+ --green-dark: #009922;
16
+ --green-glow: #00ff4180;
17
+ --bg: #0a0a0a;
18
+ --bg-panel: #0d1117;
19
+ --bg-card: #111820;
20
+ --border: #1a2332;
21
+ --text: #c9d1d9;
22
+ --text-dim: #6e7681;
23
+ --red: #ff4444;
24
+ --red-glow: #ff444460;
25
+ --amber: #ffaa00;
26
+ --cyan: #00d4ff;
27
+ }
28
+
29
+ body {
30
+ background: var(--bg);
31
+ color: var(--text);
32
+ font-family: 'JetBrains Mono', 'Courier New', monospace;
33
+ min-height: 100vh;
34
+ overflow-x: hidden;
35
+ }
36
+
37
+ /* ─── Matrix Rain Canvas ─── */
38
+ #matrix-canvas {
39
+ position: fixed;
40
+ top: 0; left: 0;
41
+ width: 100%; height: 100%;
42
+ z-index: 0;
43
+ opacity: 0.06;
44
+ pointer-events: none;
45
+ }
46
+
47
+ /* ─── Main Layout ─── */
48
+ .app {
49
+ position: relative;
50
+ z-index: 1;
51
+ max-width: 1400px;
52
+ margin: 0 auto;
53
+ padding: 20px;
54
+ }
55
+
56
+ /* ─── Header ─── */
57
+ .header {
58
+ text-align: center;
59
+ padding: 30px 0 20px;
60
+ border-bottom: 1px solid var(--border);
61
+ margin-bottom: 24px;
62
+ }
63
+
64
+ .header h1 {
65
+ font-size: 14px;
66
+ font-weight: 400;
67
+ letter-spacing: 8px;
68
+ text-transform: uppercase;
69
+ color: var(--green);
70
+ text-shadow: 0 0 20px var(--green-glow);
71
+ margin-bottom: 6px;
72
+ }
73
+
74
+ .header .subtitle {
75
+ font-size: 11px;
76
+ color: var(--text-dim);
77
+ letter-spacing: 3px;
78
+ }
79
+
80
+ .header .powered {
81
+ font-size: 10px;
82
+ color: var(--text-dim);
83
+ margin-top: 8px;
84
+ opacity: 0.6;
85
+ }
86
+
87
+ /* ─── Grid ─── */
88
+ .grid {
89
+ display: grid;
90
+ grid-template-columns: 320px 1fr 300px;
91
+ gap: 16px;
92
+ min-height: 600px;
93
+ }
94
+
95
+ @media (max-width: 1100px) {
96
+ .grid { grid-template-columns: 1fr; }
97
+ }
98
+
99
+ /* ─── Panels ─── */
100
+ .panel {
101
+ background: var(--bg-panel);
102
+ border: 1px solid var(--border);
103
+ border-radius: 4px;
104
+ overflow: hidden;
105
+ }
106
+
107
+ .panel-header {
108
+ padding: 12px 16px;
109
+ border-bottom: 1px solid var(--border);
110
+ font-size: 10px;
111
+ letter-spacing: 3px;
112
+ text-transform: uppercase;
113
+ color: var(--green-dim);
114
+ display: flex;
115
+ align-items: center;
116
+ gap: 8px;
117
+ }
118
+
119
+ .panel-header .dot {
120
+ width: 6px; height: 6px;
121
+ border-radius: 50%;
122
+ background: var(--green);
123
+ box-shadow: 0 0 6px var(--green-glow);
124
+ }
125
+
126
+ .panel-body {
127
+ padding: 16px;
128
+ }
129
+
130
+ /* ─── World Selector ─── */
131
+ .world-tabs {
132
+ display: flex;
133
+ flex-direction: column;
134
+ gap: 4px;
135
+ margin-bottom: 16px;
136
+ }
137
+
138
+ .world-tab {
139
+ padding: 10px 12px;
140
+ background: var(--bg-card);
141
+ border: 1px solid var(--border);
142
+ border-radius: 3px;
143
+ color: var(--text-dim);
144
+ font-size: 12px;
145
+ font-family: inherit;
146
+ cursor: pointer;
147
+ transition: all 0.15s;
148
+ text-align: left;
149
+ }
150
+
151
+ .world-tab:hover {
152
+ border-color: var(--green-dark);
153
+ color: var(--text);
154
+ }
155
+
156
+ .world-tab.active {
157
+ border-color: var(--green);
158
+ color: var(--green);
159
+ background: #00ff4108;
160
+ box-shadow: 0 0 10px #00ff4110;
161
+ }
162
+
163
+ .world-tab .tab-name {
164
+ display: block;
165
+ font-weight: 500;
166
+ }
167
+
168
+ .world-tab .tab-desc {
169
+ display: block;
170
+ font-size: 10px;
171
+ margin-top: 2px;
172
+ opacity: 0.6;
173
+ }
174
+
175
+ .custom-toggle {
176
+ margin-top: 8px;
177
+ padding: 8px 12px;
178
+ background: transparent;
179
+ border: 1px dashed var(--border);
180
+ border-radius: 3px;
181
+ color: var(--text-dim);
182
+ font-size: 11px;
183
+ font-family: inherit;
184
+ cursor: pointer;
185
+ width: 100%;
186
+ text-align: left;
187
+ }
188
+
189
+ .custom-toggle:hover { border-color: var(--green-dark); color: var(--text); }
190
+
191
+ .custom-textarea {
192
+ width: 100%;
193
+ height: 200px;
194
+ background: var(--bg);
195
+ border: 1px solid var(--border);
196
+ border-radius: 3px;
197
+ color: var(--green-dim);
198
+ font-family: inherit;
199
+ font-size: 11px;
200
+ padding: 10px;
201
+ resize: vertical;
202
+ margin-top: 8px;
203
+ display: none;
204
+ }
205
+
206
+ .custom-textarea:focus { outline: none; border-color: var(--green-dark); }
207
+ .custom-textarea.visible { display: block; }
208
+
209
+ /* ─── State Sliders ─── */
210
+ .state-section {
211
+ margin-top: 16px;
212
+ padding-top: 16px;
213
+ border-top: 1px solid var(--border);
214
+ }
215
+
216
+ .state-label-row {
217
+ display: flex;
218
+ justify-content: space-between;
219
+ align-items: center;
220
+ margin-bottom: 4px;
221
+ }
222
+
223
+ .state-label {
224
+ font-size: 11px;
225
+ color: var(--text-dim);
226
+ }
227
+
228
+ .state-value {
229
+ font-size: 12px;
230
+ color: var(--green);
231
+ font-weight: 500;
232
+ min-width: 40px;
233
+ text-align: right;
234
+ }
235
+
236
+ .slider-group {
237
+ margin-bottom: 14px;
238
+ }
239
+
240
+ input[type="range"] {
241
+ -webkit-appearance: none;
242
+ width: 100%;
243
+ height: 4px;
244
+ background: var(--border);
245
+ border-radius: 2px;
246
+ outline: none;
247
+ cursor: pointer;
248
+ }
249
+
250
+ input[type="range"]::-webkit-slider-thumb {
251
+ -webkit-appearance: none;
252
+ width: 14px; height: 14px;
253
+ border-radius: 50%;
254
+ background: var(--green);
255
+ box-shadow: 0 0 8px var(--green-glow);
256
+ cursor: pointer;
257
+ }
258
+
259
+ input[type="range"]::-moz-range-thumb {
260
+ width: 14px; height: 14px;
261
+ border-radius: 50%;
262
+ background: var(--green);
263
+ box-shadow: 0 0 8px var(--green-glow);
264
+ border: none;
265
+ cursor: pointer;
266
+ }
267
+
268
+ /* ─── Simulate Button ─── */
269
+ .simulate-btn {
270
+ width: 100%;
271
+ padding: 14px;
272
+ background: transparent;
273
+ border: 1px solid var(--green);
274
+ border-radius: 3px;
275
+ color: var(--green);
276
+ font-family: inherit;
277
+ font-size: 12px;
278
+ letter-spacing: 4px;
279
+ text-transform: uppercase;
280
+ cursor: pointer;
281
+ transition: all 0.2s;
282
+ margin-top: 16px;
283
+ }
284
+
285
+ .simulate-btn:hover {
286
+ background: #00ff4115;
287
+ box-shadow: 0 0 20px var(--green-glow);
288
+ }
289
+
290
+ .simulate-btn:active {
291
+ transform: scale(0.98);
292
+ }
293
+
294
+ .simulate-btn.running {
295
+ animation: pulse-border 1s infinite;
296
+ pointer-events: none;
297
+ }
298
+
299
+ @keyframes pulse-border {
300
+ 0%, 100% { box-shadow: 0 0 5px var(--green-glow); }
301
+ 50% { box-shadow: 0 0 25px var(--green-glow); }
302
+ }
303
+
304
+ /* ─── Simulation Output ─── */
305
+ .sim-output {
306
+ min-height: 500px;
307
+ }
308
+
309
+ .sim-placeholder {
310
+ display: flex;
311
+ align-items: center;
312
+ justify-content: center;
313
+ min-height: 400px;
314
+ color: var(--text-dim);
315
+ font-size: 11px;
316
+ letter-spacing: 2px;
317
+ text-align: center;
318
+ flex-direction: column;
319
+ gap: 12px;
320
+ }
321
+
322
+ .sim-placeholder .cursor {
323
+ display: inline-block;
324
+ width: 8px;
325
+ height: 16px;
326
+ background: var(--green);
327
+ animation: blink 1s infinite;
328
+ }
329
+
330
+ @keyframes blink {
331
+ 0%, 50% { opacity: 1; }
332
+ 51%, 100% { opacity: 0; }
333
+ }
334
+
335
+ /* ─── Step Cards ─── */
336
+ .step-card {
337
+ background: var(--bg-card);
338
+ border: 1px solid var(--border);
339
+ border-radius: 3px;
340
+ margin-bottom: 8px;
341
+ overflow: hidden;
342
+ opacity: 0;
343
+ transform: translateY(10px);
344
+ transition: all 0.3s ease;
345
+ }
346
+
347
+ .step-card.visible {
348
+ opacity: 1;
349
+ transform: translateY(0);
350
+ }
351
+
352
+ .step-header {
353
+ padding: 10px 14px;
354
+ display: flex;
355
+ justify-content: space-between;
356
+ align-items: center;
357
+ border-bottom: 1px solid var(--border);
358
+ font-size: 11px;
359
+ }
360
+
361
+ .step-number {
362
+ color: var(--green);
363
+ font-weight: 500;
364
+ letter-spacing: 2px;
365
+ }
366
+
367
+ .step-viability {
368
+ font-size: 10px;
369
+ letter-spacing: 1px;
370
+ padding: 2px 8px;
371
+ border-radius: 2px;
372
+ }
373
+
374
+ .step-viability.THRIVING,
375
+ .step-viability.TRUSTED { background: #00ff4120; color: var(--green); }
376
+ .step-viability.STABLE,
377
+ .step-viability.PRODUCTIVE { background: #00ff4115; color: var(--green-dim); }
378
+ .step-viability.COMPRESSED,
379
+ .step-viability.CAUTIOUS { background: #ffaa0020; color: var(--amber); }
380
+ .step-viability.CRITICAL,
381
+ .step-viability.RESTRICTED,
382
+ .step-viability.AT_RISK { background: #ff444420; color: var(--red); }
383
+ .step-viability.MODEL_COLLAPSES,
384
+ .step-viability.TERMINATED,
385
+ .step-viability.HALTED,
386
+ .step-viability.UNRELIABLE { background: #ff444430; color: var(--red); border: 1px solid var(--red); }
387
+
388
+ .step-rules {
389
+ padding: 8px 14px;
390
+ }
391
+
392
+ .rule-row {
393
+ display: flex;
394
+ align-items: center;
395
+ gap: 8px;
396
+ padding: 4px 0;
397
+ font-size: 11px;
398
+ }
399
+
400
+ .rule-icon {
401
+ width: 16px;
402
+ text-align: center;
403
+ flex-shrink: 0;
404
+ }
405
+
406
+ .rule-icon.fired { color: var(--amber); }
407
+ .rule-icon.pass { color: var(--green-dark); opacity: 0.4; }
408
+ .rule-icon.excluded { color: var(--text-dim); opacity: 0.3; }
409
+
410
+ .rule-label {
411
+ flex: 1;
412
+ color: var(--text-dim);
413
+ }
414
+
415
+ .rule-label.fired { color: var(--text); }
416
+
417
+ .rule-effect {
418
+ font-size: 10px;
419
+ color: var(--amber);
420
+ }
421
+
422
+ .rule-effect.advantage { color: var(--green); }
423
+ .rule-effect.structural { color: var(--red); }
424
+
425
+ .step-state {
426
+ padding: 8px 14px;
427
+ border-top: 1px solid var(--border);
428
+ display: flex;
429
+ flex-wrap: wrap;
430
+ gap: 12px;
431
+ font-size: 10px;
432
+ color: var(--text-dim);
433
+ }
434
+
435
+ .state-chip {
436
+ display: flex;
437
+ align-items: center;
438
+ gap: 4px;
439
+ }
440
+
441
+ .state-chip .val { color: var(--green-dim); font-weight: 500; }
442
+ .state-chip .val.changed { color: var(--amber); }
443
+
444
+ /* ─── Verdict Panel ─── */
445
+ .verdict-section {
446
+ text-align: center;
447
+ }
448
+
449
+ .viability-display {
450
+ margin: 20px 0;
451
+ }
452
+
453
+ .viability-ring {
454
+ width: 160px;
455
+ height: 160px;
456
+ margin: 0 auto 16px;
457
+ position: relative;
458
+ }
459
+
460
+ .viability-ring svg {
461
+ transform: rotate(-90deg);
462
+ width: 160px;
463
+ height: 160px;
464
+ }
465
+
466
+ .viability-ring .bg-ring {
467
+ fill: none;
468
+ stroke: var(--border);
469
+ stroke-width: 6;
470
+ }
471
+
472
+ .viability-ring .fg-ring {
473
+ fill: none;
474
+ stroke: var(--green);
475
+ stroke-width: 6;
476
+ stroke-linecap: round;
477
+ stroke-dasharray: 440;
478
+ stroke-dashoffset: 440;
479
+ transition: stroke-dashoffset 1.5s ease, stroke 0.5s;
480
+ filter: drop-shadow(0 0 6px var(--green-glow));
481
+ }
482
+
483
+ .viability-ring .value-text {
484
+ position: absolute;
485
+ top: 50%;
486
+ left: 50%;
487
+ transform: translate(-50%, -50%);
488
+ font-size: 32px;
489
+ font-weight: 700;
490
+ color: var(--green);
491
+ text-shadow: 0 0 20px var(--green-glow);
492
+ }
493
+
494
+ .gate-badge {
495
+ display: inline-block;
496
+ padding: 8px 24px;
497
+ border-radius: 3px;
498
+ font-size: 12px;
499
+ letter-spacing: 4px;
500
+ text-transform: uppercase;
501
+ font-weight: 500;
502
+ opacity: 0;
503
+ transition: opacity 0.5s;
504
+ }
505
+
506
+ .gate-badge.visible { opacity: 1; }
507
+
508
+ /* ─── Stats ─── */
509
+ .stats-grid {
510
+ display: grid;
511
+ grid-template-columns: 1fr 1fr;
512
+ gap: 8px;
513
+ margin-top: 24px;
514
+ text-align: left;
515
+ }
516
+
517
+ .stat-card {
518
+ background: var(--bg-card);
519
+ border: 1px solid var(--border);
520
+ border-radius: 3px;
521
+ padding: 12px;
522
+ }
523
+
524
+ .stat-label {
525
+ font-size: 9px;
526
+ color: var(--text-dim);
527
+ letter-spacing: 1px;
528
+ text-transform: uppercase;
529
+ margin-bottom: 4px;
530
+ }
531
+
532
+ .stat-value {
533
+ font-size: 18px;
534
+ font-weight: 700;
535
+ color: var(--green);
536
+ }
537
+
538
+ .stat-value.warning { color: var(--amber); }
539
+ .stat-value.danger { color: var(--red); }
540
+
541
+ /* ─── Collapse Banner ─── */
542
+ .collapse-banner {
543
+ background: #ff444415;
544
+ border: 1px solid #ff444440;
545
+ border-radius: 3px;
546
+ padding: 16px;
547
+ margin-top: 16px;
548
+ text-align: center;
549
+ display: none;
550
+ }
551
+
552
+ .collapse-banner.visible { display: block; }
553
+
554
+ .collapse-banner .collapse-title {
555
+ color: var(--red);
556
+ font-size: 12px;
557
+ letter-spacing: 3px;
558
+ text-transform: uppercase;
559
+ font-weight: 700;
560
+ text-shadow: 0 0 10px var(--red-glow);
561
+ }
562
+
563
+ .collapse-banner .collapse-detail {
564
+ color: var(--text-dim);
565
+ font-size: 10px;
566
+ margin-top: 6px;
567
+ }
568
+
569
+ /* ─── Info text ─── */
570
+ .info-block {
571
+ margin-top: 16px;
572
+ padding: 12px;
573
+ background: var(--bg-card);
574
+ border: 1px solid var(--border);
575
+ border-radius: 3px;
576
+ font-size: 10px;
577
+ color: var(--text-dim);
578
+ line-height: 1.6;
579
+ }
580
+
581
+ .invariant-list {
582
+ margin-top: 12px;
583
+ list-style: none;
584
+ font-size: 10px;
585
+ }
586
+
587
+ .invariant-list li {
588
+ padding: 4px 0;
589
+ color: var(--text-dim);
590
+ display: flex;
591
+ align-items: flex-start;
592
+ gap: 6px;
593
+ }
594
+
595
+ .invariant-list li::before {
596
+ content: '>';
597
+ color: var(--green-dark);
598
+ flex-shrink: 0;
599
+ }
600
+
601
+ /* Profile selector */
602
+ .profile-select {
603
+ width: 100%;
604
+ padding: 8px 12px;
605
+ background: var(--bg-card);
606
+ border: 1px solid var(--border);
607
+ border-radius: 3px;
608
+ color: var(--text);
609
+ font-family: inherit;
610
+ font-size: 11px;
611
+ cursor: pointer;
612
+ margin-top: 8px;
613
+ }
614
+
615
+ .profile-select:focus { outline: none; border-color: var(--green-dark); }
616
+
617
+ .section-divider {
618
+ font-size: 10px;
619
+ color: var(--text-dim);
620
+ letter-spacing: 2px;
621
+ text-transform: uppercase;
622
+ margin: 12px 0 8px;
623
+ }
624
+
625
+ /* Steps slider */
626
+ .steps-row {
627
+ display: flex;
628
+ align-items: center;
629
+ gap: 10px;
630
+ margin-top: 12px;
631
+ }
632
+
633
+ .steps-row label {
634
+ font-size: 11px;
635
+ color: var(--text-dim);
636
+ white-space: nowrap;
637
+ }
638
+
639
+ .steps-row input { flex: 1; }
640
+
641
+ .steps-row .steps-val {
642
+ font-size: 12px;
643
+ color: var(--green);
644
+ font-weight: 500;
645
+ min-width: 20px;
646
+ text-align: right;
647
+ }
648
+
649
+ </style>
650
+ </head>
651
+ <body>
652
+
653
+ <canvas id="matrix-canvas"></canvas>
654
+
655
+ <div class="app">
656
+ <div class="header">
657
+ <h1>NeuroVerse Simulation Engine</h1>
658
+ <div class="subtitle">Deterministic World Governance</div>
659
+ <div class="powered">neuroverseos.com</div>
660
+ </div>
661
+
662
+ <div class="grid">
663
+ <!-- LEFT: World + State -->
664
+ <div class="panel">
665
+ <div class="panel-header"><span class="dot"></span> World</div>
666
+ <div class="panel-body">
667
+ <div class="world-tabs" id="world-tabs"></div>
668
+ <button class="custom-toggle" id="custom-toggle">+ paste custom .nv-world.md</button>
669
+ <textarea class="custom-textarea" id="custom-textarea" placeholder="Paste your .nv-world.md here..."></textarea>
670
+
671
+ <div class="section-divider">Profile</div>
672
+ <select class="profile-select" id="profile-select"></select>
673
+
674
+ <div class="state-section" id="state-section">
675
+ <div class="section-divider">State Overrides</div>
676
+ <div id="state-sliders"></div>
677
+ </div>
678
+
679
+ <div class="steps-row">
680
+ <label>Steps</label>
681
+ <input type="range" id="steps-slider" min="1" max="20" value="5">
682
+ <span class="steps-val" id="steps-val">5</span>
683
+ </div>
684
+
685
+ <button class="simulate-btn" id="simulate-btn">Simulate</button>
686
+ </div>
687
+ </div>
688
+
689
+ <!-- CENTER: Simulation -->
690
+ <div class="panel">
691
+ <div class="panel-header"><span class="dot"></span> Simulation</div>
692
+ <div class="panel-body sim-output" id="sim-output">
693
+ <div class="sim-placeholder">
694
+ <div>Select a world and configure state</div>
695
+ <div>then press <span style="color:var(--green)">SIMULATE</span></div>
696
+ <span class="cursor"></span>
697
+ </div>
698
+ </div>
699
+ </div>
700
+
701
+ <!-- RIGHT: Verdict -->
702
+ <div class="panel">
703
+ <div class="panel-header"><span class="dot"></span> Verdict</div>
704
+ <div class="panel-body verdict-section" id="verdict-section">
705
+ <div class="viability-display">
706
+ <div class="viability-ring">
707
+ <svg viewBox="0 0 160 160">
708
+ <circle class="bg-ring" cx="80" cy="80" r="70"/>
709
+ <circle class="fg-ring" id="viability-ring" cx="80" cy="80" r="70"/>
710
+ </svg>
711
+ <div class="value-text" id="viability-value">--</div>
712
+ </div>
713
+ <div class="gate-badge" id="gate-badge">AWAITING</div>
714
+ </div>
715
+
716
+ <div class="stats-grid" id="stats-grid"></div>
717
+
718
+ <div class="collapse-banner" id="collapse-banner">
719
+ <div class="collapse-title">Model Collapsed</div>
720
+ <div class="collapse-detail" id="collapse-detail"></div>
721
+ </div>
722
+
723
+ <ul class="invariant-list" id="invariant-list"></ul>
724
+
725
+ </div>
726
+ </div>
727
+ </div>
728
+ </div>
729
+
730
+ <script src="dist/browser.global.js"></script>
731
+ <script>
732
+ // ═══════════════════════════════════════════════════════════════════════════
733
+ // MATRIX RAIN
734
+ // ═══════════════════════════════════════════════════════════════════════════
735
+
736
+ const canvas = document.getElementById('matrix-canvas');
737
+ const ctx = canvas.getContext('2d');
738
+
739
+ function resizeCanvas() {
740
+ canvas.width = window.innerWidth;
741
+ canvas.height = window.innerHeight;
742
+ }
743
+ resizeCanvas();
744
+ window.addEventListener('resize', resizeCanvas);
745
+
746
+ const chars = 'NeuroVerse01アイウエオカキクケコサシスセソ>|/\\=+-*';
747
+ const fontSize = 14;
748
+ let columns = Math.floor(canvas.width / fontSize);
749
+ let drops = Array(columns).fill(1);
750
+
751
+ function drawMatrix() {
752
+ ctx.fillStyle = 'rgba(10, 10, 10, 0.05)';
753
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
754
+ ctx.fillStyle = '#00ff41';
755
+ ctx.font = fontSize + 'px monospace';
756
+
757
+ for (let i = 0; i < drops.length; i++) {
758
+ const text = chars[Math.floor(Math.random() * chars.length)];
759
+ ctx.fillText(text, i * fontSize, drops[i] * fontSize);
760
+ if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
761
+ drops[i] = 0;
762
+ }
763
+ drops[i]++;
764
+ }
765
+ }
766
+
767
+ setInterval(drawMatrix, 50);
768
+
769
+ // ═══════════════════════════════════════════════════════════════════════════
770
+ // ENGINE — loaded from dist/browser.global.js (NeuroVerse.simulateWorld,
771
+ // NeuroVerse.parseWorldMarkdown). One engine, one execution path, no drift.
772
+ // ═══════════════════════════════════════════════════════════════════════════
773
+
774
+ const { simulateWorld, parseWorldMarkdown } = NeuroVerse;
775
+
776
+ // ═══════════════════════════════════════════════════════════════════════════
777
+ // PRE-BUNDLED WORLDS
778
+ // ═══════════════════════════════════════════════════════════════════════════
779
+
780
+ const BUNDLED_WORLDS = {
781
+ 'coding-agent': {
782
+ name: 'Coding Agent',
783
+ desc: 'File writes, shell commands, git',
784
+ md: `---
785
+ world_id: coding-agent
786
+ name: Coding Agent Governance
787
+ version: 1.0.0
788
+ runtime_mode: COMPLIANCE
789
+ default_profile: standard
790
+ alternative_profile: strict
791
+ ---
792
+
793
+ # Thesis
794
+
795
+ Autonomous coding agents that can read files, write code, execute shell commands, and interact with version control must operate within explicit governance boundaries.
796
+
797
+ # Invariants
798
+
799
+ - \`no_destructive_shell_commands\` — Shell commands must not perform irreversible destructive operations (structural, immutable)
800
+ - \`no_secret_exfiltration\` — Agent must never read or transmit secrets or API keys (structural, immutable)
801
+ - \`no_system_file_modification\` — Agent must not modify files outside the project repository (structural, immutable)
802
+ - \`no_direct_production_push\` — Code must never be pushed directly to main without approval (structural, immutable)
803
+ - \`repository_boundary_enforced\` — All file operations scoped to project directory (structural, immutable)
804
+
805
+ # State
806
+
807
+ ## files_modified
808
+ - type: number
809
+ - min: 0
810
+ - max: 200
811
+ - step: 1
812
+ - default: 0
813
+ - label: Files Modified
814
+ - description: Total files modified in session
815
+
816
+ ## shell_commands_run
817
+ - type: number
818
+ - min: 0
819
+ - max: 500
820
+ - step: 1
821
+ - default: 0
822
+ - label: Shell Commands Run
823
+ - description: Total shell commands executed
824
+
825
+ ## destructive_attempts
826
+ - type: number
827
+ - min: 0
828
+ - max: 20
829
+ - step: 1
830
+ - default: 0
831
+ - label: Destructive Attempts
832
+ - description: Blocked destructive actions
833
+
834
+ ## tests_passing
835
+ - type: number
836
+ - min: 0
837
+ - max: 100
838
+ - step: 1
839
+ - default: 100
840
+ - label: Tests Passing
841
+ - description: Percentage of tests passing
842
+
843
+ ## files_outside_repo
844
+ - type: number
845
+ - min: 0
846
+ - max: 20
847
+ - step: 1
848
+ - default: 0
849
+ - label: Out-of-Scope Access
850
+ - description: File ops outside repository
851
+
852
+ ## secrets_detected
853
+ - type: number
854
+ - min: 0
855
+ - max: 20
856
+ - step: 1
857
+ - default: 0
858
+ - label: Secrets Detected
859
+ - description: Secrets found in agent output
860
+
861
+ # Assumptions
862
+
863
+ ## standard
864
+ - name: Standard Development
865
+ - description: Normal dev workflow. Safe commands allowed.
866
+ - shell_access: safe_commands
867
+ - file_access: project_only
868
+
869
+ ## strict
870
+ - name: Strict Governance
871
+ - description: All writes require approval. Shell limited to tests.
872
+ - shell_access: test_only
873
+ - file_access: read_mostly
874
+
875
+ # Rules
876
+
877
+ ## rule-001: Destructive Shell Command (structural)
878
+ Destructive shell commands must be blocked immediately.
879
+
880
+ When destructive_attempts > 0 [state]
881
+ Then agent_trust *= 0.00
882
+ Collapse: agent_trust < 0.05
883
+
884
+ > trigger: Agent attempted a destructive shell command.
885
+ > rule: Destructive commands are never acceptable.
886
+ > shift: Agent trust drops to zero. Session terminated.
887
+ > effect: Agent trust eliminated.
888
+
889
+ ## rule-002: Secret Exfiltration (structural)
890
+ Secret access must be blocked and flagged.
891
+
892
+ When secrets_detected > 0 [state]
893
+ Then agent_trust *= 0.10
894
+ Collapse: agent_trust < 0.05
895
+
896
+ > trigger: Agent accessed credentials or secrets.
897
+ > rule: Secrets require explicit authorization.
898
+ > shift: Agent trust drops severely.
899
+ > effect: Agent trust reduced to 10%.
900
+
901
+ ## rule-003: Boundary Violation (structural)
902
+ File operations outside the repository are forbidden.
903
+
904
+ When files_outside_repo > 0 [state]
905
+ Then agent_trust *= 0.20
906
+ Collapse: agent_trust < 0.05
907
+
908
+ > trigger: Agent accessed files outside project directory.
909
+ > rule: Agents operate within repository scope.
910
+ > shift: Agent trust degrades significantly.
911
+ > effect: Agent trust reduced to 20%.
912
+
913
+ ## rule-004: Test Regression (degradation)
914
+ Test failures indicate the agent is creating regressions.
915
+
916
+ When tests_passing < 70 [state] AND files_modified > 0 [state]
917
+ Then agent_trust *= 0.50
918
+
919
+ > trigger: Tests dropped below 70%.
920
+ > rule: Agents that break tests create liability.
921
+ > shift: Agent must fix tests before continuing.
922
+ > effect: Agent trust reduced to 50%.
923
+
924
+ ## rule-005: Excessive Modifications (degradation)
925
+ Too many modifications indicate scope creep.
926
+
927
+ When files_modified > 50 [state]
928
+ Then agent_trust *= 0.70
929
+
930
+ > trigger: More than 50 files modified.
931
+ > rule: Large changes are risky and hard to review.
932
+ > shift: Changes should be reviewed.
933
+ > effect: Agent trust reduced to 70%.
934
+
935
+ ## rule-006: Clean Session (advantage)
936
+ No destructive attempts and passing tests.
937
+
938
+ When destructive_attempts == 0 [state] AND tests_passing > 90 [state] AND files_modified > 0 [state]
939
+ Then agent_trust *= 1.20
940
+
941
+ > trigger: Zero violations with passing tests.
942
+ > rule: Trustworthy agents are rewarded.
943
+ > shift: Session is healthy.
944
+ > effect: Agent trust boosted 20%.
945
+
946
+ ## rule-007: Productive Session (advantage)
947
+ Focused changes with good test coverage.
948
+
949
+ When files_modified > 0 [state] AND files_modified < 30 [state] AND tests_passing > 85 [state]
950
+ Then agent_trust *= 1.10
951
+
952
+ > trigger: Focused changes with quality.
953
+ > rule: Ideal workflow.
954
+ > shift: Sustainable pace.
955
+ > effect: Agent trust boosted 10%.
956
+
957
+ # Gates
958
+
959
+ - TRUSTED: agent_trust >= 90
960
+ - PRODUCTIVE: agent_trust >= 60
961
+ - CAUTIOUS: agent_trust >= 35
962
+ - RESTRICTED: agent_trust > 10
963
+ - TERMINATED: agent_trust <= 10
964
+
965
+ # Outcomes
966
+
967
+ ## agent_trust
968
+ - type: number
969
+ - range: 0-100
970
+ - display: percentage
971
+ - label: Agent Trust
972
+ - primary: true
973
+ `
974
+ },
975
+ 'research-agent': {
976
+ name: 'Research Agent',
977
+ desc: 'Citations, API budgets, sources',
978
+ md: `---
979
+ world_id: research-agent
980
+ name: Research Agent Governance
981
+ version: 1.0.0
982
+ runtime_mode: COMPLIANCE
983
+ default_profile: conservative
984
+ alternative_profile: exploratory
985
+ ---
986
+
987
+ # Thesis
988
+
989
+ AI research agents must operate within governance boundaries ensuring rigor, attribution, and responsible resource usage.
990
+
991
+ # Invariants
992
+
993
+ - \`sources_must_be_cited\` — Every claim must be traceable to a source (structural, immutable)
994
+ - \`no_fabricated_citations\` — Agent must never invent sources (structural, immutable)
995
+ - \`api_rate_limits_respected\` — Must respect rate limits on external APIs (structural, immutable)
996
+ - \`no_unauthorized_publication\` — Findings require human review before publishing (prompt, immutable)
997
+
998
+ # State
999
+
1000
+ ## sources_consulted
1001
+ - type: number
1002
+ - min: 0
1003
+ - max: 100
1004
+ - step: 1
1005
+ - default: 0
1006
+ - label: Sources Consulted
1007
+ - description: Unique sources accessed
1008
+
1009
+ ## claims_made
1010
+ - type: number
1011
+ - min: 0
1012
+ - max: 100
1013
+ - step: 1
1014
+ - default: 0
1015
+ - label: Claims Made
1016
+ - description: Assertions produced
1017
+
1018
+ ## unsourced_claims
1019
+ - type: number
1020
+ - min: 0
1021
+ - max: 50
1022
+ - step: 1
1023
+ - default: 0
1024
+ - label: Unsourced Claims
1025
+ - description: Claims without source attribution
1026
+
1027
+ ## api_calls_made
1028
+ - type: number
1029
+ - min: 0
1030
+ - max: 10000
1031
+ - step: 10
1032
+ - default: 0
1033
+ - label: API Calls Made
1034
+ - description: External API calls made
1035
+
1036
+ ## api_budget
1037
+ - type: number
1038
+ - min: 100
1039
+ - max: 10000
1040
+ - step: 100
1041
+ - default: 5000
1042
+ - label: API Budget
1043
+ - description: Maximum API calls allowed
1044
+
1045
+ # Assumptions
1046
+
1047
+ ## conservative
1048
+ - name: Conservative Research
1049
+ - description: Multiple sources per claim. Strict API limits.
1050
+ - source_requirement: multiple_per_claim
1051
+ - api_strictness: hard_limit
1052
+
1053
+ ## exploratory
1054
+ - name: Exploratory Research
1055
+ - description: Broader exploration. Softer limits.
1056
+ - source_requirement: at_least_one
1057
+ - api_strictness: soft_warning
1058
+
1059
+ # Rules
1060
+
1061
+ ## rule-001: API Budget Exhausted (structural)
1062
+ No further external calls when budget exceeded.
1063
+
1064
+ When api_calls_made > api_budget [state]
1065
+ Then research_viability *= 0.00
1066
+ Collapse: research_viability < 0.05
1067
+
1068
+ > trigger: API budget exceeded.
1069
+ > rule: Budgets prevent abuse and cost overruns.
1070
+ > shift: Research halts for external calls.
1071
+ > effect: Viability set to zero.
1072
+
1073
+ ## rule-002: Unsourced Claims (degradation)
1074
+ Too many unsourced claims lack rigor.
1075
+
1076
+ When unsourced_claims > 3 [state] AND claims_made > 0 [state]
1077
+ Then research_viability *= 0.40
1078
+
1079
+ > trigger: More than 3 unsourced claims.
1080
+ > rule: Every assertion must be traceable.
1081
+ > shift: Viability drops. Agent must add citations.
1082
+ > effect: Viability reduced to 40%.
1083
+
1084
+ ## rule-003: Source Diversity (advantage)
1085
+ Many diverse sources produce quality research.
1086
+
1087
+ When sources_consulted > 10 [state] AND unsourced_claims == 0 [state]
1088
+ Then research_viability *= 1.25
1089
+
1090
+ > trigger: 10+ sources with zero unsourced claims.
1091
+ > rule: Diverse, cited research is gold standard.
1092
+ > shift: Viability improves.
1093
+ > effect: Viability boosted 25%.
1094
+
1095
+ ## rule-004: Shallow Research (degradation)
1096
+ Many claims from few sources.
1097
+
1098
+ When claims_made > 10 [state] AND sources_consulted < 3 [state]
1099
+ Then research_viability *= 0.50
1100
+
1101
+ > trigger: 10+ claims from fewer than 3 sources.
1102
+ > rule: Good research requires multiple perspectives.
1103
+ > shift: Agent should broaden sources.
1104
+ > effect: Viability reduced to 50%.
1105
+
1106
+ # Gates
1107
+
1108
+ - RIGOROUS: research_viability >= 85
1109
+ - SOLID: research_viability >= 60
1110
+ - DEVELOPING: research_viability >= 35
1111
+ - WEAK: research_viability > 10
1112
+ - UNRELIABLE: research_viability <= 10
1113
+
1114
+ # Outcomes
1115
+
1116
+ ## research_viability
1117
+ - type: number
1118
+ - range: 0-100
1119
+ - display: percentage
1120
+ - label: Research Viability
1121
+ - primary: true
1122
+ `
1123
+ },
1124
+ 'trading-agent': {
1125
+ name: 'Trading Agent',
1126
+ desc: 'Position limits, stop-losses, P&L',
1127
+ md: `---
1128
+ world_id: trading-agent
1129
+ name: Trading Agent Governance
1130
+ version: 1.0.0
1131
+ runtime_mode: COMPLIANCE
1132
+ default_profile: conservative
1133
+ alternative_profile: aggressive
1134
+ ---
1135
+
1136
+ # Thesis
1137
+
1138
+ Autonomous trading agents must operate within strict governance including position limits, stop-losses, and daily loss constraints.
1139
+
1140
+ # Invariants
1141
+
1142
+ - \`position_limits_enforced\` — No position may exceed maximum size (structural, immutable)
1143
+ - \`stop_loss_required\` — Every position must have a stop-loss (structural, immutable)
1144
+ - \`daily_loss_limit_enforced\` — Daily losses must not exceed the limit (structural, immutable)
1145
+ - \`audit_trail_maintained\` — Every order must be logged (structural, immutable)
1146
+
1147
+ # State
1148
+
1149
+ ## daily_pnl
1150
+ - type: number
1151
+ - min: -20000
1152
+ - max: 20000
1153
+ - step: 100
1154
+ - default: 0
1155
+ - label: Daily P&L
1156
+ - description: Realized + unrealized profit/loss
1157
+
1158
+ ## daily_loss_limit
1159
+ - type: number
1160
+ - min: 1000
1161
+ - max: 50000
1162
+ - step: 1000
1163
+ - default: 5000
1164
+ - label: Daily Loss Limit
1165
+ - description: Max allowable daily loss
1166
+
1167
+ ## open_positions
1168
+ - type: number
1169
+ - min: 0
1170
+ - max: 50
1171
+ - step: 1
1172
+ - default: 0
1173
+ - label: Open Positions
1174
+ - description: Current open positions
1175
+
1176
+ ## max_positions
1177
+ - type: number
1178
+ - min: 1
1179
+ - max: 50
1180
+ - step: 1
1181
+ - default: 10
1182
+ - label: Max Positions
1183
+ - description: Maximum concurrent positions
1184
+
1185
+ ## largest_position_pct
1186
+ - type: number
1187
+ - min: 0
1188
+ - max: 100
1189
+ - step: 1
1190
+ - default: 0
1191
+ - label: Largest Position %
1192
+ - description: Portfolio % in largest position
1193
+
1194
+ ## positions_without_stop
1195
+ - type: number
1196
+ - min: 0
1197
+ - max: 20
1198
+ - step: 1
1199
+ - default: 0
1200
+ - label: Without Stop-Loss
1201
+ - description: Positions with no stop-loss
1202
+
1203
+ # Assumptions
1204
+
1205
+ ## conservative
1206
+ - name: Conservative Trading
1207
+ - description: Small positions. Strict stops. Low loss tolerance.
1208
+ - max_position_pct: 5
1209
+ - daily_loss_tolerance: strict
1210
+
1211
+ ## aggressive
1212
+ - name: Aggressive Trading
1213
+ - description: Larger positions. Higher loss tolerance.
1214
+ - max_position_pct: 15
1215
+ - daily_loss_tolerance: moderate
1216
+
1217
+ # Rules
1218
+
1219
+ ## rule-001: Loss Limit Breached (structural)
1220
+ Trading must stop when daily loss limit exceeded.
1221
+
1222
+ When daily_pnl < 0 [state] AND daily_loss_limit > 0 [state]
1223
+ Then trading_viability *= 0.00
1224
+ Collapse: trading_viability < 0.05
1225
+
1226
+ > trigger: Daily loss exceeds limit.
1227
+ > rule: Loss limits are absolute constraints.
1228
+ > shift: Trading halts immediately.
1229
+ > effect: Viability set to zero.
1230
+
1231
+ ## rule-002: Concentration Risk (degradation)
1232
+ Single position too large.
1233
+
1234
+ When largest_position_pct > 20 [state]
1235
+ Then trading_viability *= 0.50
1236
+
1237
+ > trigger: Position exceeds 20% of portfolio.
1238
+ > rule: Concentration kills portfolios.
1239
+ > shift: Agent should reduce position.
1240
+ > effect: Viability reduced to 50%.
1241
+
1242
+ ## rule-003: Naked Positions (structural)
1243
+ Positions without stop-losses are forbidden.
1244
+
1245
+ When positions_without_stop > 0 [state]
1246
+ Then trading_viability *= 0.30
1247
+ Collapse: trading_viability < 0.05
1248
+
1249
+ > trigger: Positions have no stop-loss.
1250
+ > rule: Every position needs a defined exit.
1251
+ > shift: Viability drops severely.
1252
+ > effect: Viability reduced to 30%.
1253
+
1254
+ ## rule-004: Over-Trading (degradation)
1255
+ Too many open positions.
1256
+
1257
+ When open_positions > max_positions [state]
1258
+ Then trading_viability *= 0.60
1259
+
1260
+ > trigger: Positions exceed maximum.
1261
+ > rule: Limits prevent fragmentation.
1262
+ > shift: Close positions before opening new ones.
1263
+ > effect: Viability reduced to 60%.
1264
+
1265
+ ## rule-005: Disciplined Trading (advantage)
1266
+ Profitable with proper risk controls.
1267
+
1268
+ When daily_pnl > 0 [state] AND positions_without_stop == 0 [state] AND largest_position_pct < 15 [state]
1269
+ Then trading_viability *= 1.20
1270
+
1271
+ > trigger: Positive P&L with risk controls in place.
1272
+ > rule: Disciplined trading is rewarded.
1273
+ > shift: Agent can continue strategy.
1274
+ > effect: Viability boosted 20%.
1275
+
1276
+ ## rule-006: Good Diversification (advantage)
1277
+ Small, distributed positions with stops.
1278
+
1279
+ When open_positions > 3 [state] AND largest_position_pct < 10 [state] AND positions_without_stop == 0 [state]
1280
+ Then trading_viability *= 1.15
1281
+
1282
+ > trigger: Multiple small positions, all with stops.
1283
+ > rule: Textbook diversification.
1284
+ > shift: Portfolio well-structured.
1285
+ > effect: Viability boosted 15%.
1286
+
1287
+ # Gates
1288
+
1289
+ - OPTIMAL: trading_viability >= 90
1290
+ - HEALTHY: trading_viability >= 60
1291
+ - CAUTIOUS: trading_viability >= 35
1292
+ - AT_RISK: trading_viability > 10
1293
+ - HALTED: trading_viability <= 10
1294
+
1295
+ # Outcomes
1296
+
1297
+ ## trading_viability
1298
+ - type: number
1299
+ - range: 0-100
1300
+ - display: percentage
1301
+ - label: Trading Viability
1302
+ - primary: true
1303
+ `
1304
+ }
1305
+ };
1306
+
1307
+ // ═══════════════════════════════════════════════════════════════════════════
1308
+ // UI CONTROLLER
1309
+ // ═══════════════════════════════════════════════════════════════════════════
1310
+
1311
+ let currentWorld = null;
1312
+ let currentWorldDef = null;
1313
+ let customMode = false;
1314
+
1315
+ const worldTabsEl = document.getElementById('world-tabs');
1316
+ const customToggleEl = document.getElementById('custom-toggle');
1317
+ const customTextareaEl = document.getElementById('custom-textarea');
1318
+ const profileSelectEl = document.getElementById('profile-select');
1319
+ const stateSlidersEl = document.getElementById('state-sliders');
1320
+ const stepsSliderEl = document.getElementById('steps-slider');
1321
+ const stepsValEl = document.getElementById('steps-val');
1322
+ const simulateBtnEl = document.getElementById('simulate-btn');
1323
+ const simOutputEl = document.getElementById('sim-output');
1324
+ const viabilityRingEl = document.getElementById('viability-ring');
1325
+ const viabilityValueEl = document.getElementById('viability-value');
1326
+ const gateBadgeEl = document.getElementById('gate-badge');
1327
+ const statsGridEl = document.getElementById('stats-grid');
1328
+ const collapseBannerEl = document.getElementById('collapse-banner');
1329
+ const collapseDetailEl = document.getElementById('collapse-detail');
1330
+ const invariantListEl = document.getElementById('invariant-list');
1331
+
1332
+ // Build world tabs
1333
+ for (const [id, w] of Object.entries(BUNDLED_WORLDS)) {
1334
+ const btn = document.createElement('button');
1335
+ btn.className = 'world-tab';
1336
+ btn.dataset.world = id;
1337
+ btn.innerHTML = `<span class="tab-name">${w.name}</span><span class="tab-desc">${w.desc}</span>`;
1338
+ btn.onclick = () => selectWorld(id);
1339
+ worldTabsEl.appendChild(btn);
1340
+ }
1341
+
1342
+ customToggleEl.onclick = () => {
1343
+ customMode = !customMode;
1344
+ customTextareaEl.classList.toggle('visible', customMode);
1345
+ if (customMode) {
1346
+ document.querySelectorAll('.world-tab').forEach(t => t.classList.remove('active'));
1347
+ customToggleEl.textContent = '- hide custom editor';
1348
+ } else {
1349
+ customToggleEl.textContent = '+ paste custom .nv-world.md';
1350
+ if (currentWorld) selectWorld(currentWorld);
1351
+ }
1352
+ };
1353
+
1354
+ customTextareaEl.oninput = () => {
1355
+ if (customMode && customTextareaEl.value.trim()) {
1356
+ try {
1357
+ currentWorldDef = parseWorldMarkdown(customTextareaEl.value);
1358
+ currentWorld = 'custom';
1359
+ buildControls(currentWorldDef);
1360
+ } catch (e) { /* ignore parse errors while typing */ }
1361
+ }
1362
+ };
1363
+
1364
+ stepsSliderEl.oninput = () => {
1365
+ stepsValEl.textContent = stepsSliderEl.value;
1366
+ };
1367
+
1368
+ function selectWorld(id) {
1369
+ currentWorld = id;
1370
+ customMode = false;
1371
+ customTextareaEl.classList.remove('visible');
1372
+ customToggleEl.textContent = '+ paste custom .nv-world.md';
1373
+ document.querySelectorAll('.world-tab').forEach(t => t.classList.toggle('active', t.dataset.world === id));
1374
+ currentWorldDef = parseWorldMarkdown(BUNDLED_WORLDS[id].md);
1375
+ buildControls(currentWorldDef);
1376
+ }
1377
+
1378
+ function buildControls(world) {
1379
+ // Profiles
1380
+ profileSelectEl.innerHTML = '';
1381
+ for (const [pid, prof] of Object.entries(world.assumptions.profiles)) {
1382
+ const opt = document.createElement('option');
1383
+ opt.value = pid;
1384
+ opt.textContent = prof.name || pid;
1385
+ if (pid === world.world.default_assumption_profile) opt.selected = true;
1386
+ profileSelectEl.appendChild(opt);
1387
+ }
1388
+
1389
+ // State sliders
1390
+ stateSlidersEl.innerHTML = '';
1391
+ for (const [vid, v] of Object.entries(world.stateSchema.variables)) {
1392
+ const group = document.createElement('div');
1393
+ group.className = 'slider-group';
1394
+ const min = v.min ?? 0;
1395
+ const max = v.max ?? 100;
1396
+ const step = v.step ?? 1;
1397
+ const def = v.default ?? 0;
1398
+ group.innerHTML = `
1399
+ <div class="state-label-row">
1400
+ <span class="state-label">${v.label || vid}</span>
1401
+ <span class="state-value" id="sv-${vid}">${def}</span>
1402
+ </div>
1403
+ <input type="range" id="slider-${vid}" min="${min}" max="${max}" step="${step}" value="${def}" data-var="${vid}">
1404
+ `;
1405
+ stateSlidersEl.appendChild(group);
1406
+
1407
+ const slider = group.querySelector('input');
1408
+ const display = group.querySelector('.state-value');
1409
+ slider.oninput = () => { display.textContent = slider.value; };
1410
+ }
1411
+
1412
+ // Invariants
1413
+ invariantListEl.innerHTML = '';
1414
+ for (const inv of world.invariants) {
1415
+ const li = document.createElement('li');
1416
+ li.textContent = inv.label;
1417
+ invariantListEl.appendChild(li);
1418
+ }
1419
+ }
1420
+
1421
+ // ═══════════════════════════════════════════════════════════════════════════
1422
+ // SIMULATE + ANIMATE
1423
+ // ═══════════════════════════════════════════════════════════════════════════
1424
+
1425
+ simulateBtnEl.onclick = async () => {
1426
+ if (!currentWorldDef) return;
1427
+
1428
+ simulateBtnEl.classList.add('running');
1429
+ simulateBtnEl.textContent = 'Simulating...';
1430
+ simOutputEl.innerHTML = '';
1431
+ gateBadgeEl.classList.remove('visible');
1432
+ collapseBannerEl.classList.remove('visible');
1433
+ statsGridEl.innerHTML = '';
1434
+
1435
+ // Collect state overrides
1436
+ const overrides = {};
1437
+ for (const slider of stateSlidersEl.querySelectorAll('input[type="range"]')) {
1438
+ const vid = slider.dataset.var;
1439
+ const val = parseFloat(slider.value);
1440
+ overrides[vid] = val;
1441
+ }
1442
+
1443
+ const result = simulateWorld(currentWorldDef, {
1444
+ steps: parseInt(stepsSliderEl.value),
1445
+ stateOverrides: overrides,
1446
+ profile: profileSelectEl.value,
1447
+ });
1448
+
1449
+ // Animate steps one by one
1450
+ for (let i = 0; i < result.steps.length; i++) {
1451
+ const step = result.steps[i];
1452
+ const card = document.createElement('div');
1453
+ card.className = 'step-card';
1454
+
1455
+ // Find primary outcome
1456
+ const primaryOut = currentWorldDef.outcomes.computed_outcomes.find(o => o.primary);
1457
+ const primaryField = primaryOut ? primaryOut.id : null;
1458
+ const primaryVal = primaryField ? step.stateAfter[primaryField] : null;
1459
+
1460
+ card.innerHTML = `
1461
+ <div class="step-header">
1462
+ <span class="step-number">STEP ${step.step}</span>
1463
+ <span class="step-viability ${step.viability}">${step.viability}${primaryVal !== null ? ` (${Math.round(primaryVal)}%)` : ''}</span>
1464
+ </div>
1465
+ <div class="step-rules">
1466
+ ${step.rulesEvaluated.map(r => {
1467
+ const icon = r.excluded ? '<span class="rule-icon excluded">-</span>'
1468
+ : r.triggered ? '<span class="rule-icon fired">\u26A1</span>'
1469
+ : '<span class="rule-icon pass">\u00B7</span>';
1470
+ const cls = r.triggered ? 'fired' : '';
1471
+ const effectStr = r.effects.length > 0
1472
+ ? r.effects.map(e => {
1473
+ const pct = e.operation === 'multiply' ? `${Math.round(e.value * 100)}%` : `${e.operation} ${e.value}`;
1474
+ return `<span class="rule-effect ${r.severity}">${e.target} \u2192 ${pct}</span>`;
1475
+ }).join(' ')
1476
+ : '';
1477
+ return `<div class="rule-row">${icon}<span class="rule-label ${cls}">${r.label}</span>${effectStr}</div>`;
1478
+ }).join('')}
1479
+ </div>
1480
+ <div class="step-state">
1481
+ ${Object.entries(step.stateAfter)
1482
+ .filter(([k]) => k in currentWorldDef.stateSchema.variables || (primaryField && k === primaryField))
1483
+ .map(([k, v]) => {
1484
+ const prev = i > 0 ? result.steps[i-1].stateAfter[k] : result.initialState[k];
1485
+ const changed = prev !== undefined && prev !== v;
1486
+ const label = currentWorldDef.stateSchema.variables[k]?.label || k;
1487
+ return `<span class="state-chip">${label}: <span class="val ${changed ? 'changed' : ''}">${typeof v === 'number' ? Math.round(v * 100) / 100 : v}</span></span>`;
1488
+ }).join('')}
1489
+ </div>
1490
+ `;
1491
+
1492
+ simOutputEl.appendChild(card);
1493
+ await sleep(120);
1494
+ card.classList.add('visible');
1495
+ await sleep(80);
1496
+
1497
+ // Update ring progressively
1498
+ if (primaryField && primaryVal !== null) {
1499
+ updateRing(Math.round(primaryVal), step.viability);
1500
+ }
1501
+ }
1502
+
1503
+ // Final verdict
1504
+ await sleep(200);
1505
+
1506
+ const finalPrimary = currentWorldDef.outcomes.computed_outcomes.find(o => o.primary);
1507
+ const finalVal = finalPrimary ? Math.round(result.finalState[finalPrimary.id] ?? 0) : 0;
1508
+
1509
+ updateRing(finalVal, result.finalViability);
1510
+
1511
+ gateBadgeEl.textContent = result.finalViability;
1512
+ gateBadgeEl.className = `gate-badge ${result.finalViability} visible`;
1513
+
1514
+ // Stats
1515
+ const totalFired = result.steps.reduce((s, st) => s + st.rulesFired, 0);
1516
+ const totalRules = result.steps.reduce((s, st) => s + st.rulesEvaluated.length, 0);
1517
+
1518
+ statsGridEl.innerHTML = `
1519
+ <div class="stat-card">
1520
+ <div class="stat-label">Steps</div>
1521
+ <div class="stat-value">${result.steps.length}</div>
1522
+ </div>
1523
+ <div class="stat-card">
1524
+ <div class="stat-label">Rules Fired</div>
1525
+ <div class="stat-value ${totalFired > 5 ? 'warning' : ''}">${totalFired}</div>
1526
+ </div>
1527
+ <div class="stat-card">
1528
+ <div class="stat-label">Final Score</div>
1529
+ <div class="stat-value ${finalVal < 35 ? 'danger' : finalVal < 60 ? 'warning' : ''}">${finalVal}%</div>
1530
+ </div>
1531
+ <div class="stat-card">
1532
+ <div class="stat-label">Collapsed</div>
1533
+ <div class="stat-value ${result.collapsed ? 'danger' : ''}">${result.collapsed ? 'YES' : 'NO'}</div>
1534
+ </div>
1535
+ `;
1536
+
1537
+ if (result.collapsed) {
1538
+ collapseBannerEl.classList.add('visible');
1539
+ collapseDetailEl.textContent = `Collapsed at step ${result.collapseStep} by ${result.collapseRule}`;
1540
+ }
1541
+
1542
+ simulateBtnEl.classList.remove('running');
1543
+ simulateBtnEl.textContent = 'Simulate';
1544
+ };
1545
+
1546
+ function updateRing(value, viability) {
1547
+ const circumference = 2 * Math.PI * 70; // r=70
1548
+ const offset = circumference - (value / 100) * circumference;
1549
+ viabilityRingEl.style.strokeDashoffset = offset;
1550
+
1551
+ const color = value >= 60 ? 'var(--green)' : value >= 35 ? 'var(--amber)' : 'var(--red)';
1552
+ viabilityRingEl.style.stroke = color;
1553
+ viabilityRingEl.style.filter = `drop-shadow(0 0 6px ${color === 'var(--green)' ? 'var(--green-glow)' : color === 'var(--amber)' ? '#ffaa0060' : 'var(--red-glow)'})`;
1554
+
1555
+ viabilityValueEl.textContent = value + '%';
1556
+ viabilityValueEl.style.color = color;
1557
+ viabilityValueEl.style.textShadow = `0 0 20px ${color === 'var(--green)' ? 'var(--green-glow)' : color === 'var(--amber)' ? '#ffaa0060' : 'var(--red-glow)'}`;
1558
+ }
1559
+
1560
+ function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
1561
+
1562
+ // Auto-select first world
1563
+ selectWorld('coding-agent');
1564
+
1565
+ </script>
1566
+ </body>
1567
+ </html>