@primmel/primmel 1.20.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.
Files changed (136) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +7 -3
  4. package/dist/index.js.map +1 -1
  5. package/dist/src/check-rules.d.ts +1 -1
  6. package/dist/src/check-rules.d.ts.map +1 -1
  7. package/dist/src/check-rules.js +36 -15
  8. package/dist/src/check-rules.js.map +1 -1
  9. package/dist/src/check.d.ts +4 -0
  10. package/dist/src/check.d.ts.map +1 -1
  11. package/dist/src/check.js +428 -137
  12. package/dist/src/check.js.map +1 -1
  13. package/dist/src/export/cddal.d.ts +25 -0
  14. package/dist/src/export/cddal.d.ts.map +1 -0
  15. package/dist/src/export/cddal.js +213 -0
  16. package/dist/src/export/cddal.js.map +1 -0
  17. package/dist/src/export/retrieval.d.ts +147 -6
  18. package/dist/src/export/retrieval.d.ts.map +1 -1
  19. package/dist/src/export/retrieval.js +254 -25
  20. package/dist/src/export/retrieval.js.map +1 -1
  21. package/dist/src/export/unitsdb.d.ts +19 -0
  22. package/dist/src/export/unitsdb.d.ts.map +1 -0
  23. package/dist/src/export/unitsdb.js +82 -0
  24. package/dist/src/export/unitsdb.js.map +1 -0
  25. package/dist/src/export/yaml-lite.d.ts +13 -0
  26. package/dist/src/export/yaml-lite.d.ts.map +1 -0
  27. package/dist/src/export/yaml-lite.js +219 -0
  28. package/dist/src/export/yaml-lite.js.map +1 -0
  29. package/dist/src/instance-resolution.d.ts +19 -0
  30. package/dist/src/instance-resolution.d.ts.map +1 -1
  31. package/dist/src/instance-resolution.js +87 -1
  32. package/dist/src/instance-resolution.js.map +1 -1
  33. package/dist/src/model-diff.d.ts.map +1 -1
  34. package/dist/src/model-diff.js +0 -5
  35. package/dist/src/model-diff.js.map +1 -1
  36. package/dist/src/runtime.d.ts +143 -0
  37. package/dist/src/runtime.d.ts.map +1 -0
  38. package/dist/src/runtime.js +648 -0
  39. package/dist/src/runtime.js.map +1 -0
  40. package/dist/src/ser-des/config/artifact.d.ts.map +1 -1
  41. package/dist/src/ser-des/config/artifact.js +6 -0
  42. package/dist/src/ser-des/config/artifact.js.map +1 -1
  43. package/dist/src/ser-des/config/attestation.d.ts +5 -0
  44. package/dist/src/ser-des/config/attestation.d.ts.map +1 -0
  45. package/dist/src/ser-des/config/attestation.js +143 -0
  46. package/dist/src/ser-des/config/attestation.js.map +1 -0
  47. package/dist/src/ser-des/config/data.d.ts.map +1 -1
  48. package/dist/src/ser-des/config/data.js +98 -0
  49. package/dist/src/ser-des/config/data.js.map +1 -1
  50. package/dist/src/ser-des/config/documentModule.js +5 -5
  51. package/dist/src/ser-des/config/documentModule.js.map +1 -1
  52. package/dist/src/ser-des/config/index.d.ts +8 -0
  53. package/dist/src/ser-des/config/index.d.ts.map +1 -1
  54. package/dist/src/ser-des/config/index.js +22 -49
  55. package/dist/src/ser-des/config/index.js.map +1 -1
  56. package/dist/src/ser-des/config/instance.d.ts.map +1 -1
  57. package/dist/src/ser-des/config/instance.js +24 -0
  58. package/dist/src/ser-des/config/instance.js.map +1 -1
  59. package/dist/src/ser-des/config/process.d.ts.map +1 -1
  60. package/dist/src/ser-des/config/process.js +8 -0
  61. package/dist/src/ser-des/config/process.js.map +1 -1
  62. package/dist/src/ser-des/config/processSequence.d.ts +19 -0
  63. package/dist/src/ser-des/config/processSequence.d.ts.map +1 -0
  64. package/dist/src/ser-des/config/processSequence.js +77 -0
  65. package/dist/src/ser-des/config/processSequence.js.map +1 -0
  66. package/dist/src/ser-des/config/quantity.d.ts +4 -1
  67. package/dist/src/ser-des/config/quantity.d.ts.map +1 -1
  68. package/dist/src/ser-des/config/quantity.js +63 -1
  69. package/dist/src/ser-des/config/quantity.js.map +1 -1
  70. package/dist/src/ser-des/config/subject.d.ts.map +1 -1
  71. package/dist/src/ser-des/config/subject.js +14 -0
  72. package/dist/src/ser-des/config/subject.js.map +1 -1
  73. package/dist/src/ser-des/index.d.ts +4 -1
  74. package/dist/src/ser-des/index.d.ts.map +1 -1
  75. package/dist/src/ser-des/index.js +3 -1
  76. package/dist/src/ser-des/index.js.map +1 -1
  77. package/dist/src/ser-des/package.d.ts.map +1 -1
  78. package/dist/src/ser-des/package.js +9 -7
  79. package/dist/src/ser-des/package.js.map +1 -1
  80. package/dist/src/ser-des/parse.d.ts +24 -0
  81. package/dist/src/ser-des/parse.d.ts.map +1 -1
  82. package/dist/src/ser-des/parse.js +69 -33
  83. package/dist/src/ser-des/parse.js.map +1 -1
  84. package/dist/src/ser-des/shape-front-end.d.ts +8 -0
  85. package/dist/src/ser-des/shape-front-end.d.ts.map +1 -0
  86. package/dist/src/ser-des/shape-front-end.js +215 -0
  87. package/dist/src/ser-des/shape-front-end.js.map +1 -0
  88. package/dist/src/ser-des/types.d.ts +4 -10
  89. package/dist/src/ser-des/types.d.ts.map +1 -1
  90. package/dist/src/types/Artifact.d.ts +7 -0
  91. package/dist/src/types/Artifact.d.ts.map +1 -1
  92. package/dist/src/types/Attestation.d.ts +60 -0
  93. package/dist/src/types/Attestation.d.ts.map +1 -0
  94. package/dist/src/types/Attestation.js +20 -0
  95. package/dist/src/types/Attestation.js.map +1 -0
  96. package/dist/src/types/DocumentModule.d.ts +1 -1
  97. package/dist/src/types/DocumentModule.d.ts.map +1 -1
  98. package/dist/src/types/Instance.d.ts +6 -2
  99. package/dist/src/types/Instance.d.ts.map +1 -1
  100. package/dist/src/types/ProcessModel.d.ts +0 -11
  101. package/dist/src/types/ProcessModel.d.ts.map +1 -1
  102. package/dist/src/types/ProcessModel.js +2 -28
  103. package/dist/src/types/ProcessModel.js.map +1 -1
  104. package/dist/src/types/Quantity.d.ts +22 -0
  105. package/dist/src/types/Quantity.d.ts.map +1 -1
  106. package/dist/src/types/Standard.d.ts +2 -13
  107. package/dist/src/types/Standard.d.ts.map +1 -1
  108. package/dist/src/types/Subject.d.ts +14 -0
  109. package/dist/src/types/Subject.d.ts.map +1 -1
  110. package/dist/src/types/data.d.ts +13 -0
  111. package/dist/src/types/data.d.ts.map +1 -1
  112. package/dist/src/types/process.d.ts +8 -0
  113. package/dist/src/types/process.d.ts.map +1 -1
  114. package/dist-browser/index.mjs +1746 -1829
  115. package/dist-cli/primmel.mjs +1630 -845
  116. package/package.json +15 -3
  117. package/dist/src/ser-des/config/processModel.d.ts +0 -13
  118. package/dist/src/ser-des/config/processModel.d.ts.map +0 -1
  119. package/dist/src/ser-des/config/processModel.js +0 -163
  120. package/dist/src/ser-des/config/processModel.js.map +0 -1
  121. package/dist/src/ser-des/config/storyline.d.ts +0 -7
  122. package/dist/src/ser-des/config/storyline.d.ts.map +0 -1
  123. package/dist/src/ser-des/config/storyline.js +0 -264
  124. package/dist/src/ser-des/config/storyline.js.map +0 -1
  125. package/dist/src/ser-des/config/workflowConfig.d.ts +0 -5
  126. package/dist/src/ser-des/config/workflowConfig.d.ts.map +0 -1
  127. package/dist/src/ser-des/config/workflowConfig.js +0 -129
  128. package/dist/src/ser-des/config/workflowConfig.js.map +0 -1
  129. package/dist/src/ser-des/config/workflowStage.d.ts +0 -5
  130. package/dist/src/ser-des/config/workflowStage.d.ts.map +0 -1
  131. package/dist/src/ser-des/config/workflowStage.js +0 -96
  132. package/dist/src/ser-des/config/workflowStage.js.map +0 -1
  133. package/dist/src/types/Storyline.d.ts +0 -62
  134. package/dist/src/types/Storyline.d.ts.map +0 -1
  135. package/dist/src/types/Storyline.js +0 -51
  136. 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