@primmel/primmel 1.19.0 → 1.21.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/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/src/check-rules.d.ts +1 -1
- package/dist/src/check-rules.d.ts.map +1 -1
- package/dist/src/check-rules.js +53 -15
- package/dist/src/check-rules.js.map +1 -1
- package/dist/src/check.d.ts +4 -0
- package/dist/src/check.d.ts.map +1 -1
- package/dist/src/check.js +519 -132
- package/dist/src/check.js.map +1 -1
- package/dist/src/export/cddal.d.ts +25 -0
- package/dist/src/export/cddal.d.ts.map +1 -0
- package/dist/src/export/cddal.js +213 -0
- package/dist/src/export/cddal.js.map +1 -0
- package/dist/src/export/retrieval.d.ts +147 -6
- package/dist/src/export/retrieval.d.ts.map +1 -1
- package/dist/src/export/retrieval.js +254 -25
- package/dist/src/export/retrieval.js.map +1 -1
- package/dist/src/export/unitsdb.d.ts +19 -0
- package/dist/src/export/unitsdb.d.ts.map +1 -0
- package/dist/src/export/unitsdb.js +82 -0
- package/dist/src/export/unitsdb.js.map +1 -0
- package/dist/src/export/yaml-lite.d.ts +13 -0
- package/dist/src/export/yaml-lite.d.ts.map +1 -0
- package/dist/src/export/yaml-lite.js +219 -0
- package/dist/src/export/yaml-lite.js.map +1 -0
- package/dist/src/instance-resolution.d.ts +19 -0
- package/dist/src/instance-resolution.d.ts.map +1 -1
- package/dist/src/instance-resolution.js +87 -1
- package/dist/src/instance-resolution.js.map +1 -1
- package/dist/src/model-diff.d.ts.map +1 -1
- package/dist/src/model-diff.js +0 -5
- package/dist/src/model-diff.js.map +1 -1
- package/dist/src/runtime.d.ts +143 -0
- package/dist/src/runtime.d.ts.map +1 -0
- package/dist/src/runtime.js +648 -0
- package/dist/src/runtime.js.map +1 -0
- package/dist/src/ser-des/config/artifact.d.ts.map +1 -1
- package/dist/src/ser-des/config/artifact.js +6 -0
- package/dist/src/ser-des/config/artifact.js.map +1 -1
- package/dist/src/ser-des/config/attestation.d.ts +5 -0
- package/dist/src/ser-des/config/attestation.d.ts.map +1 -0
- package/dist/src/ser-des/config/attestation.js +143 -0
- package/dist/src/ser-des/config/attestation.js.map +1 -0
- package/dist/src/ser-des/config/conformanceTest.d.ts.map +1 -1
- package/dist/src/ser-des/config/conformanceTest.js +310 -0
- package/dist/src/ser-des/config/conformanceTest.js.map +1 -1
- package/dist/src/ser-des/config/data.d.ts.map +1 -1
- package/dist/src/ser-des/config/data.js +98 -0
- package/dist/src/ser-des/config/data.js.map +1 -1
- package/dist/src/ser-des/config/documentModule.js +5 -5
- package/dist/src/ser-des/config/documentModule.js.map +1 -1
- package/dist/src/ser-des/config/index.d.ts +8 -0
- package/dist/src/ser-des/config/index.d.ts.map +1 -1
- package/dist/src/ser-des/config/index.js +22 -49
- package/dist/src/ser-des/config/index.js.map +1 -1
- package/dist/src/ser-des/config/instance.d.ts.map +1 -1
- package/dist/src/ser-des/config/instance.js +24 -0
- package/dist/src/ser-des/config/instance.js.map +1 -1
- package/dist/src/ser-des/config/process.d.ts.map +1 -1
- package/dist/src/ser-des/config/process.js +8 -0
- package/dist/src/ser-des/config/process.js.map +1 -1
- package/dist/src/ser-des/config/processSequence.d.ts +19 -0
- package/dist/src/ser-des/config/processSequence.d.ts.map +1 -0
- package/dist/src/ser-des/config/processSequence.js +77 -0
- package/dist/src/ser-des/config/processSequence.js.map +1 -0
- package/dist/src/ser-des/config/quantity.d.ts +4 -1
- package/dist/src/ser-des/config/quantity.d.ts.map +1 -1
- package/dist/src/ser-des/config/quantity.js +63 -1
- package/dist/src/ser-des/config/quantity.js.map +1 -1
- package/dist/src/ser-des/config/subject.d.ts.map +1 -1
- package/dist/src/ser-des/config/subject.js +14 -0
- package/dist/src/ser-des/config/subject.js.map +1 -1
- package/dist/src/ser-des/index.d.ts +4 -1
- package/dist/src/ser-des/index.d.ts.map +1 -1
- package/dist/src/ser-des/index.js +3 -1
- package/dist/src/ser-des/index.js.map +1 -1
- package/dist/src/ser-des/package.d.ts.map +1 -1
- package/dist/src/ser-des/package.js +9 -7
- package/dist/src/ser-des/package.js.map +1 -1
- package/dist/src/ser-des/parse.d.ts +24 -0
- package/dist/src/ser-des/parse.d.ts.map +1 -1
- package/dist/src/ser-des/parse.js +69 -33
- package/dist/src/ser-des/parse.js.map +1 -1
- package/dist/src/ser-des/shape-front-end.d.ts +8 -0
- package/dist/src/ser-des/shape-front-end.d.ts.map +1 -0
- package/dist/src/ser-des/shape-front-end.js +215 -0
- package/dist/src/ser-des/shape-front-end.js.map +1 -0
- package/dist/src/ser-des/types.d.ts +4 -10
- package/dist/src/ser-des/types.d.ts.map +1 -1
- package/dist/src/types/Artifact.d.ts +7 -0
- package/dist/src/types/Artifact.d.ts.map +1 -1
- package/dist/src/types/Attestation.d.ts +60 -0
- package/dist/src/types/Attestation.d.ts.map +1 -0
- package/dist/src/types/Attestation.js +20 -0
- package/dist/src/types/Attestation.js.map +1 -0
- package/dist/src/types/ConformanceTest.d.ts +86 -0
- package/dist/src/types/ConformanceTest.d.ts.map +1 -1
- package/dist/src/types/DocumentModule.d.ts +1 -1
- package/dist/src/types/DocumentModule.d.ts.map +1 -1
- package/dist/src/types/Instance.d.ts +6 -2
- package/dist/src/types/Instance.d.ts.map +1 -1
- package/dist/src/types/ProcessModel.d.ts +0 -11
- package/dist/src/types/ProcessModel.d.ts.map +1 -1
- package/dist/src/types/ProcessModel.js +2 -28
- package/dist/src/types/ProcessModel.js.map +1 -1
- package/dist/src/types/Quantity.d.ts +22 -0
- package/dist/src/types/Quantity.d.ts.map +1 -1
- package/dist/src/types/Standard.d.ts +2 -13
- package/dist/src/types/Standard.d.ts.map +1 -1
- package/dist/src/types/Subject.d.ts +14 -0
- package/dist/src/types/Subject.d.ts.map +1 -1
- package/dist/src/types/data.d.ts +13 -0
- package/dist/src/types/data.d.ts.map +1 -1
- package/dist/src/types/process.d.ts +8 -0
- package/dist/src/types/process.d.ts.map +1 -1
- package/dist-browser/index.mjs +1659 -1629
- package/dist-cli/primmel.mjs +2015 -875
- package/package.json +15 -3
- package/dist/src/ser-des/config/processModel.d.ts +0 -13
- package/dist/src/ser-des/config/processModel.d.ts.map +0 -1
- package/dist/src/ser-des/config/processModel.js +0 -163
- package/dist/src/ser-des/config/processModel.js.map +0 -1
- package/dist/src/ser-des/config/storyline.d.ts +0 -7
- package/dist/src/ser-des/config/storyline.d.ts.map +0 -1
- package/dist/src/ser-des/config/storyline.js +0 -264
- package/dist/src/ser-des/config/storyline.js.map +0 -1
- package/dist/src/ser-des/config/workflowConfig.d.ts +0 -5
- package/dist/src/ser-des/config/workflowConfig.d.ts.map +0 -1
- package/dist/src/ser-des/config/workflowConfig.js +0 -129
- package/dist/src/ser-des/config/workflowConfig.js.map +0 -1
- package/dist/src/ser-des/config/workflowStage.d.ts +0 -5
- package/dist/src/ser-des/config/workflowStage.d.ts.map +0 -1
- package/dist/src/ser-des/config/workflowStage.js +0 -96
- package/dist/src/ser-des/config/workflowStage.js.map +0 -1
- package/dist/src/types/Storyline.d.ts +0 -62
- package/dist/src/types/Storyline.d.ts.map +0 -1
- package/dist/src/types/Storyline.js +0 -51
- package/dist/src/types/Storyline.js.map +0 -1
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
3
|
+
// The Primmel runtime (the full flow's phase 4 — the execution plane):
|
|
4
|
+
// a model RUN is a replayable object — the test programs as executed,
|
|
5
|
+
// the verdicts derived from the authored data, the state trajectory,
|
|
6
|
+
// and the evidence records the evidence law requires. Deterministic by
|
|
7
|
+
// construction: no clock, no randomness, JSON-stable — the same model,
|
|
8
|
+
// instance and inputs always produce the same run.
|
|
9
|
+
//
|
|
10
|
+
// The evaluator covers the closed-derivation subset the checks
|
|
11
|
+
// guarantee (C149: every referenced name is declared): literals,
|
|
12
|
+
// attribute references, `.` field access into the dimension values'
|
|
13
|
+
// typed payloads, arithmetic, comparisons, if/then/else, and abs/min/
|
|
14
|
+
// max. Nothing else is legal in a declared derivation, so nothing else
|
|
15
|
+
// is evaluated.
|
|
16
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.evaluateExpression = evaluateExpression;
|
|
19
|
+
exports.projectCertificate = projectCertificate;
|
|
20
|
+
exports.executeRun = executeRun;
|
|
21
|
+
const operational_state_1 = require("./operational-state");
|
|
22
|
+
function tokenize(src) {
|
|
23
|
+
const out = [];
|
|
24
|
+
let i = 0;
|
|
25
|
+
const s = src;
|
|
26
|
+
while (i < s.length) {
|
|
27
|
+
const ch = s[i];
|
|
28
|
+
if (/\s/.test(ch)) {
|
|
29
|
+
i++;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (/[0-9]/.test(ch) || (ch === '.' && /[0-9]/.test(s[i + 1] ?? ''))) {
|
|
33
|
+
let j = i;
|
|
34
|
+
while (j < s.length && /[0-9.]/.test(s[j])) {
|
|
35
|
+
j++;
|
|
36
|
+
}
|
|
37
|
+
out.push({ t: 'num', v: Number(s.slice(i, j)) });
|
|
38
|
+
i = j;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (/[A-Za-z_]/.test(ch)) {
|
|
42
|
+
let j = i;
|
|
43
|
+
while (j < s.length && /[A-Za-z0-9_]/.test(s[j])) {
|
|
44
|
+
j++;
|
|
45
|
+
}
|
|
46
|
+
out.push({ t: 'id', v: s.slice(i, j) });
|
|
47
|
+
i = j;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (s.startsWith('<=', i) ||
|
|
51
|
+
s.startsWith('>=', i) ||
|
|
52
|
+
s.startsWith('!=', i)) {
|
|
53
|
+
out.push({ t: 'op', v: s.slice(i, i + 2) });
|
|
54
|
+
i += 2;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if ('+-*/()<>=,.'.includes(ch)) {
|
|
58
|
+
out.push({ t: 'op', v: ch });
|
|
59
|
+
i++;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`runtime: the derivation uses a character the evaluator does not know: "${ch}"`);
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
class Reader {
|
|
67
|
+
toks;
|
|
68
|
+
constructor(toks) {
|
|
69
|
+
this.toks = toks;
|
|
70
|
+
}
|
|
71
|
+
pos = 0;
|
|
72
|
+
peek() {
|
|
73
|
+
return this.toks[this.pos];
|
|
74
|
+
}
|
|
75
|
+
next() {
|
|
76
|
+
const t = this.toks[this.pos];
|
|
77
|
+
if (!t) {
|
|
78
|
+
throw new Error('runtime: the derivation ended unexpectedly');
|
|
79
|
+
}
|
|
80
|
+
this.pos++;
|
|
81
|
+
return t;
|
|
82
|
+
}
|
|
83
|
+
expectOp(v) {
|
|
84
|
+
const t = this.next();
|
|
85
|
+
if (t.t !== 'op' || t.v !== v) {
|
|
86
|
+
throw new Error(`runtime: the derivation expected "${v}"`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function evalExpr(r, env) {
|
|
91
|
+
return evalIf(r, env);
|
|
92
|
+
}
|
|
93
|
+
// if <cond> then <expr> else <expr> — R 60's tier selection rides it.
|
|
94
|
+
function evalIf(r, env) {
|
|
95
|
+
const t = r.peek();
|
|
96
|
+
if (t && t.t === 'id' && t.v === 'if') {
|
|
97
|
+
r.next();
|
|
98
|
+
const cond = evalComparison(r, env);
|
|
99
|
+
const thenT = r.next();
|
|
100
|
+
if (thenT.t !== 'id' || thenT.v !== 'then') {
|
|
101
|
+
throw new Error('runtime: the derivation expected "then"');
|
|
102
|
+
}
|
|
103
|
+
const a = evalIf(r, env);
|
|
104
|
+
const elseT = r.next();
|
|
105
|
+
if (elseT.t !== 'id' || elseT.v !== 'else') {
|
|
106
|
+
throw new Error('runtime: the derivation expected "else"');
|
|
107
|
+
}
|
|
108
|
+
const b = evalIf(r, env);
|
|
109
|
+
return cond ? a : b;
|
|
110
|
+
}
|
|
111
|
+
return evalComparison(r, env);
|
|
112
|
+
}
|
|
113
|
+
function evalComparison(r, env) {
|
|
114
|
+
const left = evalAdd(r, env);
|
|
115
|
+
const t = r.peek();
|
|
116
|
+
if (t && t.t === 'op' && ['<=', '>=', '<', '>', '=', '!='].includes(t.v)) {
|
|
117
|
+
r.next();
|
|
118
|
+
const right = evalAdd(r, env);
|
|
119
|
+
switch (t.v) {
|
|
120
|
+
case '<=':
|
|
121
|
+
return left <= right ? 1 : 0;
|
|
122
|
+
case '>=':
|
|
123
|
+
return left >= right ? 1 : 0;
|
|
124
|
+
case '<':
|
|
125
|
+
return left < right ? 1 : 0;
|
|
126
|
+
case '>':
|
|
127
|
+
return left > right ? 1 : 0;
|
|
128
|
+
case '=':
|
|
129
|
+
return left === right ? 1 : 0;
|
|
130
|
+
case '!=':
|
|
131
|
+
return left !== right ? 1 : 0;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return left;
|
|
135
|
+
}
|
|
136
|
+
function evalAdd(r, env) {
|
|
137
|
+
let v = evalMul(r, env);
|
|
138
|
+
for (;;) {
|
|
139
|
+
const t = r.peek();
|
|
140
|
+
if (t && t.t === 'op' && (t.v === '+' || t.v === '-')) {
|
|
141
|
+
r.next();
|
|
142
|
+
const rhs = evalMul(r, env);
|
|
143
|
+
v = t.v === '+' ? v + rhs : v - rhs;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
return v;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function evalMul(r, env) {
|
|
150
|
+
let v = evalUnary(r, env);
|
|
151
|
+
for (;;) {
|
|
152
|
+
const t = r.peek();
|
|
153
|
+
if (t && t.t === 'op' && (t.v === '*' || t.v === '/')) {
|
|
154
|
+
r.next();
|
|
155
|
+
const rhs = evalUnary(r, env);
|
|
156
|
+
v = t.v === '*' ? v * rhs : v / rhs;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
return v;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function evalUnary(r, env) {
|
|
163
|
+
const t = r.peek();
|
|
164
|
+
if (t && t.t === 'op' && (t.v === '-' || t.v === '+')) {
|
|
165
|
+
r.next();
|
|
166
|
+
const v = evalUnary(r, env);
|
|
167
|
+
return t.v === '-' ? -v : v;
|
|
168
|
+
}
|
|
169
|
+
return evalPostfix(r, env);
|
|
170
|
+
}
|
|
171
|
+
function evalPostfix(r, env) {
|
|
172
|
+
let v = evalAtom(r, env);
|
|
173
|
+
for (;;) {
|
|
174
|
+
const t = r.peek();
|
|
175
|
+
if (t && t.t === 'op' && t.v === '.') {
|
|
176
|
+
r.next();
|
|
177
|
+
const field = r.next();
|
|
178
|
+
if (field.t !== 'id') {
|
|
179
|
+
throw new Error('runtime: the derivation expected a field name');
|
|
180
|
+
}
|
|
181
|
+
if (v === null || typeof v !== 'object') {
|
|
182
|
+
throw new Error(`runtime: the derivation reads "${field.v}" off a plain value`);
|
|
183
|
+
}
|
|
184
|
+
const scope = v;
|
|
185
|
+
const next = scope[field.v];
|
|
186
|
+
if (next === undefined) {
|
|
187
|
+
throw new Error(`runtime: the derivation reads the undeclared field "${field.v}"`);
|
|
188
|
+
}
|
|
189
|
+
v = next;
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
return v;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function evalAtom(r, env) {
|
|
196
|
+
const t = r.next();
|
|
197
|
+
if (t.t === 'num') {
|
|
198
|
+
return t.v;
|
|
199
|
+
}
|
|
200
|
+
if (t.t === 'id') {
|
|
201
|
+
if (t.v === 'abs' || t.v === 'min' || t.v === 'max') {
|
|
202
|
+
r.expectOp('(');
|
|
203
|
+
const a = evalExpr(r, env);
|
|
204
|
+
let b = null;
|
|
205
|
+
const comma = r.peek();
|
|
206
|
+
if (comma && comma.t === 'op' && comma.v === ',') {
|
|
207
|
+
r.next();
|
|
208
|
+
b = evalExpr(r, env);
|
|
209
|
+
}
|
|
210
|
+
r.expectOp(')');
|
|
211
|
+
if (t.v === 'abs') {
|
|
212
|
+
return Math.abs(a);
|
|
213
|
+
}
|
|
214
|
+
if (b === null) {
|
|
215
|
+
throw new Error(`runtime: ${t.v} needs two arguments`);
|
|
216
|
+
}
|
|
217
|
+
return t.v === 'min' ? Math.min(a, b) : Math.max(a, b);
|
|
218
|
+
}
|
|
219
|
+
if (t.v === 'ocl') {
|
|
220
|
+
// The calculation idiom's wrapping token — the expression inside
|
|
221
|
+
// the braces was already unwrapped by the caller.
|
|
222
|
+
r.expectOp('(');
|
|
223
|
+
const v = evalExpr(r, env);
|
|
224
|
+
r.expectOp(')');
|
|
225
|
+
return v;
|
|
226
|
+
}
|
|
227
|
+
if (t.v === 'true') {
|
|
228
|
+
return 1;
|
|
229
|
+
}
|
|
230
|
+
if (t.v === 'false') {
|
|
231
|
+
return 0;
|
|
232
|
+
}
|
|
233
|
+
if (!(t.v in env)) {
|
|
234
|
+
throw new Error(`runtime: the derivation names "${t.v}", which the run scope does not bind`);
|
|
235
|
+
}
|
|
236
|
+
const v = env[t.v];
|
|
237
|
+
if (typeof v === 'object') {
|
|
238
|
+
return v;
|
|
239
|
+
} // a payload object for '.' access
|
|
240
|
+
return typeof v === 'string' ? Number(v) : v;
|
|
241
|
+
}
|
|
242
|
+
if (t.t === 'op' && t.v === '(') {
|
|
243
|
+
const v = evalExpr(r, env);
|
|
244
|
+
r.expectOp(')');
|
|
245
|
+
return v;
|
|
246
|
+
}
|
|
247
|
+
throw new Error(`runtime: the derivation has an unexpected token`);
|
|
248
|
+
}
|
|
249
|
+
/** Evaluate one closed derivation over the run scope. The checks
|
|
250
|
+
* guarantee every referenced name is declared (C149); this throws —
|
|
251
|
+
* never silently indeterminates — when the scope lacks one. */
|
|
252
|
+
function evaluateExpression(expr, env) {
|
|
253
|
+
const cleaned = expr
|
|
254
|
+
.replace(/^ocl\{/, '')
|
|
255
|
+
.replace(/\}$/, '')
|
|
256
|
+
.trim();
|
|
257
|
+
const r = new Reader(tokenize(cleaned));
|
|
258
|
+
const v = evalExpr(r, env);
|
|
259
|
+
if (r.peek() !== undefined) {
|
|
260
|
+
throw new Error('runtime: the derivation has trailing tokens');
|
|
261
|
+
}
|
|
262
|
+
return v;
|
|
263
|
+
}
|
|
264
|
+
/** Project the certificate from an executed run: the attestation's
|
|
265
|
+
* claims, each judged by the run verdict its validated_by names. */
|
|
266
|
+
function projectCertificate(standard, run, attestationId) {
|
|
267
|
+
const att = standard.attestations?.find(a => a.id === attestationId);
|
|
268
|
+
if (!att) {
|
|
269
|
+
throw new Error(`runtime: no attestation "${attestationId}" is declared`);
|
|
270
|
+
}
|
|
271
|
+
// The declared values: the lineage instance each claim names — the
|
|
272
|
+
// claim's declared path's leading id is the declaration instance.
|
|
273
|
+
const claims = [];
|
|
274
|
+
for (const claim of att.claims ?? []) {
|
|
275
|
+
const id = claim.promise;
|
|
276
|
+
// The declared path names the declaration stage (e.g. the
|
|
277
|
+
// application declaration's id); the lineage INSTANCE carries the
|
|
278
|
+
// suffix -declared on it — resolve either spelling.
|
|
279
|
+
const declaredId = claim.declared?.split('.')[0] ?? '';
|
|
280
|
+
const source = standard.instances.find(i => i.id === declaredId) ??
|
|
281
|
+
standard.instances.find(i => i.id === `${declaredId}-declared`) ??
|
|
282
|
+
standard.instances.find(i => i.id === att.subject);
|
|
283
|
+
// The declared value rides the attributes — or, for a
|
|
284
|
+
// classification claim, the dimensions map.
|
|
285
|
+
const raw = source
|
|
286
|
+
? (source.has?.attributes?.[id] ??
|
|
287
|
+
source.has?.dimensions?.[id])
|
|
288
|
+
: undefined;
|
|
289
|
+
const value = typeof raw === 'object' && raw !== null
|
|
290
|
+
? raw.value
|
|
291
|
+
: raw;
|
|
292
|
+
const declared = value === undefined
|
|
293
|
+
? undefined
|
|
294
|
+
: {
|
|
295
|
+
value: (typeof value === 'object' && value !== null
|
|
296
|
+
? value.value
|
|
297
|
+
: value),
|
|
298
|
+
unit: raw?.unit,
|
|
299
|
+
source: raw
|
|
300
|
+
?.provenance?.source,
|
|
301
|
+
};
|
|
302
|
+
const verdictId = claim.validatedBy ?? '';
|
|
303
|
+
const matched = run.verdicts.filter(v => v.id === verdictId || verdictId === '');
|
|
304
|
+
const outcome = verdictId === ''
|
|
305
|
+
? 'unexecuted'
|
|
306
|
+
: matched.length === 0
|
|
307
|
+
? 'unexecuted'
|
|
308
|
+
: matched.every(v => v.outcome === 'pass')
|
|
309
|
+
? 'pass'
|
|
310
|
+
: matched.some(v => v.outcome === 'fail')
|
|
311
|
+
? 'fail'
|
|
312
|
+
: 'indeterminate';
|
|
313
|
+
claims.push({
|
|
314
|
+
id,
|
|
315
|
+
declared,
|
|
316
|
+
validatedBy: verdictId || undefined,
|
|
317
|
+
outcome,
|
|
318
|
+
value: matched.length > 0 ? matched[matched.length - 1].value : undefined,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
return {
|
|
322
|
+
attestation: att.id,
|
|
323
|
+
subject: att.subject,
|
|
324
|
+
statement: att.statement,
|
|
325
|
+
claims,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function attrValue(inst, id) {
|
|
329
|
+
const raw = inst.has?.attributes?.[id];
|
|
330
|
+
if (raw !== undefined &&
|
|
331
|
+
raw !== null &&
|
|
332
|
+
typeof raw === 'object' &&
|
|
333
|
+
'value' in raw) {
|
|
334
|
+
return raw;
|
|
335
|
+
}
|
|
336
|
+
return raw !== undefined ? { value: raw } : undefined;
|
|
337
|
+
}
|
|
338
|
+
/** The accuracy-class dimension value's typed payload (the class's
|
|
339
|
+
* defining data — Table 1 limits, Table 4 tiers), as the evaluator's
|
|
340
|
+
* nested scope. */
|
|
341
|
+
function classPayload(standard, dimValue) {
|
|
342
|
+
const instrument = standard.instruments[0];
|
|
343
|
+
const dim = instrument?.dimensions.find(d => d.id === 'accuracy_class');
|
|
344
|
+
const valueId = dimValue;
|
|
345
|
+
const value = dim?.values.find(v => v.id === valueId);
|
|
346
|
+
const out = {};
|
|
347
|
+
const payload = value?.payload ?? {};
|
|
348
|
+
for (const [k, v] of Object.entries(payload)) {
|
|
349
|
+
const n = Number(v);
|
|
350
|
+
out[k] = Number.isNaN(n) ? String(v) : n;
|
|
351
|
+
}
|
|
352
|
+
return out;
|
|
353
|
+
}
|
|
354
|
+
/** Execute one deterministic run: the test's programs as applied, the
|
|
355
|
+
* verdict chain derived from the authored data, the state trajectory
|
|
356
|
+
* of the bound machine, and the evidence record. The same call with
|
|
357
|
+
* the same arguments always returns the same run. */
|
|
358
|
+
function executeRun(standard, options) {
|
|
359
|
+
const inst = standard.instances.find(i => i.id === options.instance);
|
|
360
|
+
if (!inst) {
|
|
361
|
+
throw new Error(`runtime: no instance "${options.instance}" is declared`);
|
|
362
|
+
}
|
|
363
|
+
// The run scope: the instance's declared attributes (p_lc, e_max,
|
|
364
|
+
// n_lc, ...) plus the typed class payload behind the dimension value.
|
|
365
|
+
const dimValue = inst.has?.dimensions?.accuracy_class;
|
|
366
|
+
const payload = classPayload(standard, dimValue);
|
|
367
|
+
const scope = { ...payload, accuracy_class: payload };
|
|
368
|
+
for (const [id] of Object.entries(inst.has?.attributes ?? {})) {
|
|
369
|
+
const v = attrValue(inst, id);
|
|
370
|
+
if (v === undefined) {
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
const n = Number(typeof v.value === 'object'
|
|
374
|
+
? v.value.value
|
|
375
|
+
: v.value);
|
|
376
|
+
if (!Number.isNaN(n)) {
|
|
377
|
+
scope[id] = n;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
// The programs: the test's ordered steps with their argument
|
|
381
|
+
// expressions evaluated over the run scope.
|
|
382
|
+
const programs = [];
|
|
383
|
+
const test = options.test
|
|
384
|
+
? standard.conformanceTests.find(t => t.id === options.test)
|
|
385
|
+
: undefined;
|
|
386
|
+
if (test) {
|
|
387
|
+
for (const step of test.preparation?.entries ?? []) {
|
|
388
|
+
const args = {};
|
|
389
|
+
for (const [k, expr] of Object.entries(step.args ?? {})) {
|
|
390
|
+
try {
|
|
391
|
+
args[k] = evaluateExpression(String(expr), scope);
|
|
392
|
+
}
|
|
393
|
+
catch {
|
|
394
|
+
args[k] = String(expr);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
programs.push({
|
|
398
|
+
program: 'preparation',
|
|
399
|
+
order: step.order ?? null,
|
|
400
|
+
drive: step.drive ?? '',
|
|
401
|
+
args,
|
|
402
|
+
hold: step.hold || undefined,
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
for (const point of test.stimulus?.entries ?? []) {
|
|
406
|
+
const args = {};
|
|
407
|
+
for (const [k, expr] of Object.entries(point.args ?? {})) {
|
|
408
|
+
try {
|
|
409
|
+
args[k] = evaluateExpression(String(expr), scope);
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
args[k] = String(expr);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
programs.push({
|
|
416
|
+
program: 'stimulus',
|
|
417
|
+
order: point.order ?? null,
|
|
418
|
+
drive: point.drive ?? '',
|
|
419
|
+
args,
|
|
420
|
+
hold: point.hold || undefined,
|
|
421
|
+
acceptance: point.acceptance || undefined,
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
// The verdicts: the bound requirement's limit's accepted verdicts,
|
|
426
|
+
// evaluated per input — |e_l| against the MPE the model derives.
|
|
427
|
+
const verdicts = [];
|
|
428
|
+
const reqIds = [
|
|
429
|
+
...(options.requirement ? [options.requirement] : []),
|
|
430
|
+
...(test?.targets ?? []),
|
|
431
|
+
];
|
|
432
|
+
const reqs = standard.requirements.filter(r => reqIds.includes(r.id));
|
|
433
|
+
const limitChain = reqs.flatMap(r => (r.limit ? [r] : []));
|
|
434
|
+
const verdictDefs = standard.verdicts;
|
|
435
|
+
for (const input of options.inputs) {
|
|
436
|
+
const runScope = {
|
|
437
|
+
...scope,
|
|
438
|
+
load_v: input.load_v,
|
|
439
|
+
e_l: input.e_l,
|
|
440
|
+
indication: input.e_l,
|
|
441
|
+
reference: 0,
|
|
442
|
+
};
|
|
443
|
+
for (const req of limitChain) {
|
|
444
|
+
const limit = req.limit;
|
|
445
|
+
const accepts = limit.accepts ? [limit.accepts] : [];
|
|
446
|
+
for (const acc of accepts) {
|
|
447
|
+
const vdef = verdictDefs.find(v => v.id === acc.verdict);
|
|
448
|
+
if (!vdef) {
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
let value;
|
|
452
|
+
try {
|
|
453
|
+
value = evaluateExpression(vdef.derive, runScope);
|
|
454
|
+
}
|
|
455
|
+
catch {
|
|
456
|
+
value = Number.NaN;
|
|
457
|
+
}
|
|
458
|
+
// The bound: the limit expression evaluated over the same scope
|
|
459
|
+
// (the MPE derivation — the tier selection over the applied
|
|
460
|
+
// load, scaled by the apportioning factor).
|
|
461
|
+
let bound = null;
|
|
462
|
+
const boundExpr = (limit.expression ?? '').trim();
|
|
463
|
+
if (boundExpr !== '') {
|
|
464
|
+
const calc = standard.calculations.find(c => c.id === boundExpr);
|
|
465
|
+
if (calc) {
|
|
466
|
+
try {
|
|
467
|
+
bound = evaluateExpression(calc.expression ?? '', runScope);
|
|
468
|
+
}
|
|
469
|
+
catch {
|
|
470
|
+
bound = null;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
try {
|
|
475
|
+
bound = evaluateExpression(boundExpr, runScope);
|
|
476
|
+
}
|
|
477
|
+
catch {
|
|
478
|
+
bound = null;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
const op = acc.op ?? 'lte';
|
|
483
|
+
const outcome = Number.isNaN(value) || bound === null
|
|
484
|
+
? 'indeterminate'
|
|
485
|
+
: op === 'lte'
|
|
486
|
+
? value <= bound
|
|
487
|
+
? 'pass'
|
|
488
|
+
: 'fail'
|
|
489
|
+
: op === 'lt'
|
|
490
|
+
? value < bound
|
|
491
|
+
? 'pass'
|
|
492
|
+
: 'fail'
|
|
493
|
+
: op === 'gte'
|
|
494
|
+
? value >= bound
|
|
495
|
+
? 'pass'
|
|
496
|
+
: 'fail'
|
|
497
|
+
: op === 'gt'
|
|
498
|
+
? value > bound
|
|
499
|
+
? 'pass'
|
|
500
|
+
: 'fail'
|
|
501
|
+
: value === bound
|
|
502
|
+
? 'pass'
|
|
503
|
+
: 'fail';
|
|
504
|
+
verdicts.push({
|
|
505
|
+
id: vdef.id,
|
|
506
|
+
derive: vdef.derive,
|
|
507
|
+
inputs: { e_l: input.e_l, load_v: input.load_v },
|
|
508
|
+
value,
|
|
509
|
+
unit: vdef.unit || undefined,
|
|
510
|
+
limit: boundExpr
|
|
511
|
+
? { expression: boundExpr, op, bound: bound ?? Number.NaN }
|
|
512
|
+
: undefined,
|
|
513
|
+
outcome,
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
// The formula leg: a limit whose uses name a declared calculation
|
|
517
|
+
// (R 60's `formula:mpe` — the tier selection) binds through it:
|
|
518
|
+
// the observed error against the calculation's value.
|
|
519
|
+
for (const use of limit.uses ?? []) {
|
|
520
|
+
if (!use.startsWith('formula:')) {
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
const calc = standard.calculations.find(c => c.id === use.slice('formula:'.length));
|
|
524
|
+
if (!calc?.expression) {
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
let bound;
|
|
528
|
+
try {
|
|
529
|
+
bound = evaluateExpression(calc.expression, runScope);
|
|
530
|
+
}
|
|
531
|
+
catch {
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
534
|
+
verdicts.push({
|
|
535
|
+
id: calc.id,
|
|
536
|
+
derive: calc.expression,
|
|
537
|
+
inputs: { e_l: input.e_l, load_v: input.load_v },
|
|
538
|
+
value: input.e_l,
|
|
539
|
+
limit: { expression: calc.id, op: 'lte', bound },
|
|
540
|
+
outcome: input.e_l <= bound ? 'pass' : 'fail',
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
// The named verdicts: the attestation claims' validated_by set.
|
|
545
|
+
// Every declared calculation's value binds into the scope under
|
|
546
|
+
// its id (mpe-verdict's derive reads `mpe`), then the derive
|
|
547
|
+
// evaluates as the judgment — truthy passes, falsy fails.
|
|
548
|
+
for (const vid of options.verdicts ?? []) {
|
|
549
|
+
const vdef = standard.verdicts.find(v => v.id === vid);
|
|
550
|
+
if (!vdef) {
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
const judgeScope = { ...runScope };
|
|
554
|
+
for (const calc of standard.calculations) {
|
|
555
|
+
if (!calc.expression || calc.id in judgeScope) {
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
try {
|
|
559
|
+
judgeScope[calc.id] = evaluateExpression(calc.expression, runScope);
|
|
560
|
+
}
|
|
561
|
+
catch {
|
|
562
|
+
// an unrestorable binding stays absent — the derive's own
|
|
563
|
+
// evaluation reports it
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
let outcome = 'indeterminate';
|
|
567
|
+
try {
|
|
568
|
+
outcome = evaluateExpression(vdef.derive, judgeScope) ? 'pass' : 'fail';
|
|
569
|
+
}
|
|
570
|
+
catch {
|
|
571
|
+
outcome = 'indeterminate';
|
|
572
|
+
}
|
|
573
|
+
verdicts.push({
|
|
574
|
+
id: vdef.id,
|
|
575
|
+
derive: vdef.derive,
|
|
576
|
+
inputs: { e_l: input.e_l, load_v: input.load_v },
|
|
577
|
+
value: input.e_l,
|
|
578
|
+
unit: vdef.unit || undefined,
|
|
579
|
+
outcome,
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
// The trajectory: the bound operational machine's fired steps (the
|
|
584
|
+
// runtime records what the run drove; the steps name transitions).
|
|
585
|
+
let trajectory = [];
|
|
586
|
+
const subject = standard.subjects.find(sub => sub.id === inst.of || sub.extends === inst.of);
|
|
587
|
+
const machineId = subject?.has?.state ?? '';
|
|
588
|
+
const machine = machineId
|
|
589
|
+
? standard.stateMachines.find(m => m.id === machineId ||
|
|
590
|
+
m.entityName === machineId)
|
|
591
|
+
: undefined;
|
|
592
|
+
if (machine) {
|
|
593
|
+
const fired = [];
|
|
594
|
+
for (const p of programs) {
|
|
595
|
+
const action = p.drive;
|
|
596
|
+
if (action && machine.transitions.some(t => t.actionName === action)) {
|
|
597
|
+
fired.push({
|
|
598
|
+
id: `${p.program}:${p.order ?? ''}`,
|
|
599
|
+
fires: action,
|
|
600
|
+
at: String(fired.length),
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
if (fired.length > 0) {
|
|
605
|
+
try {
|
|
606
|
+
trajectory = (0, operational_state_1.foldTrajectory)(machine, { state: machine.initialState, at: '0' }, fired);
|
|
607
|
+
}
|
|
608
|
+
catch {
|
|
609
|
+
trajectory = [];
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
// The evidence record: the run's outputs, per value with its
|
|
614
|
+
// provenance carried from the source attribute (the law's loop).
|
|
615
|
+
const evidence = [];
|
|
616
|
+
if (options.evidenceRegistry) {
|
|
617
|
+
const record = {
|
|
618
|
+
registry: options.evidenceRegistry,
|
|
619
|
+
run: options.runId ??
|
|
620
|
+
(options.test
|
|
621
|
+
? `${options.instance}:${options.test}`
|
|
622
|
+
: options.instance),
|
|
623
|
+
values: [
|
|
624
|
+
...options.inputs.map((inp, i) => ({
|
|
625
|
+
id: `load_v[${i}]`,
|
|
626
|
+
value: inp.load_v,
|
|
627
|
+
provenance: undefined,
|
|
628
|
+
})),
|
|
629
|
+
...verdicts.map((v, i) => ({
|
|
630
|
+
id: `${v.id}[${i}]`,
|
|
631
|
+
value: v.value,
|
|
632
|
+
unit: v.unit,
|
|
633
|
+
provenance: undefined,
|
|
634
|
+
})),
|
|
635
|
+
],
|
|
636
|
+
};
|
|
637
|
+
evidence.push(record);
|
|
638
|
+
}
|
|
639
|
+
return {
|
|
640
|
+
instance: options.instance,
|
|
641
|
+
test: options.test,
|
|
642
|
+
programs,
|
|
643
|
+
verdicts,
|
|
644
|
+
trajectory,
|
|
645
|
+
evidence,
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
//# sourceMappingURL=runtime.js.map
|