simfile 0.0.1
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 +143 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +348 -0
- package/dist/coverage/index.d.ts +2 -0
- package/dist/coverage/index.d.ts.map +1 -0
- package/dist/coverage/index.js +1 -0
- package/dist/coverage/matrix.d.ts +21 -0
- package/dist/coverage/matrix.d.ts.map +1 -0
- package/dist/coverage/matrix.js +173 -0
- package/dist/coverage/render.d.ts +3 -0
- package/dist/coverage/render.d.ts.map +1 -0
- package/dist/coverage/render.js +26 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/kernel/duration.d.ts +9 -0
- package/dist/kernel/duration.d.ts.map +1 -0
- package/dist/kernel/duration.js +44 -0
- package/dist/kernel/index.d.ts +4 -0
- package/dist/kernel/index.d.ts.map +1 -0
- package/dist/kernel/index.js +3 -0
- package/dist/kernel/range.d.ts +6 -0
- package/dist/kernel/range.d.ts.map +1 -0
- package/dist/kernel/range.js +16 -0
- package/dist/kernel/stochastic.d.ts +10 -0
- package/dist/kernel/stochastic.d.ts.map +1 -0
- package/dist/kernel/stochastic.js +25 -0
- package/dist/ledger/index.d.ts +4 -0
- package/dist/ledger/index.d.ts.map +1 -0
- package/dist/ledger/index.js +3 -0
- package/dist/ledger/markers.d.ts +46 -0
- package/dist/ledger/markers.d.ts.map +1 -0
- package/dist/ledger/markers.js +108 -0
- package/dist/ledger/stable.d.ts +65 -0
- package/dist/ledger/stable.d.ts.map +1 -0
- package/dist/ledger/stable.js +78 -0
- package/dist/ledger/validation.d.ts +16 -0
- package/dist/ledger/validation.d.ts.map +1 -0
- package/dist/ledger/validation.js +127 -0
- package/dist/moltnet/index.d.ts +3 -0
- package/dist/moltnet/index.d.ts.map +1 -0
- package/dist/moltnet/index.js +2 -0
- package/dist/moltnet/transcript-export.d.ts +34 -0
- package/dist/moltnet/transcript-export.d.ts.map +1 -0
- package/dist/moltnet/transcript-export.js +68 -0
- package/dist/moltnet/world-participant.d.ts +77 -0
- package/dist/moltnet/world-participant.d.ts.map +1 -0
- package/dist/moltnet/world-participant.js +221 -0
- package/dist/observe/artifacts.d.ts +16 -0
- package/dist/observe/artifacts.d.ts.map +1 -0
- package/dist/observe/artifacts.js +31 -0
- package/dist/observe/causalStreams.d.ts +19 -0
- package/dist/observe/causalStreams.d.ts.map +1 -0
- package/dist/observe/causalStreams.js +38 -0
- package/dist/observe/compute.d.ts +17 -0
- package/dist/observe/compute.d.ts.map +1 -0
- package/dist/observe/compute.js +97 -0
- package/dist/observe/index.d.ts +11 -0
- package/dist/observe/index.d.ts.map +1 -0
- package/dist/observe/index.js +10 -0
- package/dist/observe/manifest.d.ts +79 -0
- package/dist/observe/manifest.d.ts.map +1 -0
- package/dist/observe/manifest.js +87 -0
- package/dist/observe/memoryBanks.d.ts +38 -0
- package/dist/observe/memoryBanks.d.ts.map +1 -0
- package/dist/observe/memoryBanks.js +86 -0
- package/dist/observe/observe.d.ts +32 -0
- package/dist/observe/observe.d.ts.map +1 -0
- package/dist/observe/observe.js +73 -0
- package/dist/observe/report.d.ts +165 -0
- package/dist/observe/report.d.ts.map +1 -0
- package/dist/observe/report.js +138 -0
- package/dist/observe/seedSpread.d.ts +49 -0
- package/dist/observe/seedSpread.d.ts.map +1 -0
- package/dist/observe/seedSpread.js +262 -0
- package/dist/observe/seedSpreadArtifacts.d.ts +49 -0
- package/dist/observe/seedSpreadArtifacts.d.ts.map +1 -0
- package/dist/observe/seedSpreadArtifacts.js +118 -0
- package/dist/observe/spreadMatcher.d.ts +45 -0
- package/dist/observe/spreadMatcher.d.ts.map +1 -0
- package/dist/observe/spreadMatcher.js +124 -0
- package/dist/report/index.d.ts +4 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +3 -0
- package/dist/report/probeArtifact.d.ts +26 -0
- package/dist/report/probeArtifact.d.ts.map +1 -0
- package/dist/report/probeArtifact.js +119 -0
- package/dist/report/probes.d.ts +52 -0
- package/dist/report/probes.d.ts.map +1 -0
- package/dist/report/probes.js +164 -0
- package/dist/report/score.d.ts +27 -0
- package/dist/report/score.d.ts.map +1 -0
- package/dist/report/score.js +14 -0
- package/dist/report/transcripts.d.ts +12 -0
- package/dist/report/transcripts.d.ts.map +1 -0
- package/dist/report/transcripts.js +17 -0
- package/dist/runtime/causal-fixture.d.ts +26 -0
- package/dist/runtime/causal-fixture.d.ts.map +1 -0
- package/dist/runtime/causal-fixture.js +36 -0
- package/dist/runtime/clock.d.ts +25 -0
- package/dist/runtime/clock.d.ts.map +1 -0
- package/dist/runtime/clock.js +63 -0
- package/dist/runtime/condition.d.ts +55 -0
- package/dist/runtime/condition.d.ts.map +1 -0
- package/dist/runtime/condition.js +122 -0
- package/dist/runtime/emit-causal-fixture.d.ts +2 -0
- package/dist/runtime/emit-causal-fixture.d.ts.map +1 -0
- package/dist/runtime/emit-causal-fixture.js +45 -0
- package/dist/runtime/expression.d.ts +11 -0
- package/dist/runtime/expression.d.ts.map +1 -0
- package/dist/runtime/expression.js +305 -0
- package/dist/runtime/numeric.d.ts +7 -0
- package/dist/runtime/numeric.d.ts.map +1 -0
- package/dist/runtime/numeric.js +11 -0
- package/dist/runtime/rule-actions.d.ts +5 -0
- package/dist/runtime/rule-actions.d.ts.map +1 -0
- package/dist/runtime/rule-actions.js +82 -0
- package/dist/runtime/run-record.d.ts +73 -0
- package/dist/runtime/run-record.d.ts.map +1 -0
- package/dist/runtime/run-record.js +179 -0
- package/dist/runtime/step-tick.d.ts +43 -0
- package/dist/runtime/step-tick.d.ts.map +1 -0
- package/dist/runtime/step-tick.js +177 -0
- package/dist/runtime/trace-compile.d.ts +66 -0
- package/dist/runtime/trace-compile.d.ts.map +1 -0
- package/dist/runtime/trace-compile.js +157 -0
- package/dist/runtime/trace-export.d.ts +5 -0
- package/dist/runtime/trace-export.d.ts.map +1 -0
- package/dist/runtime/trace-export.js +4 -0
- package/dist/runtime/trace-run.d.ts +15 -0
- package/dist/runtime/trace-run.d.ts.map +1 -0
- package/dist/runtime/trace-run.js +92 -0
- package/dist/runtime/trace.d.ts +10 -0
- package/dist/runtime/trace.d.ts.map +1 -0
- package/dist/runtime/trace.js +9 -0
- package/dist/runtime/types.d.ts +61 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime/viewer-trace.d.ts +64 -0
- package/dist/runtime/viewer-trace.d.ts.map +1 -0
- package/dist/runtime/viewer-trace.js +164 -0
- package/dist/runtime/world-act.d.ts +55 -0
- package/dist/runtime/world-act.d.ts.map +1 -0
- package/dist/runtime/world-act.js +156 -0
- package/dist/schema/binding.d.ts +23 -0
- package/dist/schema/binding.d.ts.map +1 -0
- package/dist/schema/binding.js +249 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +4 -0
- package/dist/schema/model.d.ts +244 -0
- package/dist/schema/model.d.ts.map +1 -0
- package/dist/schema/model.js +222 -0
- package/dist/schema/parse.d.ts +10 -0
- package/dist/schema/parse.d.ts.map +1 -0
- package/dist/schema/parse.js +15 -0
- package/dist/schema/semantic.d.ts +3 -0
- package/dist/schema/semantic.d.ts.map +1 -0
- package/dist/schema/semantic.js +135 -0
- package/dist/sims/composeRunManifest.d.ts +54 -0
- package/dist/sims/composeRunManifest.d.ts.map +1 -0
- package/dist/sims/composeRunManifest.js +40 -0
- package/dist/sims/composedJungianSimDriver.d.ts +50 -0
- package/dist/sims/composedJungianSimDriver.d.ts.map +1 -0
- package/dist/sims/composedJungianSimDriver.js +199 -0
- package/dist/sims/composedOfficeSimDriver.d.ts +53 -0
- package/dist/sims/composedOfficeSimDriver.d.ts.map +1 -0
- package/dist/sims/composedOfficeSimDriver.js +162 -0
- package/dist/sims/exchangeWait.d.ts +56 -0
- package/dist/sims/exchangeWait.d.ts.map +1 -0
- package/dist/sims/exchangeWait.js +66 -0
- package/dist/sims/index.d.ts +14 -0
- package/dist/sims/index.d.ts.map +1 -0
- package/dist/sims/index.js +13 -0
- package/dist/sims/moltnetRoomClient.d.ts +47 -0
- package/dist/sims/moltnetRoomClient.d.ts.map +1 -0
- package/dist/sims/moltnetRoomClient.js +41 -0
- package/dist/sims/poll.d.ts +19 -0
- package/dist/sims/poll.d.ts.map +1 -0
- package/dist/sims/poll.js +23 -0
- package/dist/sims/spawnfileCli.d.ts +49 -0
- package/dist/sims/spawnfileCli.d.ts.map +1 -0
- package/dist/sims/spawnfileCli.js +90 -0
- package/dist/sims/spawnfileReceipts.d.ts +76 -0
- package/dist/sims/spawnfileReceipts.d.ts.map +1 -0
- package/dist/sims/spawnfileReceipts.js +107 -0
- package/dist/sims/worldDrivenOfficeSimDriver.d.ts +59 -0
- package/dist/sims/worldDrivenOfficeSimDriver.d.ts.map +1 -0
- package/dist/sims/worldDrivenOfficeSimDriver.js +182 -0
- package/dist/sims/worldLedgerWriter.d.ts +32 -0
- package/dist/sims/worldLedgerWriter.d.ts.map +1 -0
- package/dist/sims/worldLedgerWriter.js +39 -0
- package/dist/sims/worldSeedLint.d.ts +42 -0
- package/dist/sims/worldSeedLint.d.ts.map +1 -0
- package/dist/sims/worldSeedLint.js +73 -0
- package/dist/sims/worldTickIngest.d.ts +27 -0
- package/dist/sims/worldTickIngest.d.ts.map +1 -0
- package/dist/sims/worldTickIngest.js +35 -0
- package/dist/sims/worldTickLoop.d.ts +64 -0
- package/dist/sims/worldTickLoop.d.ts.map +1 -0
- package/dist/sims/worldTickLoop.js +122 -0
- package/dist/view/engineProvenance.d.ts +46 -0
- package/dist/view/engineProvenance.d.ts.map +1 -0
- package/dist/view/engineProvenance.js +76 -0
- package/dist/view/index.d.ts +14 -0
- package/dist/view/index.d.ts.map +1 -0
- package/dist/view/index.js +107 -0
- package/dist/view/membranes.d.ts +14 -0
- package/dist/view/membranes.d.ts.map +1 -0
- package/dist/view/membranes.js +127 -0
- package/dist/view/runDetect.d.ts +2 -0
- package/dist/view/runDetect.d.ts.map +1 -0
- package/dist/view/runDetect.js +47 -0
- package/dist/view/runRawArtifacts.d.ts +48 -0
- package/dist/view/runRawArtifacts.d.ts.map +1 -0
- package/dist/view/runRawArtifacts.js +143 -0
- package/dist/view/runTimeline.d.ts +24 -0
- package/dist/view/runTimeline.d.ts.map +1 -0
- package/dist/view/runTimeline.js +204 -0
- package/dist/view/runTimelineRecords.d.ts +42 -0
- package/dist/view/runTimelineRecords.d.ts.map +1 -0
- package/dist/view/runTimelineRecords.js +244 -0
- package/dist/view/runTimelineRefs.d.ts +27 -0
- package/dist/view/runTimelineRefs.d.ts.map +1 -0
- package/dist/view/runTimelineRefs.js +31 -0
- package/dist/view/runTimelineTypes.d.ts +99 -0
- package/dist/view/runTimelineTypes.d.ts.map +1 -0
- package/dist/view/runTimelineTypes.js +1 -0
- package/dist/view/runViewModel.d.ts +21 -0
- package/dist/view/runViewModel.d.ts.map +1 -0
- package/dist/view/runViewModel.js +66 -0
- package/dist/view/runViewModelCompute.d.ts +24 -0
- package/dist/view/runViewModelCompute.d.ts.map +1 -0
- package/dist/view/runViewModelCompute.js +157 -0
- package/dist/view/runViewModelTypes.d.ts +177 -0
- package/dist/view/runViewModelTypes.d.ts.map +1 -0
- package/dist/view/runViewModelTypes.js +1 -0
- package/dist/view/runWorldTrace.d.ts +97 -0
- package/dist/view/runWorldTrace.d.ts.map +1 -0
- package/dist/view/runWorldTrace.js +88 -0
- package/dist/view/server.d.ts +12 -0
- package/dist/view/server.d.ts.map +1 -0
- package/dist/view/server.js +306 -0
- package/package.json +65 -0
- package/web/dist/assets/index-CJHLjfsG.js +49 -0
- package/web/dist/assets/index-DJOsPsU8.css +1 -0
- package/web/dist/index.html +13 -0
- package/web/dist/models/AnimatedMushnub.glb +0 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { parseDurationMs } from "../kernel/duration.js";
|
|
2
|
+
import { attachVariablesToEventOccurrences, buildEventOccurrences, buildSampleOccurrences, normalizeProbeArtifact } from "./probeArtifact.js";
|
|
3
|
+
const eventAtomMatch = (event, atom) => {
|
|
4
|
+
if (event.kind !== atom.event) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
if (atom.target !== undefined && atom.target !== event.target) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
if (atom.actor !== undefined && atom.actor !== event.actor) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
if (atom.scope !== undefined && atom.scope !== event.scope) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
return true;
|
|
17
|
+
};
|
|
18
|
+
const holdKey = (node) => `${node.variable}:${node.above ?? ""}:${node.below ?? ""}:${node.for ?? ""}`;
|
|
19
|
+
const matchVariableAtom = (node, occurrence, holdState) => {
|
|
20
|
+
const value = occurrence.variables?.[node.variable];
|
|
21
|
+
const above = node.above ?? -Infinity;
|
|
22
|
+
const below = node.below ?? Infinity;
|
|
23
|
+
const passesWindow = value !== undefined && Number.isFinite(value) && value > above && value < below;
|
|
24
|
+
if (node.for === undefined) {
|
|
25
|
+
return passesWindow;
|
|
26
|
+
}
|
|
27
|
+
const key = holdKey(node);
|
|
28
|
+
if (!passesWindow || occurrence.simTime === undefined) {
|
|
29
|
+
holdState.startTimeByCondition.delete(key);
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const started = holdState.startTimeByCondition.get(key);
|
|
33
|
+
if (started === undefined) {
|
|
34
|
+
holdState.startTimeByCondition.set(key, occurrence.simTime);
|
|
35
|
+
return parseDurationMs(node.for) <= 0;
|
|
36
|
+
}
|
|
37
|
+
return (occurrence.simTime - started) * 1_000 >= parseDurationMs(node.for);
|
|
38
|
+
};
|
|
39
|
+
const nodeHasEventAtom = (node) => {
|
|
40
|
+
if ("event" in node) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if ("all" in node) {
|
|
44
|
+
return node.all.some(nodeHasEventAtom);
|
|
45
|
+
}
|
|
46
|
+
if ("any" in node) {
|
|
47
|
+
return node.any.some(nodeHasEventAtom);
|
|
48
|
+
}
|
|
49
|
+
if ("not" in node) {
|
|
50
|
+
return nodeHasEventAtom(node.not);
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
};
|
|
54
|
+
const matchesNode = (node, occurrence, holdState) => {
|
|
55
|
+
if ("all" in node) {
|
|
56
|
+
return node.all.every((child) => matchesNode(child, occurrence, holdState));
|
|
57
|
+
}
|
|
58
|
+
if ("any" in node) {
|
|
59
|
+
return node.any.some((child) => matchesNode(child, occurrence, holdState));
|
|
60
|
+
}
|
|
61
|
+
if ("not" in node) {
|
|
62
|
+
return !matchesNode(node.not, occurrence, holdState);
|
|
63
|
+
}
|
|
64
|
+
if ("event" in node) {
|
|
65
|
+
return occurrence.event ? eventAtomMatch(occurrence.event, node) : false;
|
|
66
|
+
}
|
|
67
|
+
if ("phase" in node) {
|
|
68
|
+
return occurrence.phase === node.phase;
|
|
69
|
+
}
|
|
70
|
+
return matchVariableAtom(node, occurrence, holdState);
|
|
71
|
+
};
|
|
72
|
+
const matchingOccurrences = (node, occurrences) => {
|
|
73
|
+
const holdState = { startTimeByCondition: new Map() };
|
|
74
|
+
return occurrences.filter((occurrence) => matchesNode(node, occurrence, holdState));
|
|
75
|
+
};
|
|
76
|
+
const filterWithAfter = (matches, afterMatches, probe) => {
|
|
77
|
+
if (probe.after === undefined) {
|
|
78
|
+
return [...matches];
|
|
79
|
+
}
|
|
80
|
+
if (probe.within === undefined) {
|
|
81
|
+
throw new Error("within is required when after is set");
|
|
82
|
+
}
|
|
83
|
+
const withinMs = parseDurationMs(probe.within);
|
|
84
|
+
return matches.filter((match) => {
|
|
85
|
+
if (match.simTime === undefined) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
const matchSimTime = match.simTime;
|
|
89
|
+
const matchTimeMs = matchSimTime * 1_000;
|
|
90
|
+
return afterMatches.some((afterMatch) => {
|
|
91
|
+
if (afterMatch.simTime === undefined || afterMatch.simTime >= matchSimTime) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
return matchTimeMs - (afterMatch.simTime * 1_000) <= withinMs;
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
const parseExpectation = (expect) => {
|
|
99
|
+
if ("at_least" in expect) {
|
|
100
|
+
if (!Number.isInteger(expect.at_least) || expect.at_least < 0) {
|
|
101
|
+
throw new Error("expect.at_least must be a non-negative integer");
|
|
102
|
+
}
|
|
103
|
+
return { mode: "at_least", value: expect.at_least };
|
|
104
|
+
}
|
|
105
|
+
if ("at_most" in expect) {
|
|
106
|
+
if (!Number.isInteger(expect.at_most) || expect.at_most < 0) {
|
|
107
|
+
throw new Error("expect.at_most must be a non-negative integer");
|
|
108
|
+
}
|
|
109
|
+
return { mode: "at_most", value: expect.at_most };
|
|
110
|
+
}
|
|
111
|
+
if ("always" in expect) {
|
|
112
|
+
return { mode: "always" };
|
|
113
|
+
}
|
|
114
|
+
if ("at_end" in expect) {
|
|
115
|
+
return { mode: "at_end" };
|
|
116
|
+
}
|
|
117
|
+
throw new Error("unsupported expect mode");
|
|
118
|
+
};
|
|
119
|
+
const uniqueEvidence = (occurrences) => {
|
|
120
|
+
const seen = new Set();
|
|
121
|
+
const evidence = [];
|
|
122
|
+
occurrences.forEach((occurrence) => {
|
|
123
|
+
if (seen.has(occurrence.evidenceId)) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
seen.add(occurrence.evidenceId);
|
|
127
|
+
evidence.push(occurrence.evidenceId);
|
|
128
|
+
});
|
|
129
|
+
return evidence;
|
|
130
|
+
};
|
|
131
|
+
const selectOccurrences = (node, eventOccurrences, sampleOccurrences) => (nodeHasEventAtom(node) ? eventOccurrences : sampleOccurrences);
|
|
132
|
+
export const evaluateProbe = (probeId, artifactOrEvents, probe) => {
|
|
133
|
+
const artifact = normalizeProbeArtifact(artifactOrEvents);
|
|
134
|
+
const sampleOccurrences = buildSampleOccurrences(artifact.events, artifact.samples ?? []);
|
|
135
|
+
const eventOccurrences = attachVariablesToEventOccurrences(buildEventOccurrences(artifact.events), sampleOccurrences);
|
|
136
|
+
const baseOccurrences = selectOccurrences(probe.when, eventOccurrences, sampleOccurrences);
|
|
137
|
+
const whenMatches = matchingOccurrences(probe.when, baseOccurrences);
|
|
138
|
+
const afterMatches = probe.after === undefined
|
|
139
|
+
? []
|
|
140
|
+
: matchingOccurrences(probe.after, selectOccurrences(probe.after, eventOccurrences, sampleOccurrences));
|
|
141
|
+
const matched = filterWithAfter(whenMatches, afterMatches, probe);
|
|
142
|
+
const count = matched.length;
|
|
143
|
+
const expectation = parseExpectation(probe.expect);
|
|
144
|
+
const evidence = uniqueEvidence(matched);
|
|
145
|
+
let passed = false;
|
|
146
|
+
if (expectation.mode === "at_least") {
|
|
147
|
+
passed = count >= expectation.value;
|
|
148
|
+
}
|
|
149
|
+
else if (expectation.mode === "at_most") {
|
|
150
|
+
passed = count <= expectation.value;
|
|
151
|
+
}
|
|
152
|
+
else if (expectation.mode === "always") {
|
|
153
|
+
passed = baseOccurrences.length > 0 && count === baseOccurrences.length;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
passed = matched.length > 0 && matched[matched.length - 1]?.evidenceId === baseOccurrences.at(-1)?.evidenceId;
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
probeId,
|
|
160
|
+
passed,
|
|
161
|
+
evidence,
|
|
162
|
+
count
|
|
163
|
+
};
|
|
164
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { LedgerEvent } from "../ledger/markers.js";
|
|
2
|
+
/**
|
|
3
|
+
* Genre-neutral scored-task inputs: which actor's world.act on which target
|
|
4
|
+
* variable counts as the submission, and which rule's firing counts as the
|
|
5
|
+
* mechanical proof of correctness. Callers supply the ids; this module names
|
|
6
|
+
* no fixture, world, or setting of its own.
|
|
7
|
+
*/
|
|
8
|
+
export interface ScoreSingleSubmissionInput {
|
|
9
|
+
actor: string;
|
|
10
|
+
target: string;
|
|
11
|
+
rule: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ScoreSingleSubmissionResult {
|
|
14
|
+
score: 0 | 1;
|
|
15
|
+
submissions: number;
|
|
16
|
+
ruleFirings: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Scores a single-submission scored task from the ledger alone. `submissions`
|
|
20
|
+
* counts `world.act` events by `(actor, target)`; `ruleFirings` counts
|
|
21
|
+
* `rule.fired` events by `actor === rule`. `score` is 1 iff both are exactly
|
|
22
|
+
* 1 — one accepted submission, mechanically proven correct by the paired
|
|
23
|
+
* rule firing. Two accepted acts (a resubmission) scores 0 even if the rule
|
|
24
|
+
* fired, by design: it is discipline pressure, not a scoring bug.
|
|
25
|
+
*/
|
|
26
|
+
export declare const scoreSingleSubmission: (events: readonly LedgerEvent[], input: ScoreSingleSubmissionInput) => ScoreSingleSubmissionResult;
|
|
27
|
+
//# sourceMappingURL=score.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../../src/report/score.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,SAAS,WAAW,EAAE,EAC9B,OAAO,0BAA0B,KAChC,2BAYF,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scores a single-submission scored task from the ledger alone. `submissions`
|
|
3
|
+
* counts `world.act` events by `(actor, target)`; `ruleFirings` counts
|
|
4
|
+
* `rule.fired` events by `actor === rule`. `score` is 1 iff both are exactly
|
|
5
|
+
* 1 — one accepted submission, mechanically proven correct by the paired
|
|
6
|
+
* rule firing. Two accepted acts (a resubmission) scores 0 even if the rule
|
|
7
|
+
* fired, by design: it is discipline pressure, not a scoring bug.
|
|
8
|
+
*/
|
|
9
|
+
export const scoreSingleSubmission = (events, input) => {
|
|
10
|
+
const submissions = events.filter((event) => event.kind === "world.act" && event.actor === input.actor && event.target === input.target).length;
|
|
11
|
+
const ruleFirings = events.filter((event) => event.kind === "rule.fired" && event.actor === input.rule).length;
|
|
12
|
+
const score = submissions === 1 && ruleFirings === 1 ? 1 : 0;
|
|
13
|
+
return { score, submissions, ruleFirings };
|
|
14
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type ReportTranscriptSource = "harness-derived" | "moltnet-exported";
|
|
2
|
+
export interface ReportTranscriptSourceArtifact {
|
|
3
|
+
source?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface TranscriptAcceptanceResult {
|
|
6
|
+
accepted: boolean;
|
|
7
|
+
reason?: string;
|
|
8
|
+
required_source: "moltnet-exported";
|
|
9
|
+
source?: ReportTranscriptSource | "unknown";
|
|
10
|
+
}
|
|
11
|
+
export declare const evaluateTranscriptAcceptance: (artifact?: ReportTranscriptSourceArtifact) => TranscriptAcceptanceResult;
|
|
12
|
+
//# sourceMappingURL=transcripts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcripts.d.ts","sourceRoot":"","sources":["../../src/report/transcripts.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAE5E,MAAM,WAAW,8BAA8B;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,kBAAkB,CAAC;IACpC,MAAM,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;CAC7C;AAID,eAAO,MAAM,4BAA4B,GACvC,WAAW,8BAA8B,KACxC,0BAgBF,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const acceptedSource = "moltnet-exported";
|
|
2
|
+
export const evaluateTranscriptAcceptance = (artifact) => {
|
|
3
|
+
if (artifact?.source === acceptedSource) {
|
|
4
|
+
return {
|
|
5
|
+
accepted: true,
|
|
6
|
+
required_source: acceptedSource,
|
|
7
|
+
source: acceptedSource
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
const source = artifact?.source === "harness-derived" ? artifact.source : "unknown";
|
|
11
|
+
return {
|
|
12
|
+
accepted: false,
|
|
13
|
+
reason: "live simulation acceptance requires a moltnet-exported transcript",
|
|
14
|
+
required_source: acceptedSource,
|
|
15
|
+
source
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { CAUSAL_ENVELOPE_VERSION, type CausalEmitter } from "../ledger/stable.js";
|
|
2
|
+
import type { RuntimeTraceEvent } from "./types.js";
|
|
3
|
+
export interface CausalFixtureRecord {
|
|
4
|
+
version: typeof CAUSAL_ENVELOPE_VERSION;
|
|
5
|
+
run_id: string;
|
|
6
|
+
event_id: string;
|
|
7
|
+
emitter: CausalEmitter;
|
|
8
|
+
type: string;
|
|
9
|
+
principal_id: string;
|
|
10
|
+
recorded_at: string;
|
|
11
|
+
cause_event_ids: string[];
|
|
12
|
+
payload: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Maps a runtime trace event (simfile's native ledger envelope) onto the
|
|
16
|
+
* noopolis.causal-event.v1 wire shape defined by root's
|
|
17
|
+
* `specs/causal-event.v1.schema.json` (referenced for shape parity, never
|
|
18
|
+
* imported — simfile keeps its own native TS type per the type-sharing rule).
|
|
19
|
+
*
|
|
20
|
+
* This is B92's real entry point: root's conformance harness invokes
|
|
21
|
+
* `npm run emit-causal-fixture` in this package and validates the printed
|
|
22
|
+
* JSONL, line by line, against the schema plus payload minimums.
|
|
23
|
+
*/
|
|
24
|
+
export declare const toCausalFixtureRecord: (event: RuntimeTraceEvent) => CausalFixtureRecord;
|
|
25
|
+
export declare const buildCausalFixtureRecords: (events: readonly RuntimeTraceEvent[]) => CausalFixtureRecord[];
|
|
26
|
+
//# sourceMappingURL=causal-fixture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"causal-fixture.d.ts","sourceRoot":"","sources":["../../src/runtime/causal-fixture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAA2E,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC3J,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,uBAAuB,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,aAAa,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAgBD;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO,iBAAiB,KAAG,mBAU/D,CAAC;AAEH,eAAO,MAAM,yBAAyB,GAAI,QAAQ,SAAS,iBAAiB,EAAE,KAAG,mBAAmB,EACjE,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { CAUSAL_ENVELOPE_VERSION, DEFAULT_EMITTER_STREAM_ID, DEFAULT_PRINCIPAL_ID, SIMFILE_EMITTER_SYSTEM } from "../ledger/stable.js";
|
|
2
|
+
const asWirePayload = (event) => {
|
|
3
|
+
const extra = event.payload && typeof event.payload === "object" && !Array.isArray(event.payload)
|
|
4
|
+
? event.payload
|
|
5
|
+
: { value: event.payload };
|
|
6
|
+
return {
|
|
7
|
+
sim_time: event.sim_time,
|
|
8
|
+
provenance: event.provenance,
|
|
9
|
+
actor: event.actor,
|
|
10
|
+
target: event.target,
|
|
11
|
+
scope: event.scope,
|
|
12
|
+
...extra
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Maps a runtime trace event (simfile's native ledger envelope) onto the
|
|
17
|
+
* noopolis.causal-event.v1 wire shape defined by root's
|
|
18
|
+
* `specs/causal-event.v1.schema.json` (referenced for shape parity, never
|
|
19
|
+
* imported — simfile keeps its own native TS type per the type-sharing rule).
|
|
20
|
+
*
|
|
21
|
+
* This is B92's real entry point: root's conformance harness invokes
|
|
22
|
+
* `npm run emit-causal-fixture` in this package and validates the printed
|
|
23
|
+
* JSONL, line by line, against the schema plus payload minimums.
|
|
24
|
+
*/
|
|
25
|
+
export const toCausalFixtureRecord = (event) => ({
|
|
26
|
+
version: event.version ?? CAUSAL_ENVELOPE_VERSION,
|
|
27
|
+
run_id: event.run_id ?? "",
|
|
28
|
+
event_id: event.event_id,
|
|
29
|
+
emitter: event.emitter ?? { system: SIMFILE_EMITTER_SYSTEM, stream_id: DEFAULT_EMITTER_STREAM_ID, seq: 0 },
|
|
30
|
+
type: event.kind,
|
|
31
|
+
principal_id: event.principal_id ?? DEFAULT_PRINCIPAL_ID,
|
|
32
|
+
recorded_at: event.recorded_at ?? new Date(0).toISOString(),
|
|
33
|
+
cause_event_ids: event.cause_event_ids ? [...event.cause_event_ids] : [],
|
|
34
|
+
payload: asWirePayload(event)
|
|
35
|
+
});
|
|
36
|
+
export const buildCausalFixtureRecords = (events) => events.map(toCausalFixtureRecord);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface ParsedPhase {
|
|
2
|
+
id: string;
|
|
3
|
+
startSeconds: number;
|
|
4
|
+
}
|
|
5
|
+
export interface ClockSpec {
|
|
6
|
+
seed?: string;
|
|
7
|
+
tick: string;
|
|
8
|
+
sim_per_tick?: string;
|
|
9
|
+
phases?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
export interface ClockRuntime {
|
|
12
|
+
tickSeconds: number;
|
|
13
|
+
simPerTickSeconds: number;
|
|
14
|
+
phases: readonly ParsedPhase[];
|
|
15
|
+
}
|
|
16
|
+
export interface ResolvedClockState {
|
|
17
|
+
tick: number;
|
|
18
|
+
simTime: number;
|
|
19
|
+
phase: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
export declare const parseClockSpec: (clock: ClockSpec) => ClockRuntime;
|
|
22
|
+
export declare const resolveClockPhase: (clock: ClockRuntime, simTimeSeconds: number) => string | undefined;
|
|
23
|
+
export declare const resolveClockState: (clock: ClockRuntime, tick: number) => ResolvedClockState;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=clock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clock.d.ts","sourceRoot":"","sources":["../../src/runtime/clock.ts"],"names":[],"mappings":"AAEA,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAoBD,eAAO,MAAM,cAAc,GAAI,OAAO,SAAS,KAAG,YAoBjD,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,OAAO,YAAY,EAAE,gBAAgB,MAAM,KAAG,MAAM,GAAG,SAwBxF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,OAAO,YAAY,EAAE,MAAM,MAAM,KAAG,kBAOrE,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { parseDurationSeconds } from "../kernel/duration.js";
|
|
2
|
+
const DAY_SECONDS = 86_400;
|
|
3
|
+
const parsePhaseTime = (value) => {
|
|
4
|
+
const normalized = value.trim();
|
|
5
|
+
const [hoursRaw, minutesRaw] = normalized.split(":", 2);
|
|
6
|
+
if (hoursRaw === undefined || minutesRaw === undefined) {
|
|
7
|
+
throw new Error(`invalid phase time: ${value}`);
|
|
8
|
+
}
|
|
9
|
+
const hours = Number(hoursRaw);
|
|
10
|
+
const minutes = Number(minutesRaw);
|
|
11
|
+
if (!Number.isInteger(hours) || !Number.isInteger(minutes) || hours < 0 || hours > 23 || minutes < 0 || minutes > 59) {
|
|
12
|
+
throw new Error(`invalid phase time: ${value}`);
|
|
13
|
+
}
|
|
14
|
+
return hours * 3600 + minutes * 60;
|
|
15
|
+
};
|
|
16
|
+
export const parseClockSpec = (clock) => {
|
|
17
|
+
const tickSeconds = parseDurationSeconds(clock.tick);
|
|
18
|
+
if (tickSeconds <= 0) {
|
|
19
|
+
throw new Error(`clock tick must be positive: ${clock.tick}`);
|
|
20
|
+
}
|
|
21
|
+
const simPerTickSeconds = clock.sim_per_tick ? parseDurationSeconds(clock.sim_per_tick) : tickSeconds;
|
|
22
|
+
if (simPerTickSeconds <= 0) {
|
|
23
|
+
throw new Error(`clock sim_per_tick must be positive: ${clock.sim_per_tick}`);
|
|
24
|
+
}
|
|
25
|
+
const phases = Object.entries(clock.phases ?? {})
|
|
26
|
+
.map(([id, rawStart]) => ({ id, startSeconds: parsePhaseTime(rawStart) }))
|
|
27
|
+
.sort((left, right) => left.startSeconds - right.startSeconds);
|
|
28
|
+
return {
|
|
29
|
+
tickSeconds,
|
|
30
|
+
simPerTickSeconds,
|
|
31
|
+
phases
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export const resolveClockPhase = (clock, simTimeSeconds) => {
|
|
35
|
+
if (clock.phases.length === 0) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const normalized = ((simTimeSeconds % DAY_SECONDS) + DAY_SECONDS) % DAY_SECONDS;
|
|
39
|
+
const first = clock.phases[0]?.startSeconds ?? 0;
|
|
40
|
+
const rotated = normalized < first ? normalized + DAY_SECONDS : normalized;
|
|
41
|
+
for (let index = 0; index < clock.phases.length; index += 1) {
|
|
42
|
+
const current = clock.phases[index];
|
|
43
|
+
if (!current) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const next = clock.phases[(index + 1) % clock.phases.length];
|
|
47
|
+
const end = index + 1 === clock.phases.length
|
|
48
|
+
? next.startSeconds + DAY_SECONDS
|
|
49
|
+
: next.startSeconds;
|
|
50
|
+
if (rotated >= current.startSeconds && rotated < end) {
|
|
51
|
+
return current.id;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return clock.phases.at(-1)?.id;
|
|
55
|
+
};
|
|
56
|
+
export const resolveClockState = (clock, tick) => {
|
|
57
|
+
const simTime = tick * clock.simPerTickSeconds;
|
|
58
|
+
return {
|
|
59
|
+
tick,
|
|
60
|
+
simTime,
|
|
61
|
+
phase: resolveClockPhase(clock, simTime)
|
|
62
|
+
};
|
|
63
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export interface ConditionVariableNode {
|
|
2
|
+
variable: string;
|
|
3
|
+
above?: number;
|
|
4
|
+
below?: number;
|
|
5
|
+
for?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ConditionPhaseNode {
|
|
8
|
+
phase: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ConditionEventNode {
|
|
11
|
+
event: string;
|
|
12
|
+
target?: string;
|
|
13
|
+
actor?: string;
|
|
14
|
+
scope?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ConditionAllNode {
|
|
17
|
+
all: readonly ConditionNode[];
|
|
18
|
+
}
|
|
19
|
+
export interface ConditionAnyNode {
|
|
20
|
+
any: readonly ConditionNode[];
|
|
21
|
+
}
|
|
22
|
+
export interface ConditionNotNode {
|
|
23
|
+
not: ConditionNode;
|
|
24
|
+
}
|
|
25
|
+
export type ConditionNode = ConditionVariableNode | ConditionPhaseNode | ConditionEventNode | ConditionAllNode | ConditionAnyNode | ConditionNotNode;
|
|
26
|
+
export interface ConditionEventMatch {
|
|
27
|
+
kind: string;
|
|
28
|
+
actor?: string;
|
|
29
|
+
target?: string;
|
|
30
|
+
scope?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface RuntimeConditionContext {
|
|
33
|
+
tick: number;
|
|
34
|
+
simTime: number;
|
|
35
|
+
phase?: string;
|
|
36
|
+
variables: Readonly<Record<string, number>>;
|
|
37
|
+
eventsAtTick: readonly ConditionEventMatch[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Every `variable` id referenced anywhere in a condition tree, deduped, in
|
|
41
|
+
* first-seen order — read straight off the compiled `when:` tree, never
|
|
42
|
+
* invented. The grounding for "this rule/event is about variable X": a
|
|
43
|
+
* caller (`trace-compile.ts`'s `compileRules`) uses this to precompute
|
|
44
|
+
* `RuleRuntime.variableIds`, which `step-tick.ts` then threads onto the
|
|
45
|
+
* rule's own `rule.fired` event and every world-effect event it emits, so
|
|
46
|
+
* the viewer can attribute those events to the variable's own storyline
|
|
47
|
+
* (`src/view/runTimelineRecords.ts`'s `buildWorldRecord`) without this
|
|
48
|
+
* package importing anything view-specific.
|
|
49
|
+
*/
|
|
50
|
+
export declare const conditionVariableIds: (node: ConditionNode) => string[];
|
|
51
|
+
export declare class ConditionEvaluator {
|
|
52
|
+
private readonly holdState;
|
|
53
|
+
evaluate(node: ConditionNode, context: RuntimeConditionContext): boolean;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=condition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"condition.d.ts","sourceRoot":"","sources":["../../src/runtime/condition.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,SAAS,aAAa,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,SAAS,aAAa,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,aAAa,CAAC;CACpB;AAED,MAAM,MAAM,aAAa,GAAG,qBAAqB,GAAG,kBAAkB,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;AAErJ,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5C,YAAY,EAAE,SAAS,mBAAmB,EAAE,CAAC;CAC9C;AAqFD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,GAAI,MAAM,aAAa,KAAG,MAAM,EA2BhE,CAAC;AAEF,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkD;IAErE,QAAQ,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,uBAAuB,GAAG,OAAO;CA2BhF"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { parseDurationSeconds } from "../kernel/duration.js";
|
|
2
|
+
const conditionKey = (node) => {
|
|
3
|
+
return `${node.variable}:${node.above ?? ""}:${node.below ?? ""}:${node.for ?? ""}`;
|
|
4
|
+
};
|
|
5
|
+
const matchesVariableCondition = (node, state, holdState) => {
|
|
6
|
+
const value = state.variables[node.variable];
|
|
7
|
+
const above = node.above ?? -Infinity;
|
|
8
|
+
const below = node.below ?? Infinity;
|
|
9
|
+
const now = Number.isFinite(value) ? value : 0;
|
|
10
|
+
const passesWindow = now > above && now < below;
|
|
11
|
+
if (node.for === undefined) {
|
|
12
|
+
return passesWindow;
|
|
13
|
+
}
|
|
14
|
+
const key = conditionKey(node);
|
|
15
|
+
const required = parseDurationSeconds(node.for);
|
|
16
|
+
if (!passesWindow) {
|
|
17
|
+
holdState.startTimeByCondition.delete(key);
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
const started = holdState.startTimeByCondition.get(key);
|
|
21
|
+
if (started === undefined) {
|
|
22
|
+
holdState.startTimeByCondition.set(key, state.simTime);
|
|
23
|
+
return required <= 0;
|
|
24
|
+
}
|
|
25
|
+
return state.simTime - started >= required;
|
|
26
|
+
};
|
|
27
|
+
const matchesEventCondition = (node, eventsAtTick) => {
|
|
28
|
+
return eventsAtTick.some((event) => {
|
|
29
|
+
if (event.kind !== node.event) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (node.actor !== undefined && node.actor !== event.actor) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (node.target !== undefined && node.target !== event.target) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (node.scope !== undefined && node.scope !== event.scope) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
const asVariableNode = (node) => {
|
|
45
|
+
return "variable" in node;
|
|
46
|
+
};
|
|
47
|
+
const asPhaseNode = (node) => {
|
|
48
|
+
return "phase" in node;
|
|
49
|
+
};
|
|
50
|
+
const asEventNode = (node) => {
|
|
51
|
+
return "event" in node;
|
|
52
|
+
};
|
|
53
|
+
const asAllNode = (node) => {
|
|
54
|
+
return "all" in node;
|
|
55
|
+
};
|
|
56
|
+
const asAnyNode = (node) => {
|
|
57
|
+
return "any" in node;
|
|
58
|
+
};
|
|
59
|
+
const asNotNode = (node) => {
|
|
60
|
+
return "not" in node;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Every `variable` id referenced anywhere in a condition tree, deduped, in
|
|
64
|
+
* first-seen order — read straight off the compiled `when:` tree, never
|
|
65
|
+
* invented. The grounding for "this rule/event is about variable X": a
|
|
66
|
+
* caller (`trace-compile.ts`'s `compileRules`) uses this to precompute
|
|
67
|
+
* `RuleRuntime.variableIds`, which `step-tick.ts` then threads onto the
|
|
68
|
+
* rule's own `rule.fired` event and every world-effect event it emits, so
|
|
69
|
+
* the viewer can attribute those events to the variable's own storyline
|
|
70
|
+
* (`src/view/runTimelineRecords.ts`'s `buildWorldRecord`) without this
|
|
71
|
+
* package importing anything view-specific.
|
|
72
|
+
*/
|
|
73
|
+
export const conditionVariableIds = (node) => {
|
|
74
|
+
const ids = [];
|
|
75
|
+
const seen = new Set();
|
|
76
|
+
const visit = (current) => {
|
|
77
|
+
if (asVariableNode(current)) {
|
|
78
|
+
if (!seen.has(current.variable)) {
|
|
79
|
+
seen.add(current.variable);
|
|
80
|
+
ids.push(current.variable);
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (asAllNode(current)) {
|
|
85
|
+
current.all.forEach(visit);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (asAnyNode(current)) {
|
|
89
|
+
current.any.forEach(visit);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (asNotNode(current)) {
|
|
93
|
+
visit(current.not);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
visit(node);
|
|
97
|
+
return ids;
|
|
98
|
+
};
|
|
99
|
+
export class ConditionEvaluator {
|
|
100
|
+
holdState = { startTimeByCondition: new Map() };
|
|
101
|
+
evaluate(node, context) {
|
|
102
|
+
if (asVariableNode(node)) {
|
|
103
|
+
return matchesVariableCondition(node, context, this.holdState);
|
|
104
|
+
}
|
|
105
|
+
if (asPhaseNode(node)) {
|
|
106
|
+
return context.phase === node.phase;
|
|
107
|
+
}
|
|
108
|
+
if (asEventNode(node)) {
|
|
109
|
+
return matchesEventCondition(node, context.eventsAtTick);
|
|
110
|
+
}
|
|
111
|
+
if (asAllNode(node)) {
|
|
112
|
+
return node.all.every((child) => this.evaluate(child, context));
|
|
113
|
+
}
|
|
114
|
+
if (asAnyNode(node)) {
|
|
115
|
+
return node.any.some((child) => this.evaluate(child, context));
|
|
116
|
+
}
|
|
117
|
+
if (asNotNode(node)) {
|
|
118
|
+
return !this.evaluate(node.not, context);
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-causal-fixture.d.ts","sourceRoot":"","sources":["../../src/runtime/emit-causal-fixture.ts"],"names":[],"mappings":"AA8BA,eAAO,MAAM,sBAAsB,QAAO,MAAM,EAK/C,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { parseSimfileSource } from "../schema/parse.js";
|
|
2
|
+
import { buildCausalFixtureRecords } from "./causal-fixture.js";
|
|
3
|
+
import { runSimfileTrace } from "./trace-run.js";
|
|
4
|
+
/**
|
|
5
|
+
* B92's entry point into simfile: root's conformance harness shells out to
|
|
6
|
+
* `npm run emit-causal-fixture` and validates each printed line against
|
|
7
|
+
* `specs/causal-event.v1.schema.json` plus payload minimums. Keep stdout
|
|
8
|
+
* pure JSONL — one noopolis.causal-event.v1 record per line, no banner, no
|
|
9
|
+
* other console output.
|
|
10
|
+
*/
|
|
11
|
+
const FIXTURE_SOURCE = `
|
|
12
|
+
simfile_version: "0.1"
|
|
13
|
+
name: causal-fixture-world
|
|
14
|
+
clock:
|
|
15
|
+
seed: causal-fixture
|
|
16
|
+
tick: 1m
|
|
17
|
+
rules:
|
|
18
|
+
announce:
|
|
19
|
+
fire: once
|
|
20
|
+
when:
|
|
21
|
+
event: clock.sync
|
|
22
|
+
do:
|
|
23
|
+
- action: moltnet:message
|
|
24
|
+
to: room:office-floor:case-warroom
|
|
25
|
+
content: "causal fixture message"
|
|
26
|
+
- action: wake:recommend
|
|
27
|
+
to: room:office-floor:case-warroom
|
|
28
|
+
`;
|
|
29
|
+
export const emitCausalFixtureJsonl = () => {
|
|
30
|
+
const runId = process.env.NOOPOLIS_RUN_ID ?? "simfile-fixture-run";
|
|
31
|
+
const { simfile } = parseSimfileSource(FIXTURE_SOURCE, { path: "causal-fixture.yaml" });
|
|
32
|
+
const trace = runSimfileTrace(simfile, { runId, seed: "causal-fixture-seed", ticks: 2 });
|
|
33
|
+
return buildCausalFixtureRecords(trace.events).map((record) => JSON.stringify(record));
|
|
34
|
+
};
|
|
35
|
+
/* c8 ignore start -- thin stdout entry point, exercised via emitCausalFixtureJsonl in tests */
|
|
36
|
+
const isMainModule = () => {
|
|
37
|
+
const entry = process.argv[1];
|
|
38
|
+
return typeof entry === "string" && import.meta.url === new URL(`file://${entry}`).href;
|
|
39
|
+
};
|
|
40
|
+
if (isMainModule()) {
|
|
41
|
+
for (const line of emitCausalFixtureJsonl()) {
|
|
42
|
+
process.stdout.write(`${line}\n`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/* c8 ignore stop */
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CompiledExpression {
|
|
2
|
+
source: string;
|
|
3
|
+
dependencies: string[];
|
|
4
|
+
evaluate: (input: {
|
|
5
|
+
variables: Readonly<Record<string, number>>;
|
|
6
|
+
tick: number;
|
|
7
|
+
t: number;
|
|
8
|
+
}) => number;
|
|
9
|
+
}
|
|
10
|
+
export declare const compileExpression: (source: string) => CompiledExpression;
|
|
11
|
+
//# sourceMappingURL=expression.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expression.d.ts","sourceRoot":"","sources":["../../src/runtime/expression.ts"],"names":[],"mappings":"AA+UA,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,CAAC,KAAK,EAAE;QAAE,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CACvG;AAED,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,KAAG,kBAkBlD,CAAC"}
|