@neuroverseos/governance 0.3.1 → 0.3.4
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/.well-known/ai-plugin.json +34 -9
- package/AGENTS.md +72 -24
- package/README.md +343 -248
- package/dist/adapters/autoresearch.cjs +1345 -0
- package/dist/adapters/autoresearch.d.cts +111 -0
- package/dist/adapters/autoresearch.d.ts +111 -0
- package/dist/adapters/autoresearch.js +12 -0
- package/dist/adapters/deep-agents.cjs +1528 -0
- package/dist/adapters/deep-agents.d.cts +181 -0
- package/dist/adapters/deep-agents.d.ts +181 -0
- package/dist/adapters/deep-agents.js +17 -0
- package/dist/adapters/express.cjs +1253 -0
- package/dist/adapters/express.d.cts +66 -0
- package/dist/adapters/express.d.ts +66 -0
- package/dist/adapters/express.js +12 -0
- package/dist/adapters/index.cjs +2112 -0
- package/dist/adapters/index.d.cts +8 -0
- package/dist/adapters/index.d.ts +8 -0
- package/dist/adapters/index.js +68 -0
- package/dist/adapters/langchain.cjs +1315 -0
- package/dist/adapters/langchain.d.cts +89 -0
- package/dist/adapters/langchain.d.ts +89 -0
- package/dist/adapters/langchain.js +17 -0
- package/dist/adapters/openai.cjs +1345 -0
- package/dist/adapters/openai.d.cts +99 -0
- package/dist/adapters/openai.d.ts +99 -0
- package/dist/adapters/openai.js +17 -0
- package/dist/adapters/openclaw.cjs +1337 -0
- package/dist/adapters/openclaw.d.cts +99 -0
- package/dist/adapters/openclaw.d.ts +99 -0
- package/dist/adapters/openclaw.js +17 -0
- package/dist/add-ROOZLU62.js +314 -0
- package/dist/behavioral-MJO34S6Q.js +118 -0
- package/dist/bootstrap-CQRZVOXK.js +116 -0
- package/dist/bootstrap-emitter-Q7UIJZ2O.js +7 -0
- package/dist/bootstrap-parser-EEF36XDU.js +7 -0
- package/dist/browser.global.js +941 -0
- package/dist/build-ZHPMX5AZ.js +342 -0
- package/dist/chunk-3WQLXYTP.js +91 -0
- package/dist/chunk-4FLICVVA.js +119 -0
- package/dist/chunk-4NGDRRQH.js +10 -0
- package/dist/chunk-5TPFNWRU.js +215 -0
- package/dist/chunk-5U2MQO5P.js +57 -0
- package/dist/chunk-6CZSKEY5.js +164 -0
- package/dist/chunk-7P3S7MAY.js +1090 -0
- package/dist/chunk-A5W4GNQO.js +130 -0
- package/dist/chunk-A7GKPPU7.js +226 -0
- package/dist/chunk-AKW5YVCE.js +96 -0
- package/dist/chunk-B6OXJLJ5.js +622 -0
- package/dist/chunk-BNKJPUPQ.js +113 -0
- package/dist/chunk-BQZMOEML.js +43 -0
- package/dist/chunk-CNSO6XW5.js +207 -0
- package/dist/chunk-CTZHONLA.js +135 -0
- package/dist/chunk-D2UCV5AK.js +326 -0
- package/dist/chunk-EMQDLDAF.js +458 -0
- package/dist/chunk-F66BVUYB.js +340 -0
- package/dist/chunk-FMSTRBBS.js +17 -0
- package/dist/chunk-G7DJ6VOD.js +101 -0
- package/dist/chunk-I3RRAYK2.js +11 -0
- package/dist/chunk-INWQHLPS.js +47 -0
- package/dist/chunk-IS4WUH6Y.js +363 -0
- package/dist/chunk-O5ABKEA7.js +304 -0
- package/dist/chunk-OT6PXH54.js +61 -0
- package/dist/chunk-PVTQQS3Y.js +186 -0
- package/dist/chunk-QLPTHTVB.js +253 -0
- package/dist/chunk-QWGCMQQD.js +16 -0
- package/dist/chunk-QXBFT7NI.js +201 -0
- package/dist/chunk-TG6SEF24.js +246 -0
- package/dist/chunk-U6U7EJZL.js +177 -0
- package/dist/chunk-VXHSMA3I.js +166 -0
- package/dist/chunk-W7LLXRGY.js +830 -0
- package/dist/chunk-YEKMVDWK.js +624 -0
- package/dist/chunk-ZJTDUCC2.js +194 -0
- package/dist/chunk-ZWI3NIXK.js +314 -0
- package/dist/cli/neuroverse.cjs +14379 -0
- package/dist/cli/neuroverse.d.cts +1 -0
- package/dist/cli/neuroverse.d.ts +1 -0
- package/dist/cli/neuroverse.js +227 -0
- package/dist/cli/plan.cjs +2439 -0
- package/dist/cli/plan.d.cts +20 -0
- package/dist/cli/plan.d.ts +20 -0
- package/dist/cli/plan.js +353 -0
- package/dist/cli/run.cjs +2001 -0
- package/dist/cli/run.d.cts +20 -0
- package/dist/cli/run.d.ts +20 -0
- package/dist/cli/run.js +143 -0
- package/dist/configure-ai-5MP5DWTT.js +134 -0
- package/dist/decision-flow-M63D47LO.js +61 -0
- package/dist/demo-G43RLCPK.js +469 -0
- package/dist/derive-LMDUTXDD.js +154 -0
- package/dist/doctor-6BC6X2VO.js +173 -0
- package/dist/equity-penalties-SG5IZQ7I.js +244 -0
- package/dist/explain-RHBU2GBR.js +51 -0
- package/dist/guard-AEEJNWLD.js +126 -0
- package/dist/guard-contract-B7lplwm9.d.cts +837 -0
- package/dist/guard-contract-B7lplwm9.d.ts +837 -0
- package/dist/guard-engine-PNR6MHCM.js +10 -0
- package/dist/impact-3XVDSCBU.js +59 -0
- package/dist/improve-TQP4ECSY.js +66 -0
- package/dist/index.cjs +7738 -0
- package/dist/index.d.cts +2350 -0
- package/dist/index.d.ts +2350 -0
- package/dist/index.js +479 -0
- package/dist/infer-world-IFXCACJ5.js +543 -0
- package/dist/init-FYPV4SST.js +144 -0
- package/dist/init-world-TI7ARHBT.js +223 -0
- package/dist/mcp-server-5Y3ZM7TV.js +13 -0
- package/dist/model-adapter-VXEKB4LS.js +11 -0
- package/dist/playground-VZBNPPBO.js +560 -0
- package/dist/redteam-MZPZD3EF.js +357 -0
- package/dist/session-JYOARW54.js +15 -0
- package/dist/shared-7RLUHNMU.js +16 -0
- package/dist/shared-C_zpdvBm.d.cts +60 -0
- package/dist/shared-Cf7yxx4-.d.ts +60 -0
- package/dist/simulate-LJXYBC6M.js +83 -0
- package/dist/test-BOOR4A5F.js +217 -0
- package/dist/trace-PKV4KX56.js +166 -0
- package/dist/validate-RALX7CZS.js +81 -0
- package/dist/validate-engine-7ZXFVGF2.js +7 -0
- package/dist/viz/assets/index-B8SaeJZZ.js +23 -0
- package/dist/viz/index.html +23 -0
- package/dist/world-BIP4GZBZ.js +376 -0
- package/dist/world-loader-Y6HMQH2D.js +13 -0
- package/dist/worlds/autoresearch.nv-world.md +230 -0
- package/dist/worlds/coding-agent.nv-world.md +211 -0
- package/dist/worlds/derivation-world.nv-world.md +278 -0
- package/dist/worlds/research-agent.nv-world.md +169 -0
- package/dist/worlds/social-media.nv-world.md +198 -0
- package/dist/worlds/trading-agent.nv-world.md +218 -0
- package/examples/social-media-sim/bridge.py +209 -0
- package/examples/social-media-sim/simulation.py +927 -0
- package/package.json +16 -3
- package/simulate.html +4 -336
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadConfig
|
|
3
|
+
} from "./chunk-OT6PXH54.js";
|
|
4
|
+
import {
|
|
5
|
+
createProvider
|
|
6
|
+
} from "./chunk-INWQHLPS.js";
|
|
7
|
+
import {
|
|
8
|
+
validateWorld
|
|
9
|
+
} from "./chunk-7P3S7MAY.js";
|
|
10
|
+
import {
|
|
11
|
+
parseWorldMarkdown
|
|
12
|
+
} from "./chunk-EMQDLDAF.js";
|
|
13
|
+
import {
|
|
14
|
+
emitWorldDefinition
|
|
15
|
+
} from "./chunk-PVTQQS3Y.js";
|
|
16
|
+
|
|
17
|
+
// src/engine/derive-normalizer.ts
|
|
18
|
+
function findSections(lines) {
|
|
19
|
+
const sections = [];
|
|
20
|
+
let current = null;
|
|
21
|
+
for (let i = 0; i < lines.length; i++) {
|
|
22
|
+
if (lines[i].startsWith("# ")) {
|
|
23
|
+
if (current) {
|
|
24
|
+
current.end = i;
|
|
25
|
+
sections.push(current);
|
|
26
|
+
}
|
|
27
|
+
current = { name: lines[i].replace(/^#\s+/, "").trim(), start: i, end: lines.length };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (current) {
|
|
31
|
+
current.end = lines.length;
|
|
32
|
+
sections.push(current);
|
|
33
|
+
}
|
|
34
|
+
return sections;
|
|
35
|
+
}
|
|
36
|
+
var VALID_INVARIANT_RE = /^-\s+`[^`]+`\s*[—–-]\s*.+/;
|
|
37
|
+
function normalizeInvariantLine(line) {
|
|
38
|
+
const trimmed = line.trim();
|
|
39
|
+
if (!trimmed.startsWith("- ")) return line;
|
|
40
|
+
if (VALID_INVARIANT_RE.test(trimmed)) return line;
|
|
41
|
+
const boldMatch = trimmed.match(/^-\s+\*\*([^*]+)\*\*\s*([—–-])\s*(.+)$/);
|
|
42
|
+
if (boldMatch) {
|
|
43
|
+
const id = boldMatch[1].toLowerCase().replace(/\s+/g, "_");
|
|
44
|
+
const desc = boldMatch[3].trim();
|
|
45
|
+
const hasParens = /\([^)]+\)\s*$/.test(desc);
|
|
46
|
+
return `- \`${id}\` \u2014 ${hasParens ? desc : desc + " (structural, immutable)"}`;
|
|
47
|
+
}
|
|
48
|
+
const snakeMatch = trimmed.match(/^-\s+(\w[\w]*(?:_\w+)+)\s*([—–-])\s*(.+)$/);
|
|
49
|
+
if (snakeMatch) {
|
|
50
|
+
const id = snakeMatch[1];
|
|
51
|
+
const desc = snakeMatch[3].trim();
|
|
52
|
+
const hasParens = /\([^)]+\)\s*$/.test(desc);
|
|
53
|
+
return `- \`${id}\` \u2014 ${hasParens ? desc : desc + " (structural, immutable)"}`;
|
|
54
|
+
}
|
|
55
|
+
const proseMatch = trimmed.match(/^-\s+([A-Z][^(]+?)(?:\s*\(([^)]+)\))?\s*$/);
|
|
56
|
+
if (proseMatch) {
|
|
57
|
+
const desc = proseMatch[1].trim();
|
|
58
|
+
const parens = proseMatch[2] ?? "structural, immutable";
|
|
59
|
+
const id = desc.toLowerCase().replace(/[^a-z0-9\s]/g, "").replace(/\s+/g, "_").slice(0, 50);
|
|
60
|
+
if (id.length >= 3) {
|
|
61
|
+
return `- \`${id}\` \u2014 ${desc} (${parens})`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return line;
|
|
65
|
+
}
|
|
66
|
+
var VALID_GATE_RE = /^-\s+\w+:\s*\w+\s*(==|!=|>=|<=|>|<)\s*[\d.]+/;
|
|
67
|
+
var SYMBOLIC_TO_NUMERIC = {
|
|
68
|
+
// Positive states
|
|
69
|
+
full: 100,
|
|
70
|
+
complete: 100,
|
|
71
|
+
total: 100,
|
|
72
|
+
optimal: 95,
|
|
73
|
+
maximum: 100,
|
|
74
|
+
high: 80,
|
|
75
|
+
strong: 80,
|
|
76
|
+
// Mid states
|
|
77
|
+
partial: 60,
|
|
78
|
+
moderate: 50,
|
|
79
|
+
medium: 50,
|
|
80
|
+
growing: 60,
|
|
81
|
+
developing: 50,
|
|
82
|
+
// Low/negative states
|
|
83
|
+
low: 30,
|
|
84
|
+
minimal: 20,
|
|
85
|
+
weak: 20,
|
|
86
|
+
declining: 40,
|
|
87
|
+
limited: 30,
|
|
88
|
+
escalating: 50,
|
|
89
|
+
// Extreme states
|
|
90
|
+
none: 0,
|
|
91
|
+
absent: 0,
|
|
92
|
+
zero: 0,
|
|
93
|
+
critical: 80,
|
|
94
|
+
extreme: 90,
|
|
95
|
+
severe: 85,
|
|
96
|
+
indiscriminate: 80,
|
|
97
|
+
uncontrolled: 90,
|
|
98
|
+
overwhelming: 90
|
|
99
|
+
};
|
|
100
|
+
function normalizeGateLine(line) {
|
|
101
|
+
const trimmed = line.trim();
|
|
102
|
+
if (!trimmed.startsWith("- ")) return line;
|
|
103
|
+
if (VALID_GATE_RE.test(trimmed)) return line;
|
|
104
|
+
const symbolicMatch = trimmed.match(
|
|
105
|
+
/^-\s+(\w+):\s*(\w+)\s*(?:==?)\s*"?([a-zA-Z_]+)"?\s*$/
|
|
106
|
+
);
|
|
107
|
+
if (symbolicMatch) {
|
|
108
|
+
const status = symbolicMatch[1];
|
|
109
|
+
const field = symbolicMatch[2];
|
|
110
|
+
const symbolic = symbolicMatch[3].toLowerCase();
|
|
111
|
+
const numeric = SYMBOLIC_TO_NUMERIC[symbolic];
|
|
112
|
+
if (numeric !== void 0) {
|
|
113
|
+
return `- ${status}: ${field} >= ${numeric}`;
|
|
114
|
+
}
|
|
115
|
+
return `- ${status}: ${field} >= 50`;
|
|
116
|
+
}
|
|
117
|
+
const eqNumMatch = trimmed.match(/^-\s+(\w+):\s*(\w+)\s*=\s*([\d.]+)\s*$/);
|
|
118
|
+
if (eqNumMatch) {
|
|
119
|
+
return `- ${eqNumMatch[1]}: ${eqNumMatch[2]} >= ${eqNumMatch[3]}`;
|
|
120
|
+
}
|
|
121
|
+
return line;
|
|
122
|
+
}
|
|
123
|
+
function normalizeWhenLine(line) {
|
|
124
|
+
const trimmed = line.trim();
|
|
125
|
+
if (!trimmed.startsWith("When ")) return line;
|
|
126
|
+
const parts = trimmed.slice(5).split(/\s+AND\s+/i);
|
|
127
|
+
const normalized = parts.map((part) => {
|
|
128
|
+
const p = part.trim();
|
|
129
|
+
if (/\[(state|assumption)\]\s*$/.test(p)) return p;
|
|
130
|
+
return p + " [state]";
|
|
131
|
+
});
|
|
132
|
+
return "When " + normalized.join(" AND ");
|
|
133
|
+
}
|
|
134
|
+
function normalizeWorldMarkdown(markdown) {
|
|
135
|
+
const lines = markdown.split("\n");
|
|
136
|
+
const sections = findSections(lines);
|
|
137
|
+
const report = { fixCount: 0, invariantIds: 0, gateThresholds: 0, triggerTags: 0 };
|
|
138
|
+
const invariantsSection = sections.find((s) => s.name.toLowerCase() === "invariants");
|
|
139
|
+
const gatesSection = sections.find((s) => s.name.toLowerCase() === "gates");
|
|
140
|
+
const rulesSection = sections.find((s) => s.name.toLowerCase() === "rules");
|
|
141
|
+
for (let i = 0; i < lines.length; i++) {
|
|
142
|
+
const original = lines[i];
|
|
143
|
+
if (invariantsSection && i > invariantsSection.start && i < invariantsSection.end) {
|
|
144
|
+
lines[i] = normalizeInvariantLine(lines[i]);
|
|
145
|
+
if (lines[i] !== original) report.invariantIds++;
|
|
146
|
+
}
|
|
147
|
+
if (gatesSection && i > gatesSection.start && i < gatesSection.end) {
|
|
148
|
+
lines[i] = normalizeGateLine(lines[i]);
|
|
149
|
+
if (lines[i] !== original) report.gateThresholds++;
|
|
150
|
+
}
|
|
151
|
+
if (rulesSection && i > rulesSection.start && i < rulesSection.end) {
|
|
152
|
+
lines[i] = normalizeWhenLine(lines[i]);
|
|
153
|
+
if (lines[i] !== original) report.triggerTags++;
|
|
154
|
+
}
|
|
155
|
+
if (lines[i] !== original) report.fixCount++;
|
|
156
|
+
}
|
|
157
|
+
return { normalized: lines.join("\n"), fixCount: report.fixCount, report };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/engine/derive-engine.ts
|
|
161
|
+
import { writeFile } from "fs/promises";
|
|
162
|
+
|
|
163
|
+
// src/engine/derive-prompt.ts
|
|
164
|
+
import { readFile } from "fs/promises";
|
|
165
|
+
import { join, dirname } from "path";
|
|
166
|
+
var WORLD_FILENAME = "derivation-world.nv-world.md";
|
|
167
|
+
function getModuleDir() {
|
|
168
|
+
try {
|
|
169
|
+
return dirname(new URL(import.meta.url).pathname);
|
|
170
|
+
} catch {
|
|
171
|
+
return __dirname;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async function loadDerivationWorld() {
|
|
175
|
+
const moduleDir = getModuleDir();
|
|
176
|
+
const candidates = [
|
|
177
|
+
join(moduleDir, "..", "worlds", WORLD_FILENAME),
|
|
178
|
+
join(moduleDir, "worlds", WORLD_FILENAME)
|
|
179
|
+
];
|
|
180
|
+
for (const candidate of candidates) {
|
|
181
|
+
try {
|
|
182
|
+
return await readFile(candidate, "utf-8");
|
|
183
|
+
} catch {
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
throw new Error(
|
|
187
|
+
`DerivationWorld not found. Searched:
|
|
188
|
+
${candidates.map((c) => ` - ${c}`).join("\n")}`
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
async function collectMarkdownSources(inputPath) {
|
|
192
|
+
const { stat, readFile: rf, readdir } = await import("fs/promises");
|
|
193
|
+
const { join: pathJoin, extname, basename } = await import("path");
|
|
194
|
+
const stats = await stat(inputPath);
|
|
195
|
+
if (stats.isFile()) {
|
|
196
|
+
const content = await rf(inputPath, "utf-8");
|
|
197
|
+
return [{ filename: basename(inputPath), content }];
|
|
198
|
+
}
|
|
199
|
+
if (stats.isDirectory()) {
|
|
200
|
+
const sources = [];
|
|
201
|
+
await collectDir(inputPath, sources, rf, pathJoin, extname, basename);
|
|
202
|
+
sources.sort((a, b) => a.filename.localeCompare(b.filename));
|
|
203
|
+
return sources;
|
|
204
|
+
}
|
|
205
|
+
throw new Error(`Input path is neither a file nor a directory: ${inputPath}`);
|
|
206
|
+
}
|
|
207
|
+
async function collectDir(dir, sources, rf, pathJoin, extname, basename) {
|
|
208
|
+
const { readdir } = await import("fs/promises");
|
|
209
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
210
|
+
for (const entry of entries) {
|
|
211
|
+
const fullPath = pathJoin(dir, entry.name);
|
|
212
|
+
if (entry.isDirectory()) {
|
|
213
|
+
await collectDir(fullPath, sources, rf, pathJoin, extname, basename);
|
|
214
|
+
} else if (entry.isFile() && extname(entry.name).toLowerCase() === ".md") {
|
|
215
|
+
const content = await rf(fullPath, "utf-8");
|
|
216
|
+
sources.push({ filename: entry.name, content });
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function concatenateSources(sources) {
|
|
221
|
+
return sources.map((s) => `=== FILE: ${s.filename} ===
|
|
222
|
+
${s.content}`).join("\n\n");
|
|
223
|
+
}
|
|
224
|
+
var NV_WORLD_SPEC = `
|
|
225
|
+
## .nv-world.md Format Specification
|
|
226
|
+
|
|
227
|
+
A .nv-world.md file is a structured markdown document with YAML frontmatter and H1 sections.
|
|
228
|
+
|
|
229
|
+
### Frontmatter (required)
|
|
230
|
+
\`\`\`yaml
|
|
231
|
+
---
|
|
232
|
+
world_id: <snake_case_id>
|
|
233
|
+
name: <Human Readable Name>
|
|
234
|
+
version: 1.0.0
|
|
235
|
+
---
|
|
236
|
+
\`\`\`
|
|
237
|
+
|
|
238
|
+
### Required Sections
|
|
239
|
+
|
|
240
|
+
# Thesis
|
|
241
|
+
A single paragraph stating the structural claim this world tests. Must be testable and falsifiable.
|
|
242
|
+
|
|
243
|
+
# Invariants
|
|
244
|
+
Bullet list of non-negotiable constraints.
|
|
245
|
+
|
|
246
|
+
STRICT FORMAT \u2014 Invariant IDs MUST be wrapped in backticks. Every bullet MUST follow this exact pattern:
|
|
247
|
+
- \\\`invariant_id\\\` \u2014 Description text (enforcement, mutability)
|
|
248
|
+
|
|
249
|
+
VALID examples:
|
|
250
|
+
- \\\`rage_manifestation\\\` \u2014 Suppressed rage manifests as a physical monster (structural, immutable)
|
|
251
|
+
- \\\`healing_requires_integration\\\` \u2014 Recovery requires emotional integration (operational, immutable)
|
|
252
|
+
|
|
253
|
+
INVALID examples (these WILL cause parse failures):
|
|
254
|
+
- rage_manifestation \u2014 Suppressed rage manifests as a monster
|
|
255
|
+
- Suppressed rage manifests as a monster (structural, immutable)
|
|
256
|
+
- **rage_manifestation** \u2014 Description
|
|
257
|
+
|
|
258
|
+
Rules:
|
|
259
|
+
- The ID inside backticks must be snake_case (lowercase with underscores)
|
|
260
|
+
- Use "structural" for constraints derived directly from source material
|
|
261
|
+
- Use "operational" for constraints you inferred
|
|
262
|
+
- Mutability is almost always "immutable"
|
|
263
|
+
|
|
264
|
+
# State
|
|
265
|
+
H2 sub-sections, each defining a state variable:
|
|
266
|
+
## variable_name
|
|
267
|
+
- type: number | enum | boolean
|
|
268
|
+
- min: <number> (for number type)
|
|
269
|
+
- max: <number> (for number type)
|
|
270
|
+
- step: <number> (for number type)
|
|
271
|
+
- options: option_a, option_b (for enum type)
|
|
272
|
+
- default: <value>
|
|
273
|
+
- label: Human Label
|
|
274
|
+
- description: What this variable represents
|
|
275
|
+
|
|
276
|
+
IMPORTANT: State variable IDs (the ## heading) must be snake_case. The "default" value MUST be numeric for number types and MUST be one of the declared options for enum types.
|
|
277
|
+
|
|
278
|
+
# Assumptions
|
|
279
|
+
H2 sub-sections, each defining a scenario profile:
|
|
280
|
+
## profile_id
|
|
281
|
+
- name: Profile Name
|
|
282
|
+
- description: What this profile represents
|
|
283
|
+
- param_key: param_value
|
|
284
|
+
|
|
285
|
+
# Rules
|
|
286
|
+
H2 sub-sections with this format:
|
|
287
|
+
## rule-001: Rule Label (structural|degradation|advantage)
|
|
288
|
+
Single sentence description.
|
|
289
|
+
|
|
290
|
+
When field == "value" [state] AND other_field > 50 [state]
|
|
291
|
+
Then target *= 0.30, other_target = false
|
|
292
|
+
Collapse: field < 0.05
|
|
293
|
+
|
|
294
|
+
> trigger: What triggers this rule
|
|
295
|
+
> rule: What the rule means
|
|
296
|
+
> shift: What changes
|
|
297
|
+
> effect: The concrete effect
|
|
298
|
+
|
|
299
|
+
Rules must have:
|
|
300
|
+
- A "When" line with triggers referencing [state] or [assumption] sources
|
|
301
|
+
- A "Then" line with effects using =, *=, +=, or -= operators
|
|
302
|
+
- Optional "Collapse:" line for failure conditions
|
|
303
|
+
|
|
304
|
+
STRICT FORMAT for triggers \u2014 each trigger MUST match: field_name <operator> <value> [state|assumption]
|
|
305
|
+
- Operators: ==, !=, >=, <=, >, <
|
|
306
|
+
- Values must be numeric (50), boolean (true/false), or quoted strings ("value")
|
|
307
|
+
- Source tag [state] or [assumption] is REQUIRED
|
|
308
|
+
|
|
309
|
+
STRICT FORMAT for effects \u2014 each effect MUST match: target_field <operator> <value>
|
|
310
|
+
- Operators: =, *=, +=, -=
|
|
311
|
+
- Values must be numeric (0.30), boolean (true/false), or quoted strings ("value")
|
|
312
|
+
|
|
313
|
+
# Gates
|
|
314
|
+
Bullet list of status thresholds (must be monotonically decreasing).
|
|
315
|
+
|
|
316
|
+
STRICT FORMAT \u2014 Gate thresholds MUST be numeric. Symbolic values like "full", "partial", "escalating" are NOT allowed. Every gate MUST follow this exact pattern:
|
|
317
|
+
- STATUS_NAME: field_name >= <number>
|
|
318
|
+
|
|
319
|
+
VALID examples:
|
|
320
|
+
- BEST_STATUS: integration_level >= 90
|
|
321
|
+
- GOOD_STATUS: integration_level >= 60
|
|
322
|
+
- WARN_STATUS: monster_rage >= 40
|
|
323
|
+
- BAD_STATUS: monster_rage >= 70
|
|
324
|
+
- WORST_STATUS: josie_endangerment >= 90
|
|
325
|
+
|
|
326
|
+
INVALID examples (these WILL cause parse failures):
|
|
327
|
+
- BEST_STATUS: integration = full
|
|
328
|
+
- GOOD_STATUS: integration = partial
|
|
329
|
+
- BEST_STATUS: true_integration_state == "complete"
|
|
330
|
+
|
|
331
|
+
Rules:
|
|
332
|
+
- All gate thresholds must be NUMERIC values (integers or decimals)
|
|
333
|
+
- The field_name must reference a declared State variable or Outcome
|
|
334
|
+
- Operators: >=, <=, >, <, ==, !=
|
|
335
|
+
- Status names should be uppercase with underscores
|
|
336
|
+
- Thresholds must be monotonically decreasing from best to worst status
|
|
337
|
+
|
|
338
|
+
# Outcomes
|
|
339
|
+
H2 sub-sections defining computed outcomes:
|
|
340
|
+
## outcome_id
|
|
341
|
+
- type: number | enum | boolean
|
|
342
|
+
- range: 0-100 (for numbers)
|
|
343
|
+
- display: percentage | integer | decimal
|
|
344
|
+
- label: Human Label
|
|
345
|
+
- primary: true (for the main metric)
|
|
346
|
+
`.trim();
|
|
347
|
+
async function buildSystemPrompt() {
|
|
348
|
+
const derivationWorld = await loadDerivationWorld();
|
|
349
|
+
const invariantLines = derivationWorld.split("\n").filter((l) => l.trim().startsWith("- `")).map((l) => {
|
|
350
|
+
const match = l.match(/^-\s+`([^`]+)`\s*[—–-]\s*(.+?)(?:\s*\([^)]+\))?\s*$/);
|
|
351
|
+
return match ? `- ${match[2].trim()}` : null;
|
|
352
|
+
}).filter(Boolean);
|
|
353
|
+
return `You are a governance document synthesizer for NeuroVerse OS.
|
|
354
|
+
|
|
355
|
+
Your task: Given arbitrary markdown source material, synthesize a valid .nv-world.md governance document.
|
|
356
|
+
|
|
357
|
+
${NV_WORLD_SPEC}
|
|
358
|
+
|
|
359
|
+
## Synthesis Constraints (from DerivationWorld)
|
|
360
|
+
|
|
361
|
+
You MUST follow these constraints:
|
|
362
|
+
${invariantLines.join("\n")}
|
|
363
|
+
|
|
364
|
+
## Critical Rules
|
|
365
|
+
|
|
366
|
+
1. Output ONLY the .nv-world.md document. No preamble, no explanation, no trailing commentary.
|
|
367
|
+
2. Do not wrap the output in a code fence.
|
|
368
|
+
3. Every invariant derived from explicit source statements must be marked (structural, immutable).
|
|
369
|
+
4. Every invariant you infer that is not directly stated in the source must be marked (operational, immutable).
|
|
370
|
+
5. All state variables, rules, and invariants must trace to concepts present in the input.
|
|
371
|
+
6. Do not invent governance domains beyond what the source material covers.
|
|
372
|
+
7. Every rule must have a When trigger line and a Then effect line.
|
|
373
|
+
8. Gate thresholds must be monotonically decreasing from best to worst status.
|
|
374
|
+
9. The frontmatter must include world_id, name, and version.
|
|
375
|
+
10. Rule descriptions must be a single sentence.
|
|
376
|
+
|
|
377
|
+
## Syntax Precision (CRITICAL)
|
|
378
|
+
|
|
379
|
+
The output is parsed by a deterministic regex parser. If the syntax is wrong, the parse FAILS.
|
|
380
|
+
|
|
381
|
+
INVARIANTS: Every invariant bullet MUST use backtick-wrapped IDs:
|
|
382
|
+
CORRECT: - \\\`my_invariant_id\\\` \u2014 Description (structural, immutable)
|
|
383
|
+
WRONG: - my_invariant_id \u2014 Description
|
|
384
|
+
|
|
385
|
+
GATES: Every gate MUST use NUMERIC thresholds:
|
|
386
|
+
CORRECT: - THRIVING: score >= 80
|
|
387
|
+
WRONG: - THRIVING: state = optimal
|
|
388
|
+
|
|
389
|
+
TRIGGERS: Every trigger MUST end with [state] or [assumption]:
|
|
390
|
+
CORRECT: When score < 25 [state]
|
|
391
|
+
WRONG: When score < 25
|
|
392
|
+
|
|
393
|
+
EFFECTS: Every effect MUST use a recognized operator:
|
|
394
|
+
CORRECT: Then score *= 0.50, active = false
|
|
395
|
+
WRONG: Then score decreases by half`;
|
|
396
|
+
}
|
|
397
|
+
function buildUserPrompt(concatenatedMarkdown) {
|
|
398
|
+
return `Synthesize a valid .nv-world.md under DerivationWorld constraints from the following source material.
|
|
399
|
+
|
|
400
|
+
Output ONLY the .nv-world.md content. Start with the --- frontmatter delimiter.
|
|
401
|
+
|
|
402
|
+
Source material:
|
|
403
|
+
|
|
404
|
+
${concatenatedMarkdown}`;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// src/engine/derive-engine.ts
|
|
408
|
+
function extractWorldMarkdown(raw) {
|
|
409
|
+
let content = raw.trim();
|
|
410
|
+
const fenceMatch = content.match(/```(?:markdown|md)?\s*\n([\s\S]*?)```/);
|
|
411
|
+
if (fenceMatch) {
|
|
412
|
+
content = fenceMatch[1].trim();
|
|
413
|
+
}
|
|
414
|
+
const sentinelMatch = content.match(
|
|
415
|
+
/(?:BEGIN NV WORLD|BEGIN_NV_WORLD)[\s\n]*([\s\S]*?)[\s\n]*(?:END NV WORLD|END_NV_WORLD)/i
|
|
416
|
+
);
|
|
417
|
+
if (sentinelMatch) {
|
|
418
|
+
content = sentinelMatch[1].trim();
|
|
419
|
+
}
|
|
420
|
+
if (!content.startsWith("---")) {
|
|
421
|
+
const fmIndex = content.indexOf("---\n");
|
|
422
|
+
if (fmIndex >= 0) {
|
|
423
|
+
content = content.slice(fmIndex);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
if (!content.startsWith("---") && /^# /m.test(content)) {
|
|
427
|
+
const generated = generateFrontmatter(content);
|
|
428
|
+
content = generated + "\n" + content;
|
|
429
|
+
}
|
|
430
|
+
if (!content.startsWith("---")) return null;
|
|
431
|
+
const fmEnd = content.indexOf("---", 3);
|
|
432
|
+
if (fmEnd === -1) return null;
|
|
433
|
+
const frontmatter = content.slice(3, fmEnd);
|
|
434
|
+
if (!frontmatter.includes("world_id:")) return null;
|
|
435
|
+
return content;
|
|
436
|
+
}
|
|
437
|
+
function generateFrontmatter(content) {
|
|
438
|
+
let name = "Derived World";
|
|
439
|
+
const thesisMatch = content.match(/^# Thesis\s*\n+(.+)/m);
|
|
440
|
+
if (thesisMatch) {
|
|
441
|
+
const firstSentence = thesisMatch[1].replace(/[.!?].*$/, "").trim();
|
|
442
|
+
if (firstSentence.length >= 3 && firstSentence.length <= 60) {
|
|
443
|
+
name = firstSentence;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
const worldId = name.toLowerCase().replace(/[^a-z0-9\s]/g, "").replace(/\s+/g, "_").slice(0, 50);
|
|
447
|
+
return [
|
|
448
|
+
"---",
|
|
449
|
+
`world_id: ${worldId}`,
|
|
450
|
+
`name: ${name}`,
|
|
451
|
+
"version: 0.1",
|
|
452
|
+
"runtime_mode: simulation",
|
|
453
|
+
"---"
|
|
454
|
+
].join("\n");
|
|
455
|
+
}
|
|
456
|
+
var GATES = [
|
|
457
|
+
{ status: "FAITHFUL", threshold: 0.85 },
|
|
458
|
+
{ status: "USABLE", threshold: 0.6 },
|
|
459
|
+
{ status: "REVIEWABLE", threshold: 0.4 },
|
|
460
|
+
{ status: "SUSPECT", threshold: 0.15 },
|
|
461
|
+
{ status: "DERIVATION_REJECTED", threshold: 0 }
|
|
462
|
+
];
|
|
463
|
+
function classifyGate(errors, warnings, sectionCount) {
|
|
464
|
+
const maxSections = 7;
|
|
465
|
+
const completeness = sectionCount / maxSections;
|
|
466
|
+
const fidelity = errors === 0 ? Math.max(0, completeness - warnings * 0.05) : 0;
|
|
467
|
+
for (const gate of GATES) {
|
|
468
|
+
if (fidelity >= gate.threshold) return gate.status;
|
|
469
|
+
}
|
|
470
|
+
return "DERIVATION_REJECTED";
|
|
471
|
+
}
|
|
472
|
+
async function deriveWorld(options) {
|
|
473
|
+
const startTime = performance.now();
|
|
474
|
+
const sources = await collectMarkdownSources(options.inputPath);
|
|
475
|
+
if (sources.length === 0) {
|
|
476
|
+
throw new DeriveInputError("No markdown files found in input path");
|
|
477
|
+
}
|
|
478
|
+
const concatenated = concatenateSources(sources);
|
|
479
|
+
const systemPrompt = await buildSystemPrompt();
|
|
480
|
+
const userPrompt = buildUserPrompt(concatenated);
|
|
481
|
+
if (options.dryRun) {
|
|
482
|
+
return {
|
|
483
|
+
result: {
|
|
484
|
+
success: true,
|
|
485
|
+
outputPath: options.outputPath,
|
|
486
|
+
sectionsDetected: [],
|
|
487
|
+
validationErrors: 0,
|
|
488
|
+
validationWarnings: 0,
|
|
489
|
+
findings: [],
|
|
490
|
+
gate: "DRY_RUN",
|
|
491
|
+
durationMs: performance.now() - startTime
|
|
492
|
+
},
|
|
493
|
+
exitCode: 0,
|
|
494
|
+
dryRunOutput: { systemPrompt, userPrompt }
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
const savedConfig = await loadConfig();
|
|
498
|
+
const config = {
|
|
499
|
+
provider: options.providerOverride?.provider ?? savedConfig?.provider ?? "",
|
|
500
|
+
model: options.providerOverride?.model ?? savedConfig?.model ?? "",
|
|
501
|
+
apiKey: options.providerOverride?.apiKey ?? savedConfig?.apiKey ?? "",
|
|
502
|
+
endpoint: options.providerOverride?.endpoint ?? savedConfig?.endpoint ?? null
|
|
503
|
+
};
|
|
504
|
+
if (!config.apiKey) {
|
|
505
|
+
throw new DeriveProviderError("No API key configured. Run: neuroverse configure-ai");
|
|
506
|
+
}
|
|
507
|
+
if (!config.model) {
|
|
508
|
+
throw new DeriveProviderError("No model configured. Run: neuroverse configure-ai");
|
|
509
|
+
}
|
|
510
|
+
const provider = createProvider(config);
|
|
511
|
+
let rawResponse;
|
|
512
|
+
try {
|
|
513
|
+
rawResponse = await provider.complete(systemPrompt, userPrompt);
|
|
514
|
+
} catch (e) {
|
|
515
|
+
throw new DeriveProviderError(`AI provider failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
516
|
+
}
|
|
517
|
+
const extracted = extractWorldMarkdown(rawResponse);
|
|
518
|
+
if (!extracted) {
|
|
519
|
+
throw new DeriveProviderError(
|
|
520
|
+
"Could not extract valid .nv-world.md from AI response. Response must contain frontmatter with world_id."
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
const { normalized, fixCount, report: normReport } = normalizeWorldMarkdown(extracted);
|
|
524
|
+
const { world, issues } = parseWorldMarkdown(normalized);
|
|
525
|
+
const errors = issues.filter((i) => i.severity === "error");
|
|
526
|
+
const warnings = issues.filter((i) => i.severity === "warning");
|
|
527
|
+
const sectionsDetected = world ? Object.keys(world).filter((k) => {
|
|
528
|
+
const val = world[k];
|
|
529
|
+
if (Array.isArray(val)) return val.length > 0;
|
|
530
|
+
if (typeof val === "string") return val.length > 0;
|
|
531
|
+
return !!val;
|
|
532
|
+
}) : [];
|
|
533
|
+
if (world && options.validate) {
|
|
534
|
+
try {
|
|
535
|
+
const { world: worldDef } = emitWorldDefinition(world);
|
|
536
|
+
const report = validateWorld(worldDef);
|
|
537
|
+
for (const finding of report.findings) {
|
|
538
|
+
if (finding.severity === "error" || finding.severity === "warning") {
|
|
539
|
+
issues.push({
|
|
540
|
+
line: 0,
|
|
541
|
+
section: `Validate:${finding.category}`,
|
|
542
|
+
message: finding.message,
|
|
543
|
+
severity: finding.severity
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
} catch {
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
const allErrors = issues.filter((i) => i.severity === "error");
|
|
551
|
+
const allWarnings = issues.filter((i) => i.severity === "warning");
|
|
552
|
+
const gate = classifyGate(allErrors.length, allWarnings.length, sectionsDetected.length);
|
|
553
|
+
const findings = issues.filter((i) => i.severity === "error" || i.severity === "warning").map((i) => ({
|
|
554
|
+
severity: i.severity,
|
|
555
|
+
section: i.section,
|
|
556
|
+
message: i.message,
|
|
557
|
+
line: i.line
|
|
558
|
+
}));
|
|
559
|
+
let output = normalized;
|
|
560
|
+
if (findings.length > 0 || fixCount > 0) {
|
|
561
|
+
const lines = [`<!-- DERIVATION STATUS: ${gate}`];
|
|
562
|
+
if (fixCount > 0) {
|
|
563
|
+
const details = [];
|
|
564
|
+
if (normReport.invariantIds > 0) details.push(`${normReport.invariantIds} invariant ID(s) wrapped`);
|
|
565
|
+
if (normReport.gateThresholds > 0) details.push(`${normReport.gateThresholds} gate threshold(s) converted`);
|
|
566
|
+
if (normReport.triggerTags > 0) details.push(`${normReport.triggerTags} trigger(s) tagged with [state]`);
|
|
567
|
+
lines.push(``, `Normalizer: ${fixCount} fix(es) applied`);
|
|
568
|
+
for (const d of details) lines.push(` - ${d}`);
|
|
569
|
+
}
|
|
570
|
+
const errs = findings.filter((f) => f.severity === "error");
|
|
571
|
+
const warns = findings.filter((f) => f.severity === "warning");
|
|
572
|
+
if (errs.length > 0) {
|
|
573
|
+
lines.push("", "Errors:");
|
|
574
|
+
for (const f of errs) lines.push(`- [${f.section}] ${f.message}`);
|
|
575
|
+
}
|
|
576
|
+
if (warns.length > 0) {
|
|
577
|
+
lines.push("", "Warnings:");
|
|
578
|
+
for (const f of warns) lines.push(`- [${f.section}] ${f.message}`);
|
|
579
|
+
}
|
|
580
|
+
lines.push("-->", "");
|
|
581
|
+
output = lines.join("\n") + normalized;
|
|
582
|
+
}
|
|
583
|
+
await writeFile(options.outputPath, output, "utf-8");
|
|
584
|
+
const hasErrors = allErrors.length > 0;
|
|
585
|
+
return {
|
|
586
|
+
result: {
|
|
587
|
+
success: !hasErrors,
|
|
588
|
+
outputPath: options.outputPath,
|
|
589
|
+
sectionsDetected,
|
|
590
|
+
validationErrors: allErrors.length,
|
|
591
|
+
validationWarnings: allWarnings.length,
|
|
592
|
+
findings,
|
|
593
|
+
gate,
|
|
594
|
+
normalization: fixCount > 0 ? {
|
|
595
|
+
fixCount: normReport.fixCount,
|
|
596
|
+
invariantIds: normReport.invariantIds,
|
|
597
|
+
gateThresholds: normReport.gateThresholds,
|
|
598
|
+
triggerTags: normReport.triggerTags
|
|
599
|
+
} : void 0,
|
|
600
|
+
durationMs: performance.now() - startTime
|
|
601
|
+
},
|
|
602
|
+
exitCode: hasErrors ? 1 : 0
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
var DeriveInputError = class extends Error {
|
|
606
|
+
constructor(message) {
|
|
607
|
+
super(message);
|
|
608
|
+
this.name = "DeriveInputError";
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
var DeriveProviderError = class extends Error {
|
|
612
|
+
constructor(message) {
|
|
613
|
+
super(message);
|
|
614
|
+
this.name = "DeriveProviderError";
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
export {
|
|
619
|
+
normalizeWorldMarkdown,
|
|
620
|
+
extractWorldMarkdown,
|
|
621
|
+
deriveWorld,
|
|
622
|
+
DeriveInputError,
|
|
623
|
+
DeriveProviderError
|
|
624
|
+
};
|