@neuroverseos/governance 0.5.0 → 0.6.0
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 +244 -0
- package/dist/adapters/autoresearch.d.cts +2 -1
- package/dist/adapters/autoresearch.d.ts +2 -1
- package/dist/adapters/autoresearch.js +2 -2
- package/dist/adapters/deep-agents.d.cts +3 -2
- package/dist/adapters/deep-agents.d.ts +3 -2
- package/dist/adapters/deep-agents.js +2 -2
- package/dist/adapters/express.d.cts +2 -1
- package/dist/adapters/express.d.ts +2 -1
- package/dist/adapters/express.js +2 -2
- package/dist/adapters/github.cjs +1697 -0
- package/dist/adapters/github.d.cts +225 -0
- package/dist/adapters/github.d.ts +225 -0
- package/dist/adapters/github.js +27 -0
- package/dist/adapters/index.d.cts +4 -316
- package/dist/adapters/index.d.ts +4 -316
- package/dist/adapters/index.js +23 -21
- package/dist/adapters/langchain.d.cts +3 -2
- package/dist/adapters/langchain.d.ts +3 -2
- package/dist/adapters/langchain.js +2 -2
- package/dist/adapters/mentraos.cjs +2181 -0
- package/dist/adapters/mentraos.d.cts +319 -0
- package/dist/adapters/mentraos.d.ts +319 -0
- package/dist/{mentraos-LLH7KEV4.js → adapters/mentraos.js} +12 -10
- package/dist/adapters/openai.d.cts +3 -2
- package/dist/adapters/openai.d.ts +3 -2
- package/dist/adapters/openai.js +2 -2
- package/dist/adapters/openclaw.d.cts +3 -2
- package/dist/adapters/openclaw.d.ts +3 -2
- package/dist/adapters/openclaw.js +2 -2
- package/dist/{add-LYHDZ5RL.js → add-XSANI3FK.js} +1 -1
- package/dist/admin/index.cjs +2214 -0
- package/dist/admin/index.d.cts +362 -0
- package/dist/admin/index.d.ts +362 -0
- package/dist/admin/index.js +703 -0
- package/dist/bootstrap-contract-DcV6t-8M.d.cts +216 -0
- package/dist/bootstrap-contract-DcV6t-8M.d.ts +216 -0
- package/dist/{build-SCAWPA7E.js → build-UTVDGHB3.js} +5 -5
- package/dist/{chunk-JKGPSFGH.js → chunk-7FL3U7Z5.js} +3 -3
- package/dist/chunk-A2UZTLRV.js +421 -0
- package/dist/{chunk-TD5GKIHP.js → chunk-B3IIPTY3.js} +3 -3
- package/dist/chunk-EQR7BGFN.js +337 -0
- package/dist/{chunk-5JUZ4HL7.js → chunk-FDPPZLSQ.js} +3 -3
- package/dist/{chunk-MFKHTE5R.js → chunk-FKQCPRKI.js} +3 -3
- package/dist/{chunk-7D7PZLB7.js → chunk-FS2UUJJO.js} +3 -3
- package/dist/{chunk-U6FRAEQJ.js → chunk-GJ6LM4JZ.js} +1 -441
- package/dist/chunk-H3REGQRI.js +107 -0
- package/dist/{chunk-25XHSTPT.js → chunk-HDNDL6D5.js} +3 -3
- package/dist/{chunk-BXLTEUS4.js → chunk-I4RTIMLX.js} +2 -2
- package/dist/chunk-IOVXB6QN.js +447 -0
- package/dist/{chunk-Y6WXAPKY.js → chunk-NTHXZAW4.js} +3 -3
- package/dist/{chunk-UTH7OXTM.js → chunk-OTZU76DH.js} +22 -4
- package/dist/{chunk-DWHUZUEY.js → chunk-T6GMRZWC.js} +3 -3
- package/dist/{chunk-V4FZHJQX.js → chunk-TIXVEPS2.js} +3 -3
- package/dist/{chunk-YNYCQECH.js → chunk-TJ5L2UTE.js} +3 -3
- package/dist/chunk-UGTNKTHS.js +542 -0
- package/dist/cli/neuroverse.cjs +3372 -523
- package/dist/cli/neuroverse.js +53 -21
- package/dist/cli/plan.js +2 -2
- package/dist/cli/run.cjs +242 -139
- package/dist/cli/run.js +23 -3
- package/dist/cli/worldmodel.cjs +1624 -0
- package/dist/cli/worldmodel.d.cts +24 -0
- package/dist/cli/worldmodel.d.ts +24 -0
- package/dist/cli/worldmodel.js +742 -0
- package/dist/{demo-66MMJTEH.js → demo-6W3YXLAX.js} +4 -4
- package/dist/{derive-AUQE3L3P.js → derive-42IJW7JI.js} +4 -4
- package/dist/{doctor-EY7LKSYY.js → doctor-XEMLO6UA.js} +3 -2
- package/dist/engine/bootstrap-emitter.cjs +241 -0
- package/dist/engine/bootstrap-emitter.d.cts +27 -0
- package/dist/engine/bootstrap-emitter.d.ts +27 -0
- package/dist/{bootstrap-emitter-GIMOJFOC.js → engine/bootstrap-emitter.js} +2 -2
- package/dist/engine/bootstrap-parser.cjs +560 -0
- package/dist/engine/bootstrap-parser.d.cts +96 -0
- package/dist/engine/bootstrap-parser.d.ts +96 -0
- package/dist/{bootstrap-parser-LBLGVEMU.js → engine/bootstrap-parser.js} +2 -2
- package/dist/engine/guard-engine.cjs +1116 -0
- package/dist/engine/guard-engine.d.cts +60 -0
- package/dist/engine/guard-engine.d.ts +60 -0
- package/dist/{guard-engine-N7TUIUU7.js → engine/guard-engine.js} +3 -3
- package/dist/engine/simulate-engine.cjs +390 -0
- package/dist/engine/simulate-engine.d.cts +105 -0
- package/dist/engine/simulate-engine.d.ts +105 -0
- package/dist/engine/simulate-engine.js +9 -0
- package/dist/engine/worldmodel-compiler.cjs +366 -0
- package/dist/engine/worldmodel-compiler.d.cts +46 -0
- package/dist/engine/worldmodel-compiler.d.ts +46 -0
- package/dist/engine/worldmodel-compiler.js +17 -0
- package/dist/engine/worldmodel-parser.cjs +566 -0
- package/dist/engine/worldmodel-parser.d.cts +22 -0
- package/dist/engine/worldmodel-parser.d.ts +22 -0
- package/dist/engine/worldmodel-parser.js +7 -0
- package/dist/{equity-penalties-WWC7UDQD.js → equity-penalties-CCO3GVHS.js} +6 -6
- package/dist/{explain-MUSGDT67.js → explain-HDFN4ION.js} +1 -1
- package/dist/{guard-W3BMQPBJ.js → guard-IHJEKHL2.js} +16 -4
- package/dist/{guard-contract-CLBbTGK_.d.ts → guard-contract-ddiIPlOg.d.cts} +2 -369
- package/dist/{guard-contract-CLBbTGK_.d.cts → guard-contract-q6HJAq3Q.d.ts} +2 -369
- package/dist/{improve-PJDAWW4Q.js → improve-LRORRYEX.js} +3 -3
- package/dist/index.cjs +471 -1
- package/dist/index.d.cts +14 -492
- package/dist/index.d.ts +14 -492
- package/dist/index.js +63 -42
- package/dist/keygen-BSZH3NM2.js +77 -0
- package/dist/{lens-IP6GIZ2Q.js → lens-TLDZQXBI.js} +152 -26
- package/dist/{mcp-server-OG3PPVD2.js → mcp-server-CKYBHXWK.js} +2 -2
- package/dist/migrate-NH5PVMX4.js +221 -0
- package/dist/{playground-4BK2XQ47.js → playground-3TTBN7XD.js} +5 -5
- package/dist/{redteam-BRZALBPP.js → redteam-W644UMWN.js} +3 -3
- package/dist/{session-SGRUT2UH.js → session-FMAROEIE.js} +2 -2
- package/dist/{shared-CwGpPheR.d.ts → shared-DAzdfWtU.d.ts} +1 -1
- package/dist/{shared-BGzmYP5g.d.cts → shared-PpalGKxc.d.cts} +1 -1
- package/dist/sign-RRELHKWM.js +11 -0
- package/dist/{simulate-FGXKIH7V.js → simulate-VT437EEL.js} +2 -2
- package/dist/{test-PT44BSYG.js → test-XDB2DH3L.js} +3 -3
- package/dist/types.cjs +18 -0
- package/dist/types.d.cts +370 -0
- package/dist/types.d.ts +370 -0
- package/dist/types.js +0 -0
- package/dist/{validate-Q5O5TGLT.js → validate-M52DX22Y.js} +1 -1
- package/dist/verify-6AVTWX75.js +151 -0
- package/dist/{world-V52ZMH26.js → world-O4HTQPDP.js} +1 -1
- package/dist/{world-loader-C4D3VPP3.js → world-loader-YTYFOP7D.js} +1 -1
- package/dist/worldmodel-contract-BPGhiuW5.d.cts +221 -0
- package/dist/worldmodel-contract-BPGhiuW5.d.ts +221 -0
- package/dist/worlds/auki-vanguard.worldmodel.md +116 -0
- package/dist/worlds/behavioral-demo.nv-world.md +130 -0
- package/dist/worlds/neuroverse-governance.worldmodel.md +115 -0
- package/package.json +44 -3
- package/dist/{bootstrap-IP5QMC3Q.js → bootstrap-2OW5ZLBL.js} +3 -3
- package/dist/{chunk-4G6WHPLI.js → chunk-735Z3HA4.js} +6 -6
- package/dist/{chunk-7QIAF377.js → chunk-CYDMUJVZ.js} +0 -0
- package/dist/{configure-ai-LL3VAPQW.js → configure-ai-5MP5DWTT.js} +3 -3
- package/dist/{decision-flow-3K4D72G4.js → decision-flow-IJPNMVQK.js} +3 -3
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { WorldDefinition, GovernanceEvent } from '../types.cjs';
|
|
2
|
+
import { a as GuardEvent, b as GuardEngineOptions, G as GuardVerdict, d as GuardStatus } from '../guard-contract-ddiIPlOg.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Guard Engine — Deterministic Governance Evaluator
|
|
6
|
+
*
|
|
7
|
+
* Pure function: (event, world, options) → verdict
|
|
8
|
+
*
|
|
9
|
+
* Evaluates a GuardEvent against a loaded WorldDefinition and produces
|
|
10
|
+
* a GuardVerdict with evidence and optional evaluation trace.
|
|
11
|
+
*
|
|
12
|
+
* Evaluation chain (first-match-wins on BLOCK/PAUSE):
|
|
13
|
+
* 1. Safety checks (prompt injection, scope escape) → PAUSE
|
|
14
|
+
* 1.5 Plan enforcement (task scope) → BLOCK/PAUSE
|
|
15
|
+
* 2. Role-specific rules (cannotDo, requiresApproval) → BLOCK/PAUSE
|
|
16
|
+
* 3. Declarative guards (guards.json) → BLOCK/PAUSE/WARN
|
|
17
|
+
* 4. Kernel rules (kernel.json forbidden patterns) → BLOCK
|
|
18
|
+
* 5. Level constraints (basic/standard/strict) → PAUSE
|
|
19
|
+
* 6. Default → ALLOW
|
|
20
|
+
*
|
|
21
|
+
* Invariant checks run unconditionally and are recorded in evidence
|
|
22
|
+
* but do not produce verdicts — they measure world health.
|
|
23
|
+
*
|
|
24
|
+
* INVARIANTS:
|
|
25
|
+
* - Deterministic: same event + same world → same verdict.
|
|
26
|
+
* - Zero network calls. Zero LLM calls. Zero async.
|
|
27
|
+
* - Every check is recorded in the trace, not just the decider.
|
|
28
|
+
* - No hidden logic. Everything is in the world file or declared here.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
declare function evaluateGuard(event: GuardEvent, world: WorldDefinition, options?: GuardEngineOptions): GuardVerdict;
|
|
32
|
+
/**
|
|
33
|
+
* Build a normalized allowlist key from a GuardEvent.
|
|
34
|
+
*
|
|
35
|
+
* Format: `tool::intent` (both lowercased, intent trimmed).
|
|
36
|
+
* Tool defaults to '*' when absent.
|
|
37
|
+
*
|
|
38
|
+
* Callers use this to:
|
|
39
|
+
* 1. Add keys to the allowlist set (on user "allow-always" decision)
|
|
40
|
+
* 2. The engine uses it to check membership before evaluation
|
|
41
|
+
*
|
|
42
|
+
* The key is opaque — callers should always use this function
|
|
43
|
+
* rather than constructing keys manually.
|
|
44
|
+
*/
|
|
45
|
+
declare function eventToAllowlistKey(event: GuardEvent): string;
|
|
46
|
+
/**
|
|
47
|
+
* Convert a guard verdict into a GovernanceEvent.
|
|
48
|
+
*
|
|
49
|
+
* The guard evaluation log IS the event stream.
|
|
50
|
+
* No Kafka, no queues — just data flowing from Guard → Simulate.
|
|
51
|
+
*
|
|
52
|
+
* Mapping:
|
|
53
|
+
* ALLOW → "action_allowed"
|
|
54
|
+
* BLOCK → "action_blocked"
|
|
55
|
+
* PAUSE → "action_paused"
|
|
56
|
+
* + semantic type from intent when available
|
|
57
|
+
*/
|
|
58
|
+
declare function verdictToEvent(status: GuardStatus, intent?: string): GovernanceEvent;
|
|
59
|
+
|
|
60
|
+
export { evaluateGuard, eventToAllowlistKey, verdictToEvent };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { WorldDefinition, GovernanceEvent } from '../types.js';
|
|
2
|
+
import { a as GuardEvent, b as GuardEngineOptions, G as GuardVerdict, d as GuardStatus } from '../guard-contract-q6HJAq3Q.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Guard Engine — Deterministic Governance Evaluator
|
|
6
|
+
*
|
|
7
|
+
* Pure function: (event, world, options) → verdict
|
|
8
|
+
*
|
|
9
|
+
* Evaluates a GuardEvent against a loaded WorldDefinition and produces
|
|
10
|
+
* a GuardVerdict with evidence and optional evaluation trace.
|
|
11
|
+
*
|
|
12
|
+
* Evaluation chain (first-match-wins on BLOCK/PAUSE):
|
|
13
|
+
* 1. Safety checks (prompt injection, scope escape) → PAUSE
|
|
14
|
+
* 1.5 Plan enforcement (task scope) → BLOCK/PAUSE
|
|
15
|
+
* 2. Role-specific rules (cannotDo, requiresApproval) → BLOCK/PAUSE
|
|
16
|
+
* 3. Declarative guards (guards.json) → BLOCK/PAUSE/WARN
|
|
17
|
+
* 4. Kernel rules (kernel.json forbidden patterns) → BLOCK
|
|
18
|
+
* 5. Level constraints (basic/standard/strict) → PAUSE
|
|
19
|
+
* 6. Default → ALLOW
|
|
20
|
+
*
|
|
21
|
+
* Invariant checks run unconditionally and are recorded in evidence
|
|
22
|
+
* but do not produce verdicts — they measure world health.
|
|
23
|
+
*
|
|
24
|
+
* INVARIANTS:
|
|
25
|
+
* - Deterministic: same event + same world → same verdict.
|
|
26
|
+
* - Zero network calls. Zero LLM calls. Zero async.
|
|
27
|
+
* - Every check is recorded in the trace, not just the decider.
|
|
28
|
+
* - No hidden logic. Everything is in the world file or declared here.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
declare function evaluateGuard(event: GuardEvent, world: WorldDefinition, options?: GuardEngineOptions): GuardVerdict;
|
|
32
|
+
/**
|
|
33
|
+
* Build a normalized allowlist key from a GuardEvent.
|
|
34
|
+
*
|
|
35
|
+
* Format: `tool::intent` (both lowercased, intent trimmed).
|
|
36
|
+
* Tool defaults to '*' when absent.
|
|
37
|
+
*
|
|
38
|
+
* Callers use this to:
|
|
39
|
+
* 1. Add keys to the allowlist set (on user "allow-always" decision)
|
|
40
|
+
* 2. The engine uses it to check membership before evaluation
|
|
41
|
+
*
|
|
42
|
+
* The key is opaque — callers should always use this function
|
|
43
|
+
* rather than constructing keys manually.
|
|
44
|
+
*/
|
|
45
|
+
declare function eventToAllowlistKey(event: GuardEvent): string;
|
|
46
|
+
/**
|
|
47
|
+
* Convert a guard verdict into a GovernanceEvent.
|
|
48
|
+
*
|
|
49
|
+
* The guard evaluation log IS the event stream.
|
|
50
|
+
* No Kafka, no queues — just data flowing from Guard → Simulate.
|
|
51
|
+
*
|
|
52
|
+
* Mapping:
|
|
53
|
+
* ALLOW → "action_allowed"
|
|
54
|
+
* BLOCK → "action_blocked"
|
|
55
|
+
* PAUSE → "action_paused"
|
|
56
|
+
* + semantic type from intent when available
|
|
57
|
+
*/
|
|
58
|
+
declare function verdictToEvent(status: GuardStatus, intent?: string): GovernanceEvent;
|
|
59
|
+
|
|
60
|
+
export { evaluateGuard, eventToAllowlistKey, verdictToEvent };
|
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
evaluateGuard,
|
|
3
3
|
eventToAllowlistKey,
|
|
4
4
|
verdictToEvent
|
|
5
|
-
} from "
|
|
6
|
-
import "
|
|
7
|
-
import "
|
|
5
|
+
} from "../chunk-ZAF6JH23.js";
|
|
6
|
+
import "../chunk-QLPTHTVB.js";
|
|
7
|
+
import "../chunk-QWGCMQQD.js";
|
|
8
8
|
export {
|
|
9
9
|
evaluateGuard,
|
|
10
10
|
eventToAllowlistKey,
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/engine/simulate-engine.ts
|
|
21
|
+
var simulate_engine_exports = {};
|
|
22
|
+
__export(simulate_engine_exports, {
|
|
23
|
+
renderSimulateText: () => renderSimulateText,
|
|
24
|
+
simulateWorld: () => simulateWorld
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(simulate_engine_exports);
|
|
27
|
+
function simulateWorld(world, options = {}) {
|
|
28
|
+
if (!world || !world.world) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
'World definition required. simulateWorld() cannot run without a world.\nLoad one with: loadWorld("./world/") or parseWorldMarkdown(markdown)'
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
const steps = Math.max(1, Math.min(options.steps ?? 1, 50));
|
|
34
|
+
const profileName = options.profile ?? world.world.default_assumption_profile;
|
|
35
|
+
const state = buildInitialState(world.stateSchema, options.stateOverrides);
|
|
36
|
+
for (const outcome of world.outcomes?.computed_outcomes ?? []) {
|
|
37
|
+
if (!(outcome.id in state)) {
|
|
38
|
+
state[outcome.id] = outcome.primary ? 100 : 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const assumptions = resolveAssumptions(world.assumptions, profileName);
|
|
42
|
+
const initialState = { ...state };
|
|
43
|
+
const simulationSteps = [];
|
|
44
|
+
let collapsed = false;
|
|
45
|
+
let collapseStep;
|
|
46
|
+
let collapseRule;
|
|
47
|
+
const sortedRules = [...world.rules].sort((a, b) => a.order - b.order);
|
|
48
|
+
const allEvents = options.events ?? [];
|
|
49
|
+
const eventsByStep = Array.from({ length: steps }, () => []);
|
|
50
|
+
for (let i = 0; i < allEvents.length; i++) {
|
|
51
|
+
const stepIdx = Math.min(i, steps - 1);
|
|
52
|
+
eventsByStep[stepIdx].push(allEvents[i]);
|
|
53
|
+
}
|
|
54
|
+
let totalEventsConsumed = 0;
|
|
55
|
+
for (let stepNum = 1; stepNum <= steps; stepNum++) {
|
|
56
|
+
if (collapsed) break;
|
|
57
|
+
const stepEvents = eventsByStep[stepNum - 1];
|
|
58
|
+
const stepResult = evaluateStep(
|
|
59
|
+
stepNum,
|
|
60
|
+
sortedRules,
|
|
61
|
+
state,
|
|
62
|
+
assumptions,
|
|
63
|
+
world,
|
|
64
|
+
stepEvents
|
|
65
|
+
);
|
|
66
|
+
totalEventsConsumed += stepResult.eventsApplied.length;
|
|
67
|
+
simulationSteps.push(stepResult);
|
|
68
|
+
if (stepResult.collapsed) {
|
|
69
|
+
collapsed = true;
|
|
70
|
+
collapseStep = stepNum;
|
|
71
|
+
collapseRule = stepResult.rulesEvaluated.find((r) => r.collapsed)?.ruleId;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const finalViability = classifyViability(state, world);
|
|
75
|
+
return {
|
|
76
|
+
worldId: world.world.world_id,
|
|
77
|
+
worldName: world.world.name,
|
|
78
|
+
profile: profileName,
|
|
79
|
+
initialState,
|
|
80
|
+
steps: simulationSteps,
|
|
81
|
+
finalState: { ...state },
|
|
82
|
+
finalViability,
|
|
83
|
+
collapsed,
|
|
84
|
+
collapseStep,
|
|
85
|
+
collapseRule,
|
|
86
|
+
eventsConsumed: totalEventsConsumed
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function evaluateStep(stepNum, rules, state, assumptions, world, events = []) {
|
|
90
|
+
const evaluations = [];
|
|
91
|
+
const eventApplications = [];
|
|
92
|
+
let rulesFired = 0;
|
|
93
|
+
let collapsed = false;
|
|
94
|
+
const firedRuleIds = /* @__PURE__ */ new Set();
|
|
95
|
+
for (const evt of events) {
|
|
96
|
+
const application = {
|
|
97
|
+
eventType: evt.type,
|
|
98
|
+
rulesTriggered: [],
|
|
99
|
+
effects: []
|
|
100
|
+
};
|
|
101
|
+
for (const rule of rules) {
|
|
102
|
+
const eventTrigger = rule.triggers.find(
|
|
103
|
+
(t) => t.field === "event" && t.source === "state"
|
|
104
|
+
);
|
|
105
|
+
if (!eventTrigger) continue;
|
|
106
|
+
const matches = evaluateOperator(evt.type, eventTrigger.operator, eventTrigger.value);
|
|
107
|
+
if (!matches) continue;
|
|
108
|
+
application.rulesTriggered.push(rule.id);
|
|
109
|
+
firedRuleIds.add(rule.id);
|
|
110
|
+
for (const effect of rule.effects ?? []) {
|
|
111
|
+
const applied = applyEffect(effect, state);
|
|
112
|
+
if (applied) application.effects.push(applied);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
eventApplications.push(application);
|
|
116
|
+
}
|
|
117
|
+
for (const rule of rules) {
|
|
118
|
+
if (collapsed) {
|
|
119
|
+
evaluations.push({
|
|
120
|
+
ruleId: rule.id,
|
|
121
|
+
label: rule.label,
|
|
122
|
+
triggered: false,
|
|
123
|
+
excluded: true,
|
|
124
|
+
effects: [],
|
|
125
|
+
collapsed: false
|
|
126
|
+
});
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const excluded = rule.exclusive_with ? firedRuleIds.has(rule.exclusive_with) : false;
|
|
130
|
+
if (excluded) {
|
|
131
|
+
evaluations.push({
|
|
132
|
+
ruleId: rule.id,
|
|
133
|
+
label: rule.label,
|
|
134
|
+
triggered: false,
|
|
135
|
+
excluded: true,
|
|
136
|
+
effects: [],
|
|
137
|
+
collapsed: false
|
|
138
|
+
});
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const triggered = evaluateTriggers(rule.triggers, state, assumptions);
|
|
142
|
+
if (!triggered) {
|
|
143
|
+
evaluations.push({
|
|
144
|
+
ruleId: rule.id,
|
|
145
|
+
label: rule.label,
|
|
146
|
+
triggered: false,
|
|
147
|
+
excluded: false,
|
|
148
|
+
effects: [],
|
|
149
|
+
collapsed: false
|
|
150
|
+
});
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
firedRuleIds.add(rule.id);
|
|
154
|
+
rulesFired++;
|
|
155
|
+
const appliedEffects = [];
|
|
156
|
+
for (const effect of rule.effects ?? []) {
|
|
157
|
+
const applied = applyEffect(effect, state);
|
|
158
|
+
if (applied) appliedEffects.push(applied);
|
|
159
|
+
}
|
|
160
|
+
for (const ce of rule.effects_conditional ?? []) {
|
|
161
|
+
const conditionMet = evaluateSingleTrigger(ce.condition, state, assumptions);
|
|
162
|
+
const andMet = ce.and ? evaluateSingleTrigger(ce.and, state, assumptions) : true;
|
|
163
|
+
const orMet = ce.or ? evaluateSingleTrigger(ce.or, state, assumptions) : false;
|
|
164
|
+
const anyMet = ce.condition_any ? ce.condition_any.some((c) => evaluateSingleTrigger(c, state, assumptions)) : false;
|
|
165
|
+
const shouldApply = conditionMet && andMet || ce.or && orMet || ce.condition_any && anyMet;
|
|
166
|
+
if (shouldApply) {
|
|
167
|
+
for (const effect of ce.effects) {
|
|
168
|
+
const applied = applyEffect(effect, state);
|
|
169
|
+
if (applied) appliedEffects.push(applied);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
let ruleCollapsed = false;
|
|
174
|
+
if (rule.collapse_check) {
|
|
175
|
+
const fieldVal = typeof state[rule.collapse_check.field] === "number" ? state[rule.collapse_check.field] : 0;
|
|
176
|
+
if (evaluateOperator(fieldVal, rule.collapse_check.operator, rule.collapse_check.value)) {
|
|
177
|
+
ruleCollapsed = true;
|
|
178
|
+
collapsed = true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (!ruleCollapsed && rule.secondary_check) {
|
|
182
|
+
const fieldVal = typeof state[rule.secondary_check.field] === "number" ? state[rule.secondary_check.field] : 0;
|
|
183
|
+
if (evaluateOperator(fieldVal, rule.secondary_check.operator, rule.secondary_check.value)) {
|
|
184
|
+
ruleCollapsed = true;
|
|
185
|
+
collapsed = true;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
evaluations.push({
|
|
189
|
+
ruleId: rule.id,
|
|
190
|
+
label: rule.label,
|
|
191
|
+
triggered: true,
|
|
192
|
+
excluded: false,
|
|
193
|
+
effects: appliedEffects,
|
|
194
|
+
collapsed: ruleCollapsed,
|
|
195
|
+
collapseField: ruleCollapsed ? rule.collapse_check?.field ?? rule.secondary_check?.field : void 0
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
const viability = classifyViability(state, world);
|
|
199
|
+
return {
|
|
200
|
+
step: stepNum,
|
|
201
|
+
eventsApplied: eventApplications,
|
|
202
|
+
rulesEvaluated: evaluations,
|
|
203
|
+
rulesFired,
|
|
204
|
+
stateAfter: { ...state },
|
|
205
|
+
viability,
|
|
206
|
+
collapsed
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function evaluateTriggers(triggers, state, assumptions) {
|
|
210
|
+
if (!triggers || triggers.length === 0) return true;
|
|
211
|
+
return triggers.every((t) => evaluateSingleTrigger(t, state, assumptions));
|
|
212
|
+
}
|
|
213
|
+
function evaluateSingleTrigger(trigger, state, assumptions) {
|
|
214
|
+
const source = trigger.source === "assumption" ? assumptions : state;
|
|
215
|
+
const fieldValue = source[trigger.field];
|
|
216
|
+
if (fieldValue === void 0) return false;
|
|
217
|
+
return evaluateOperator(fieldValue, trigger.operator, trigger.value);
|
|
218
|
+
}
|
|
219
|
+
function evaluateOperator(fieldValue, operator, conditionValue) {
|
|
220
|
+
switch (operator) {
|
|
221
|
+
case "==":
|
|
222
|
+
return fieldValue === conditionValue;
|
|
223
|
+
case "!=":
|
|
224
|
+
return fieldValue !== conditionValue;
|
|
225
|
+
case ">":
|
|
226
|
+
return typeof fieldValue === "number" && typeof conditionValue === "number" && fieldValue > conditionValue;
|
|
227
|
+
case "<":
|
|
228
|
+
return typeof fieldValue === "number" && typeof conditionValue === "number" && fieldValue < conditionValue;
|
|
229
|
+
case ">=":
|
|
230
|
+
return typeof fieldValue === "number" && typeof conditionValue === "number" && fieldValue >= conditionValue;
|
|
231
|
+
case "<=":
|
|
232
|
+
return typeof fieldValue === "number" && typeof conditionValue === "number" && fieldValue <= conditionValue;
|
|
233
|
+
case "in":
|
|
234
|
+
return Array.isArray(conditionValue) && conditionValue.includes(String(fieldValue));
|
|
235
|
+
default:
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function applyEffect(effect, state) {
|
|
240
|
+
const before = state[effect.target];
|
|
241
|
+
let after;
|
|
242
|
+
switch (effect.operation) {
|
|
243
|
+
case "multiply":
|
|
244
|
+
case "multiply_dynamic": {
|
|
245
|
+
const current = typeof before === "number" ? before : 0;
|
|
246
|
+
const factor = typeof effect.value === "number" ? effect.value : 1;
|
|
247
|
+
after = current * factor;
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
case "add":
|
|
251
|
+
case "add_dynamic": {
|
|
252
|
+
const current = typeof before === "number" ? before : 0;
|
|
253
|
+
const addend = typeof effect.value === "number" ? effect.value : 0;
|
|
254
|
+
after = current + addend;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
case "subtract":
|
|
258
|
+
case "subtract_dynamic": {
|
|
259
|
+
const current = typeof before === "number" ? before : 0;
|
|
260
|
+
const subtrahend = typeof effect.value === "number" ? effect.value : 0;
|
|
261
|
+
after = current - subtrahend;
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
case "set":
|
|
265
|
+
case "set_dynamic":
|
|
266
|
+
after = effect.value;
|
|
267
|
+
break;
|
|
268
|
+
case "set_boolean":
|
|
269
|
+
after = !!effect.value;
|
|
270
|
+
break;
|
|
271
|
+
default:
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
state[effect.target] = after;
|
|
275
|
+
return {
|
|
276
|
+
target: effect.target,
|
|
277
|
+
operation: effect.operation,
|
|
278
|
+
value: effect.value,
|
|
279
|
+
before: before ?? 0,
|
|
280
|
+
after
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function buildInitialState(schema, overrides) {
|
|
284
|
+
const state = {};
|
|
285
|
+
for (const [name, variable] of Object.entries(schema.variables ?? {})) {
|
|
286
|
+
state[name] = variable.default;
|
|
287
|
+
}
|
|
288
|
+
if (overrides) {
|
|
289
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
290
|
+
state[key] = value;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return state;
|
|
294
|
+
}
|
|
295
|
+
function resolveAssumptions(config, profileName) {
|
|
296
|
+
const profile = config.profiles?.[profileName];
|
|
297
|
+
return profile?.parameters ?? {};
|
|
298
|
+
}
|
|
299
|
+
function classifyViability(state, world) {
|
|
300
|
+
const gates = world.gates?.viability_classification ?? [];
|
|
301
|
+
for (const gate of gates) {
|
|
302
|
+
const fieldValue = state[gate.field];
|
|
303
|
+
if (typeof fieldValue !== "number") continue;
|
|
304
|
+
if (evaluateOperator(fieldValue, gate.operator, gate.value)) {
|
|
305
|
+
return gate.status;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return "MODEL_COLLAPSES";
|
|
309
|
+
}
|
|
310
|
+
function renderSimulateText(result) {
|
|
311
|
+
const lines = [];
|
|
312
|
+
lines.push(`SIMULATION: ${result.worldName}`);
|
|
313
|
+
lines.push(`Profile: ${result.profile}`);
|
|
314
|
+
lines.push(`Steps: ${result.steps.length}`);
|
|
315
|
+
lines.push("");
|
|
316
|
+
lines.push("INITIAL STATE");
|
|
317
|
+
for (const [key, value] of Object.entries(result.initialState)) {
|
|
318
|
+
lines.push(` ${key}: ${value}`);
|
|
319
|
+
}
|
|
320
|
+
lines.push("");
|
|
321
|
+
for (const step of result.steps) {
|
|
322
|
+
lines.push(`STEP ${step.step}`);
|
|
323
|
+
if (step.eventsApplied && step.eventsApplied.length > 0) {
|
|
324
|
+
for (const evt of step.eventsApplied) {
|
|
325
|
+
lines.push(` EVENT: ${evt.eventType}`);
|
|
326
|
+
if (evt.rulesTriggered.length > 0) {
|
|
327
|
+
lines.push(` Rules triggered: ${evt.rulesTriggered.join(", ")}`);
|
|
328
|
+
}
|
|
329
|
+
for (const effect of evt.effects) {
|
|
330
|
+
const beforeStr = formatValue(effect.before);
|
|
331
|
+
const afterStr = formatValue(effect.after);
|
|
332
|
+
lines.push(` ${effect.target}: ${beforeStr} -> ${afterStr}`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const fired = step.rulesEvaluated.filter((r) => r.triggered);
|
|
337
|
+
const skipped = step.rulesEvaluated.filter((r) => !r.triggered && !r.excluded);
|
|
338
|
+
const excluded = step.rulesEvaluated.filter((r) => r.excluded);
|
|
339
|
+
if (fired.length === 0) {
|
|
340
|
+
lines.push(" No rules fired (state unchanged)");
|
|
341
|
+
} else {
|
|
342
|
+
for (const rule of fired) {
|
|
343
|
+
lines.push(` FIRED: ${rule.label}`);
|
|
344
|
+
for (const effect of rule.effects) {
|
|
345
|
+
const beforeStr = formatValue(effect.before);
|
|
346
|
+
const afterStr = formatValue(effect.after);
|
|
347
|
+
lines.push(` ${effect.target}: ${beforeStr} -> ${afterStr}`);
|
|
348
|
+
}
|
|
349
|
+
if (rule.collapsed) {
|
|
350
|
+
lines.push(` COLLAPSE on ${rule.collapseField}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (excluded.length > 0) {
|
|
355
|
+
lines.push(` Excluded: ${excluded.map((r) => r.label).join(", ")}`);
|
|
356
|
+
}
|
|
357
|
+
lines.push(` Viability: ${step.viability}`);
|
|
358
|
+
if (step.collapsed) {
|
|
359
|
+
lines.push(" ** MODEL COLLAPSED **");
|
|
360
|
+
}
|
|
361
|
+
lines.push("");
|
|
362
|
+
}
|
|
363
|
+
lines.push("FINAL STATE");
|
|
364
|
+
for (const [key, value] of Object.entries(result.finalState)) {
|
|
365
|
+
const initial = result.initialState[key];
|
|
366
|
+
const changed = initial !== value;
|
|
367
|
+
const marker = changed ? " (changed)" : "";
|
|
368
|
+
lines.push(` ${key}: ${formatValue(value)}${marker}`);
|
|
369
|
+
}
|
|
370
|
+
lines.push("");
|
|
371
|
+
if (result.eventsConsumed > 0) {
|
|
372
|
+
lines.push(`EVENTS CONSUMED: ${result.eventsConsumed}`);
|
|
373
|
+
}
|
|
374
|
+
lines.push(`VIABILITY: ${result.finalViability}`);
|
|
375
|
+
if (result.collapsed) {
|
|
376
|
+
lines.push(`COLLAPSED at step ${result.collapseStep} (rule: ${result.collapseRule})`);
|
|
377
|
+
}
|
|
378
|
+
return lines.join("\n");
|
|
379
|
+
}
|
|
380
|
+
function formatValue(v) {
|
|
381
|
+
if (typeof v === "number") {
|
|
382
|
+
return Number.isInteger(v) ? String(v) : v.toFixed(2);
|
|
383
|
+
}
|
|
384
|
+
return String(v);
|
|
385
|
+
}
|
|
386
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
387
|
+
0 && (module.exports = {
|
|
388
|
+
renderSimulateText,
|
|
389
|
+
simulateWorld
|
|
390
|
+
});
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { GovernanceEvent, ViabilityStatus, WorldDefinition } from '../types.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Simulate Engine — Deterministic State Evolution (Reference Simulator)
|
|
5
|
+
*
|
|
6
|
+
* Pure function: (world, options) → SimulationResult
|
|
7
|
+
*
|
|
8
|
+
* This is NeuroVerse's REFERENCE SIMULATOR — one way to model how a world
|
|
9
|
+
* evolves over time. It is NOT the governance engine.
|
|
10
|
+
*
|
|
11
|
+
* simulateWorld() ≠ evaluateGuard()
|
|
12
|
+
*
|
|
13
|
+
* evaluateGuard() — Runtime enforcement. Decides if an action is allowed.
|
|
14
|
+
* Includes safety layer, role checks, plan enforcement,
|
|
15
|
+
* kernel rules, level constraints. Use for governance.
|
|
16
|
+
*
|
|
17
|
+
* simulateWorld() — State evolution modeling. Evaluates rule triggers,
|
|
18
|
+
* applies effects, tracks viability over N steps.
|
|
19
|
+
* Use for scenario planning and what-if analysis.
|
|
20
|
+
*
|
|
21
|
+
* World files (.nv-world.md) are portable — they define rules, roles, and
|
|
22
|
+
* constraints that can be consumed by any simulator or governance engine.
|
|
23
|
+
* This simulator is a reference implementation, not the only interpreter.
|
|
24
|
+
*
|
|
25
|
+
* Supports:
|
|
26
|
+
* - Single-step evaluation (default)
|
|
27
|
+
* - Multi-step iteration (--steps N)
|
|
28
|
+
* - State overrides (start from non-default values)
|
|
29
|
+
* - Assumption profile selection
|
|
30
|
+
* - Collapse detection (early termination)
|
|
31
|
+
*
|
|
32
|
+
* INVARIANTS:
|
|
33
|
+
* - Deterministic: same world + same options → same result.
|
|
34
|
+
* - Zero network calls. Zero LLM calls. Zero async.
|
|
35
|
+
* - Every rule evaluation is recorded in the trace.
|
|
36
|
+
* - World definition is REQUIRED — no world, no simulation.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
interface SimulateOptions {
|
|
40
|
+
/** Number of simulation steps (default: 1) */
|
|
41
|
+
steps?: number;
|
|
42
|
+
/** State variable overrides (start values) */
|
|
43
|
+
stateOverrides?: Record<string, string | number | boolean>;
|
|
44
|
+
/** Assumption profile to use (default: world default) */
|
|
45
|
+
profile?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Governance events to inject into the simulation.
|
|
48
|
+
* Events are applied before state-driven rules each step.
|
|
49
|
+
* This is the bridge: Guard → Events → Simulate → State Evolution.
|
|
50
|
+
*
|
|
51
|
+
* Events are distributed across steps (round-robin) or all applied to step 1
|
|
52
|
+
* if there are fewer steps than events.
|
|
53
|
+
*/
|
|
54
|
+
events?: GovernanceEvent[];
|
|
55
|
+
}
|
|
56
|
+
interface SimulationResult {
|
|
57
|
+
worldId: string;
|
|
58
|
+
worldName: string;
|
|
59
|
+
profile: string;
|
|
60
|
+
initialState: Record<string, string | number | boolean>;
|
|
61
|
+
steps: SimulationStep[];
|
|
62
|
+
finalState: Record<string, string | number | boolean>;
|
|
63
|
+
finalViability: ViabilityStatus;
|
|
64
|
+
collapsed: boolean;
|
|
65
|
+
collapseStep?: number;
|
|
66
|
+
collapseRule?: string;
|
|
67
|
+
/** Total events consumed during simulation */
|
|
68
|
+
eventsConsumed: number;
|
|
69
|
+
}
|
|
70
|
+
interface SimulationStep {
|
|
71
|
+
step: number;
|
|
72
|
+
/** Events applied during this step (before rules) */
|
|
73
|
+
eventsApplied: EventApplication[];
|
|
74
|
+
rulesEvaluated: RuleEvaluation[];
|
|
75
|
+
rulesFired: number;
|
|
76
|
+
stateAfter: Record<string, string | number | boolean>;
|
|
77
|
+
viability: ViabilityStatus;
|
|
78
|
+
collapsed: boolean;
|
|
79
|
+
}
|
|
80
|
+
/** Record of an event applied during simulation */
|
|
81
|
+
interface EventApplication {
|
|
82
|
+
eventType: string;
|
|
83
|
+
rulesTriggered: string[];
|
|
84
|
+
effects: AppliedEffect[];
|
|
85
|
+
}
|
|
86
|
+
interface RuleEvaluation {
|
|
87
|
+
ruleId: string;
|
|
88
|
+
label: string;
|
|
89
|
+
triggered: boolean;
|
|
90
|
+
excluded: boolean;
|
|
91
|
+
effects: AppliedEffect[];
|
|
92
|
+
collapsed: boolean;
|
|
93
|
+
collapseField?: string;
|
|
94
|
+
}
|
|
95
|
+
interface AppliedEffect {
|
|
96
|
+
target: string;
|
|
97
|
+
operation: string;
|
|
98
|
+
value: number | boolean | string;
|
|
99
|
+
before: string | number | boolean;
|
|
100
|
+
after: string | number | boolean;
|
|
101
|
+
}
|
|
102
|
+
declare function simulateWorld(world: WorldDefinition, options?: SimulateOptions): SimulationResult;
|
|
103
|
+
declare function renderSimulateText(result: SimulationResult): string;
|
|
104
|
+
|
|
105
|
+
export { type AppliedEffect, type EventApplication, type RuleEvaluation, type SimulateOptions, type SimulationResult, type SimulationStep, renderSimulateText, simulateWorld };
|