@primmel/primmel 1.20.0 → 1.21.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.
Files changed (141) 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 +446 -138
  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/certificateTemplate.d.ts.map +1 -1
  48. package/dist/src/ser-des/config/certificateTemplate.js +7 -1
  49. package/dist/src/ser-des/config/certificateTemplate.js.map +1 -1
  50. package/dist/src/ser-des/config/data.d.ts.map +1 -1
  51. package/dist/src/ser-des/config/data.js +98 -0
  52. package/dist/src/ser-des/config/data.js.map +1 -1
  53. package/dist/src/ser-des/config/documentModule.js +5 -5
  54. package/dist/src/ser-des/config/documentModule.js.map +1 -1
  55. package/dist/src/ser-des/config/index.d.ts +8 -0
  56. package/dist/src/ser-des/config/index.d.ts.map +1 -1
  57. package/dist/src/ser-des/config/index.js +22 -49
  58. package/dist/src/ser-des/config/index.js.map +1 -1
  59. package/dist/src/ser-des/config/instance.d.ts.map +1 -1
  60. package/dist/src/ser-des/config/instance.js +24 -0
  61. package/dist/src/ser-des/config/instance.js.map +1 -1
  62. package/dist/src/ser-des/config/process.d.ts.map +1 -1
  63. package/dist/src/ser-des/config/process.js +8 -0
  64. package/dist/src/ser-des/config/process.js.map +1 -1
  65. package/dist/src/ser-des/config/processSequence.d.ts +19 -0
  66. package/dist/src/ser-des/config/processSequence.d.ts.map +1 -0
  67. package/dist/src/ser-des/config/processSequence.js +77 -0
  68. package/dist/src/ser-des/config/processSequence.js.map +1 -0
  69. package/dist/src/ser-des/config/quantity.d.ts +4 -1
  70. package/dist/src/ser-des/config/quantity.d.ts.map +1 -1
  71. package/dist/src/ser-des/config/quantity.js +63 -1
  72. package/dist/src/ser-des/config/quantity.js.map +1 -1
  73. package/dist/src/ser-des/config/subject.d.ts.map +1 -1
  74. package/dist/src/ser-des/config/subject.js +20 -0
  75. package/dist/src/ser-des/config/subject.js.map +1 -1
  76. package/dist/src/ser-des/index.d.ts +4 -1
  77. package/dist/src/ser-des/index.d.ts.map +1 -1
  78. package/dist/src/ser-des/index.js +3 -1
  79. package/dist/src/ser-des/index.js.map +1 -1
  80. package/dist/src/ser-des/package.d.ts.map +1 -1
  81. package/dist/src/ser-des/package.js +24 -7
  82. package/dist/src/ser-des/package.js.map +1 -1
  83. package/dist/src/ser-des/parse.d.ts +24 -0
  84. package/dist/src/ser-des/parse.d.ts.map +1 -1
  85. package/dist/src/ser-des/parse.js +69 -33
  86. package/dist/src/ser-des/parse.js.map +1 -1
  87. package/dist/src/ser-des/shape-front-end.d.ts +8 -0
  88. package/dist/src/ser-des/shape-front-end.d.ts.map +1 -0
  89. package/dist/src/ser-des/shape-front-end.js +215 -0
  90. package/dist/src/ser-des/shape-front-end.js.map +1 -0
  91. package/dist/src/ser-des/types.d.ts +4 -10
  92. package/dist/src/ser-des/types.d.ts.map +1 -1
  93. package/dist/src/types/Artifact.d.ts +7 -0
  94. package/dist/src/types/Artifact.d.ts.map +1 -1
  95. package/dist/src/types/Attestation.d.ts +60 -0
  96. package/dist/src/types/Attestation.d.ts.map +1 -0
  97. package/dist/src/types/Attestation.js +20 -0
  98. package/dist/src/types/Attestation.js.map +1 -0
  99. package/dist/src/types/CertificateTemplate.d.ts +4 -0
  100. package/dist/src/types/CertificateTemplate.d.ts.map +1 -1
  101. package/dist/src/types/DocumentModule.d.ts +1 -1
  102. package/dist/src/types/DocumentModule.d.ts.map +1 -1
  103. package/dist/src/types/Instance.d.ts +6 -2
  104. package/dist/src/types/Instance.d.ts.map +1 -1
  105. package/dist/src/types/ProcessModel.d.ts +0 -11
  106. package/dist/src/types/ProcessModel.d.ts.map +1 -1
  107. package/dist/src/types/ProcessModel.js +2 -28
  108. package/dist/src/types/ProcessModel.js.map +1 -1
  109. package/dist/src/types/Quantity.d.ts +22 -0
  110. package/dist/src/types/Quantity.d.ts.map +1 -1
  111. package/dist/src/types/Standard.d.ts +2 -13
  112. package/dist/src/types/Standard.d.ts.map +1 -1
  113. package/dist/src/types/Subject.d.ts +18 -0
  114. package/dist/src/types/Subject.d.ts.map +1 -1
  115. package/dist/src/types/data.d.ts +13 -0
  116. package/dist/src/types/data.d.ts.map +1 -1
  117. package/dist/src/types/process.d.ts +8 -0
  118. package/dist/src/types/process.d.ts.map +1 -1
  119. package/dist-browser/index.mjs +1756 -1832
  120. package/dist-cli/primmel.mjs +1659 -847
  121. package/package.json +15 -3
  122. package/dist/src/ser-des/config/processModel.d.ts +0 -13
  123. package/dist/src/ser-des/config/processModel.d.ts.map +0 -1
  124. package/dist/src/ser-des/config/processModel.js +0 -163
  125. package/dist/src/ser-des/config/processModel.js.map +0 -1
  126. package/dist/src/ser-des/config/storyline.d.ts +0 -7
  127. package/dist/src/ser-des/config/storyline.d.ts.map +0 -1
  128. package/dist/src/ser-des/config/storyline.js +0 -264
  129. package/dist/src/ser-des/config/storyline.js.map +0 -1
  130. package/dist/src/ser-des/config/workflowConfig.d.ts +0 -5
  131. package/dist/src/ser-des/config/workflowConfig.d.ts.map +0 -1
  132. package/dist/src/ser-des/config/workflowConfig.js +0 -129
  133. package/dist/src/ser-des/config/workflowConfig.js.map +0 -1
  134. package/dist/src/ser-des/config/workflowStage.d.ts +0 -5
  135. package/dist/src/ser-des/config/workflowStage.d.ts.map +0 -1
  136. package/dist/src/ser-des/config/workflowStage.js +0 -96
  137. package/dist/src/ser-des/config/workflowStage.js.map +0 -1
  138. package/dist/src/types/Storyline.d.ts +0 -62
  139. package/dist/src/types/Storyline.d.ts.map +0 -1
  140. package/dist/src/types/Storyline.js +0 -51
  141. package/dist/src/types/Storyline.js.map +0 -1
package/dist/src/check.js CHANGED
@@ -360,22 +360,6 @@
360
360
  // part_annex register's declaration shape — letters unique per
361
361
  // package, the source provenance required; the obligation
362
362
  // vocabulary is parse-enforced upstream
363
- // C129 storyline-shape (smart TODO.roadmap/40 batch 4): the demo-seed
364
- // shapes — the id_prefix pattern (register-free), party →
365
- // demo_world participant seeds (gated), record stores → entity-
366
- // class stores (gated), in-construct record cross-references
367
- // (ungated); field-level discipline stays app-side
368
- // C144–C146 the license facets (smart TODO.external-refs/04; the
369
- // entitlement facet + catalog): the catalog-key shape
370
- // (^std:[a-z0-9-]+$), at most one license_key per package (the
371
- // parser's earlier declarations surface here), and the
372
- // license_holder required with the key — a package without a key
373
- // is public content and every leg keys on the key's presence
374
- // C147–C148 the executable test programs (smart TODO.twin-demo/03;
375
- // the model-drive bindings): the preparation/stimulus entry-order
376
- // and step/point shape, and the hold/fresh_within duration
377
- // discipline (a stimulus point declares fresh_within — §14.12's
378
- // no-stale-semantics doctrine)
379
363
  //
380
364
  // Levels (TODO.roadmap/17): the DEFAULT level runs the normal-level
381
365
  // rules at their catalog severities. --audit additionally runs the
@@ -402,6 +386,10 @@
402
386
  Object.defineProperty(exports, "__esModule", { value: true });
403
387
  exports.checkPackage = checkPackage;
404
388
  exports.checkManifestResolution = checkManifestResolution;
389
+ exports.checkArtifactContracts = checkArtifactContracts;
390
+ exports.checkTypedPayloads = checkTypedPayloads;
391
+ exports.checkAttestations = checkAttestations;
392
+ exports.checkClosedDerivations = checkClosedDerivations;
405
393
  exports.checkSpellingCodes = checkSpellingCodes;
406
394
  exports.checkDeclaredPredicates = checkDeclaredPredicates;
407
395
  exports.checkTermAliases = checkTermAliases;
@@ -426,6 +414,7 @@ const FormulasUsed_1 = require("./types/FormulasUsed");
426
414
  const tokenize_1 = require("./ser-des/tokenize");
427
415
  const operational_state_1 = require("./operational-state");
428
416
  const check_rules_1 = require("./check-rules");
417
+ const instance_resolution_1 = require("./instance-resolution");
429
418
  const check_allowlist_1 = require("./check-allowlist");
430
419
  const text_coverage_1 = require("./text-coverage");
431
420
  const spelling_1 = require("./spelling");
@@ -490,7 +479,12 @@ function checkPackage(dir, options = {}) {
490
479
  });
491
480
  standard = loaded.standard;
492
481
  for (const i of loaded.issues) {
493
- if (i.code === 'provides-unconsumed') {
482
+ // The deprecation report (phase 2): the parse-time issue maps to
483
+ // its rule.
484
+ if (i.code === 'construct-deprecated') {
485
+ warn('C154', i.message);
486
+ }
487
+ else if (i.code === 'provides-unconsumed') {
494
488
  warn('C30', i.message);
495
489
  }
496
490
  else if (i.code === 'extends-deprecated') {
@@ -545,11 +539,20 @@ function checkPackage(dir, options = {}) {
545
539
  issues.push(...checkReferences(standard));
546
540
  // ── C116/C117: the verdict chain (MN 114 v3.2, clause 11.3) ────────
547
541
  issues.push(...checkVerdictChains(standard));
542
+ // ── C149: the closed-derivation rule (the typed kernel, R3) ────────
543
+ issues.push(...checkClosedDerivations(standard));
544
+ // ── C150/C151: the attestation's references and claim lineage ──────
545
+ issues.push(...checkAttestations(standard));
546
+ // ── C152: the typed payload rule (the typed kernel, R2) ────────────
547
+ issues.push(...checkTypedPayloads(standard));
548
+ // ── C153: the contract-derivation facet (the typed kernel, clause 10)
549
+ issues.push(...checkArtifactContracts(standard));
548
550
  const reqIds = new Set((standard.requirements ?? []).map((r) => r.id));
549
551
  const testIds = new Set((standard.conformanceTests ?? []).map((t) => t.id));
550
552
  const attrIds = new Set((standard.attributeDefinitions ?? []).map((a) => a.id));
553
+ const roleIds = new Set((standard.roles ?? []).map(r => r.id));
551
554
  const behaviorIds = new Set((standard.behaviors ?? []).map((b) => b.id));
552
- const subjectIds = new Set((standard.subjects ?? []).map((s) => s.id));
555
+ const subjectIds = new Set((standard.subjects ?? []).map(s => s.id));
553
556
  // Observables live in the symbols registry, not the attribute layer —
554
557
  // binds_to / limit.uses may reference them (e.g. sample.test_context
555
558
  // quantities that are measured test outputs).
@@ -1162,7 +1165,9 @@ function checkPackage(dir, options = {}) {
1162
1165
  // C45 — artifact-def-contract: the content contract is well-formed.
1163
1166
  for (const d of standard.artifactDefinitions ?? []) {
1164
1167
  const c = d.contentContract;
1165
- if (c.fields.length === 0) {
1168
+ // A derived contract (contract_from, C153) is the referenced
1169
+ // promise set's projection — its fields are the set's.
1170
+ if (!d.contractFrom && c.fields.length === 0) {
1166
1171
  err('C45', `artifact definition ${d.id}: content contract declares no fields — a definition must contract SOME content (artifact-def-contract)`);
1167
1172
  }
1168
1173
  const seenFields = new Set();
@@ -1697,15 +1702,6 @@ function checkPackage(dir, options = {}) {
1697
1702
  }
1698
1703
  }
1699
1704
  }
1700
- for (const m of standard.processModels ?? []) {
1701
- const where = `process_model ${m.id}`;
1702
- for (const s of m.sequence ?? []) {
1703
- resolveProcessRef(where, 'sequence', s);
1704
- }
1705
- for (const r of m.registers ?? []) {
1706
- resolveOrganAp(`${where} register ${r.id}`, 'maintainer', r.maintainer);
1707
- }
1708
- }
1709
1705
  }
1710
1706
  // ── C84: constraint-shape (TODO.roadmap/51 — BUG.R60-SSOT gap 7) ─────
1711
1707
  // The subject-intrinsic constraint's DECLARATION shape — the kernel
@@ -2039,7 +2035,6 @@ function checkPackage(dir, options = {}) {
2039
2035
  // escalation ACTIONS are runtime — the smart app's monitor service owns
2040
2036
  // them; these rules guarantee the declarations the runtime needs.
2041
2037
  {
2042
- const roleIds = new Set((standard.roles ?? []).map(r => r.id));
2043
2038
  const KNOWN_OUTCOMES = new Set(Monitor_1.MONITOR_OUTCOMES);
2044
2039
  const KNOWN_ACTIONS = new Set(Monitor_1.MONITOR_ESCALATION_ACTIONS);
2045
2040
  const KNOWN_STREAMS = new Set(Monitor_1.MONITOR_STREAMS);
@@ -2343,6 +2338,12 @@ function checkPackage(dir, options = {}) {
2343
2338
  };
2344
2339
  const instrumentIds = new Set((standard.instruments ?? []).map(i => i.id));
2345
2340
  const instanceIds = new Set((standard.instances ?? []).map(i => i.id));
2341
+ const dataclassIds = new Set((standard.dataclasses ?? []).map(c => c.id));
2342
+ // The BARE-PREFIX link spelling: a class's extends may name a class
2343
+ // without its plane segment (Organization for Organization#data —
2344
+ // the language's own link spelling; the pre-1.21.0 checker and the
2345
+ // platform linker resolve it). C156 resolves both spellings.
2346
+ const dataclassBareIds = new Set((standard.dataclasses ?? []).map(c => c.id.split('#')[0]));
2346
2347
  const attrScopes = new Map((standard.attributeDefinitions ?? []).map(a => [a.id, a.scope]));
2347
2348
  // Classification-dimension scopes, by every spelling a classification
2348
2349
  // map may use: the instrument dimension id, the is_dimension attribute
@@ -2436,9 +2437,54 @@ function checkPackage(dir, options = {}) {
2436
2437
  }
2437
2438
  }
2438
2439
  // C20 — instance-of-resolves: the `of` reference names a declared
2439
- // subject (v3) or instrument (v2) definition.
2440
- if (!subjectIds.has(inst.of) && !instrumentIds.has(inst.of)) {
2441
- err('C20', `instance ${inst.id}: of "${inst.of}" is not a declared subject or instrument (instance-of-resolves)`);
2440
+ // subject (v3), instrument (v2), or ANOTHER INSTANCE (the power-type
2441
+ // discipline — every instance can serve as the definition of further
2442
+ // instantiation).
2443
+ if (!subjectIds.has(inst.of) &&
2444
+ !instrumentIds.has(inst.of) &&
2445
+ !instanceIds.has(inst.of) &&
2446
+ !dataclassIds.has(inst.of)) {
2447
+ err('C20', `instance ${inst.id}: of "${inst.of}" is not a declared subject, instrument, class, or instance (instance-of-resolves)`);
2448
+ }
2449
+ // C155 — power-type-chain (coherence leg): an instance whose `of`
2450
+ // names another instance carries NO upward subject-chain link — the
2451
+ // two are one pattern's two spellings, and mixing them makes the
2452
+ // delegation walk ambiguous.
2453
+ if (instanceIds.has(inst.of)) {
2454
+ const links = ['model', 'group', 'family'].filter(k => inst[k]);
2455
+ if (links.length > 0) {
2456
+ err('C155', `instance ${inst.id}: of "${inst.of}" names an instance and the instance carries an upward ${links.join('/')} link — the power-type chain and the subject-chain profile do not mix (power-type-chain)`);
2457
+ }
2458
+ }
2459
+ }
2460
+ // C155 — power-type-chain (acyclicity leg): the MIXED delegation
2461
+ // graph — of-chains to instances AND the prototype hop (an `of` to a
2462
+ // class whose extends names an instance) — is acyclic: a cycle over
2463
+ // these edges would make the delegation walk non-terminating, and a
2464
+ // class instantiating its own prototype (`instance x of C` while
2465
+ // `C extends { x }`) is the shapes' own mutual recursion.
2466
+ const delegation = (0, instance_resolution_1.delegationSuccessors)(standard);
2467
+ const ofAdj = new Map();
2468
+ for (const [from, to] of delegation) {
2469
+ if (instanceIds.has(to)) {
2470
+ ofAdj.set(from, [to]);
2471
+ }
2472
+ }
2473
+ const ofCycle = findCycle(ofAdj);
2474
+ if (ofCycle) {
2475
+ err('C155', `the power-type of-chain is cyclic: ${ofCycle.join(' → ')} (power-type-chain)`);
2476
+ }
2477
+ // C156 — class-extends-resolves: a class's extends names a declared
2478
+ // class or a declared INSTANCE (the definition side of the power-type
2479
+ // discipline — a class extending an instance specializes that
2480
+ // individual). Successfully merged links clear at resolve time, so a
2481
+ // surviving link is exactly an unresolved one.
2482
+ for (const c of standard.dataclasses ?? []) {
2483
+ if (c.extends &&
2484
+ !dataclassIds.has(c.extends) &&
2485
+ !dataclassBareIds.has(c.extends) &&
2486
+ !instanceIds.has(c.extends)) {
2487
+ warn('C156', `class ${c.id}: extends "${c.extends}" is not a declared class or instance (class-extends-resolves)`);
2442
2488
  }
2443
2489
  }
2444
2490
  // C19 — chain-acyclic (integrity part 2): the resolved link graph is
@@ -3321,6 +3367,13 @@ function checkPackage(dir, options = {}) {
3321
3367
  }
3322
3368
  const unitToKind = new Map(); // unit id|symbol → kind id
3323
3369
  const unitHome = new Map(); // unit id|symbol → register id
3370
+ // The full entry behind each key: a redeclaration that is
3371
+ // IDENTICAL (same kind, factor, symbol) is idempotent under
3372
+ // composition — the sibling IEC packages each declare kV/degC for
3373
+ // standalone self-containment, and the merged register set carries
3374
+ // one shared entry, not a conflict. Only a CONFLICTING entry (the
3375
+ // same key, different meaning) is a redefinition.
3376
+ const unitEntry = new Map(); // key → kind|factor|symbol
3324
3377
  const registersExist = (standard.quantityRegisters ?? []).length > 0;
3325
3378
  for (const reg of standard.quantityRegisters ?? []) {
3326
3379
  for (const u of reg.units) {
@@ -3330,13 +3383,17 @@ function checkPackage(dir, options = {}) {
3330
3383
  }
3331
3384
  // C33 — no cross-register redefinition: a rec EXTENDS the register
3332
3385
  // with domain units; it never redefines an existing entry.
3386
+ const entry = `${u.kind}|${u.factorToSI}|${u.offsetToSI ?? ''}|${u.symbol}`;
3333
3387
  for (const key of new Set([u.id, u.symbol].filter(s => s))) {
3334
3388
  const prior = unitHome.get(key);
3335
3389
  if (prior !== undefined) {
3336
- err('C33', `quantity_register ${reg.id}: unit "${u.id}" ("${key}") redefines a unit already declared by register "${prior}" — a package extends the register, it never redefines entries (quantity-coherence)`);
3390
+ if (unitEntry.get(key) !== entry) {
3391
+ err('C33', `quantity_register ${reg.id}: unit "${u.id}" ("${key}") redefines a unit already declared by register "${prior}" — a package extends the register, it never redefines entries (quantity-coherence)`);
3392
+ }
3337
3393
  }
3338
3394
  else {
3339
3395
  unitHome.set(key, reg.id);
3396
+ unitEntry.set(key, entry);
3340
3397
  unitToKind.set(key, u.kind);
3341
3398
  }
3342
3399
  }
@@ -3694,68 +3751,6 @@ function checkPackage(dir, options = {}) {
3694
3751
  }
3695
3752
  }
3696
3753
  }
3697
- // ── C129: storyline-shape (smart TODO.roadmap/40 batch 4; the ──────
3698
- // packages-as-SSOT epic) ────────────────────────────────────────────
3699
- // The demo-seed shapes: the id_prefix pattern (the register-free shape
3700
- // leg); the party laboratory/authority resolve against the package's
3701
- // participant seeds WHEN a demo_world with participants is in scope
3702
- // (per-register gating, the C58 doctrine); the record stores resolve
3703
- // against the declared entity-class stores WHEN that register is in
3704
- // scope; and the in-construct cross-references resolve — a record
3705
- // field keyed by a sibling record's store names a sibling record of
3706
- // that store (in-construct, ungated). The field-level discipline (the
3707
- // schema's per-slot required fields) stays app-side.
3708
- {
3709
- const participantSeeds = new Set();
3710
- for (const w of standard.demoWorlds ?? []) {
3711
- for (const section of w.participants ?? []) {
3712
- for (const e of section.entries ?? []) {
3713
- participantSeeds.add(e.id);
3714
- }
3715
- }
3716
- }
3717
- const entityStores = new Set((standard.dataclasses ?? [])
3718
- .map(c => c.store)
3719
- .filter((s) => !!s));
3720
- for (const s of standard.storylines ?? []) {
3721
- const where = `storyline ${s.id}`;
3722
- if (s.idPrefix && !/^[a-z0-9-]+$/.test(s.idPrefix)) {
3723
- err('C129', `${where}: id_prefix "${s.idPrefix}" does not match ^[a-z0-9-]+$ — the id-minting prefix is a lowercase slug (storyline-shape)`);
3724
- }
3725
- if (participantSeeds.size > 0) {
3726
- for (const [slot, ref] of [
3727
- ['laboratory', s.party.laboratory],
3728
- ['authority', s.party.authority],
3729
- ]) {
3730
- if (ref && !participantSeeds.has(ref)) {
3731
- err('C129', `${where}: party ${slot} "${ref}" is not a declared participant seed (storyline-shape)`);
3732
- }
3733
- }
3734
- }
3735
- const siblingStores = new Map();
3736
- for (const r of s.records ?? []) {
3737
- if (entityStores.size > 0 && !entityStores.has(r.store)) {
3738
- err('C129', `${where}: record store "${r.store}" is not a declared entity-class store (storyline-shape)`);
3739
- }
3740
- let ids = siblingStores.get(r.store);
3741
- if (!ids) {
3742
- ids = new Set();
3743
- siblingStores.set(r.store, ids);
3744
- }
3745
- ids.add(r.id);
3746
- }
3747
- for (const r of s.records ?? []) {
3748
- for (const [key, value] of Object.entries(r.fields)) {
3749
- const targets = siblingStores.get(key);
3750
- if (targets !== undefined &&
3751
- !Array.isArray(value) &&
3752
- !targets.has(String(value))) {
3753
- err('C129', `${where}: record ${r.store} ${r.id}: ${key} "${String(value)}" is not a sibling ${key} record of this storyline (storyline-shape)`);
3754
- }
3755
- }
3756
- }
3757
- }
3758
- }
3759
3754
  // ── C130: identity-and-aspect-references (smart TODO.roadmap/40 ─────
3760
3755
  // batch 3; the packages-as-SSOT epic) ────────────────────────────────
3761
3756
  // The documentary identity slots + the qualitative aspect register
@@ -4126,7 +4121,6 @@ function checkPackage(dir, options = {}) {
4126
4121
  // (the R26 field-resolution precedent). The phase vocabulary is
4127
4122
  // parse-enforced upstream (no check leg).
4128
4123
  {
4129
- const roleIds = new Set((standard.roles ?? []).map(r => r.id));
4130
4124
  // Class ids may carry a namespace suffix (`Application#data`) while
4131
4125
  // the workflow's inputs/outputs spell the bare entity name — index
4132
4126
  // both spellings (the semantic-status leg's precedent).
@@ -4137,28 +4131,6 @@ function checkPackage(dir, options = {}) {
4137
4131
  dataclassIds.add(c.id.slice(0, c.id.indexOf('#')));
4138
4132
  }
4139
4133
  }
4140
- const CLEAN_TOKEN = /^[A-Za-z_][A-Za-z0-9_]*$/;
4141
- for (const w of standard.workflowConfigs ?? []) {
4142
- for (const s of w.steps ?? []) {
4143
- const where = `workflow_config ${w.id}: step ${s.id}`;
4144
- if (s.actor && roleIds.size > 0 && !roleIds.has(s.actor)) {
4145
- err('C137', `${where}: actor "${s.actor}" is not a declared role (workflow-config-references)`);
4146
- }
4147
- for (const [facet, list] of [
4148
- ['inputs', s.inputs],
4149
- ['outputs', s.outputs],
4150
- ]) {
4151
- for (const entry of list) {
4152
- if (!CLEAN_TOKEN.test(entry)) {
4153
- continue; // a composite documentary string — never resolved
4154
- }
4155
- if (dataclassIds.size > 0 && !dataclassIds.has(entry)) {
4156
- err('C137', `${where}: ${facet} entry "${entry}" is not a declared data class (workflow-config-references)`);
4157
- }
4158
- }
4159
- }
4160
- }
4161
- }
4162
4134
  }
4163
4135
  // ── C138: verification-pathway-references (smart TODO.roadmap/40 ───
4164
4136
  // batch 3; the packages-as-SSOT epic) ────────────────────────────────
@@ -4405,26 +4377,6 @@ function checkPackage(dir, options = {}) {
4405
4377
  }
4406
4378
  // The workflow_stage members-resolve legs (step 5d) — the events
4407
4379
  // stay documentary, never resolved.
4408
- const stageApprovalIds = new Set((standard.approvals ?? []).map(a => a.id));
4409
- const stageGatewayIds = new Set((standard.gateways ?? []).map(g => g.id));
4410
- for (const s of standard.workflowStages ?? []) {
4411
- const where = `workflow_stage ${s.id}`;
4412
- for (const el of s.elements ?? []) {
4413
- if (gwProcessIds.size > 0 && !gwProcessIds.has(el)) {
4414
- err('C142', `${where}: element "${el}" is not a declared process (gateway-edges-resolve)`);
4415
- }
4416
- }
4417
- for (const a of s.approvals ?? []) {
4418
- if (stageApprovalIds.size > 0 && !stageApprovalIds.has(a)) {
4419
- err('C142', `${where}: approval "${a}" is not a declared approval (gateway-edges-resolve)`);
4420
- }
4421
- }
4422
- for (const g of s.gateways ?? []) {
4423
- if (stageGatewayIds.size > 0 && !stageGatewayIds.has(g)) {
4424
- err('C142', `${where}: gateway "${g}" is not a declared gateway (gateway-edges-resolve)`);
4425
- }
4426
- }
4427
- }
4428
4380
  }
4429
4381
  // ── C143: approval-references-resolve (smart TODO.roadmap/40 batch ──
4430
4382
  // 5; the packages-as-SSOT epic) ─────────────────────────────────────
@@ -5678,6 +5630,362 @@ function textAddressKey(item, segment) {
5678
5630
  * (titular:source:target:identifying); a `zz-` user-assigned code
5679
5631
  * validates with a warning (user-assigned codes are not portable).
5680
5632
  */
5633
+ // ── C153: artifact-contract-derivation (the typed kernel, clause 10) ─
5634
+ // An artifact definition whose content is the projection of declared
5635
+ // claims declares contract_from; the referenced set resolves, and a
5636
+ // definition that restates inline fields while deriving its contract
5637
+ // is the restatement the rule exists to prevent.
5638
+ function checkArtifactContracts(standard) {
5639
+ const issues = [];
5640
+ const err = (check, message) => issues.push({ check, severity: 'error', message });
5641
+ const setIds = new Set();
5642
+ for (const ps of standard.promiseSets ?? []) {
5643
+ setIds.add(ps.id);
5644
+ setIds.add(`${ps.id}.promise_set`);
5645
+ }
5646
+ for (const s of standard.subjects ?? []) {
5647
+ if ((s.is?.promises ?? []).length > 0) {
5648
+ setIds.add(s.id);
5649
+ setIds.add(`${s.id}.promise_set`);
5650
+ }
5651
+ }
5652
+ for (const d of standard.artifactDefinitions ?? []) {
5653
+ if (!d.contractFrom) {
5654
+ continue;
5655
+ }
5656
+ if (!setIds.has(d.contractFrom)) {
5657
+ err('C153', `artifact_definition ${d.id}: contract_from "${d.contractFrom}" does not resolve to a declared promise set (artifact-contract-derivation)`);
5658
+ }
5659
+ const c = d.contentContract;
5660
+ if (c.fields.length > 0 || c.structure || c.media.length > 0) {
5661
+ err('C153', `artifact_definition ${d.id}: declares both contract_from and inline contract fields — the derived contract is the referenced set's projection, never a restatement (artifact-contract-derivation)`);
5662
+ }
5663
+ }
5664
+ return issues;
5665
+ }
5666
+ // ── C152: payload-typed-by-class (the typed kernel R2, clause 10) ────
5667
+ // A dimension that declares payload_class types every value's
5668
+ // definition: the class resolves, every payload field is a field of
5669
+ // that class, and every value carries its definition — a value IS its
5670
+ // definition, not a symbol pointing at a table. The attribute-side
5671
+ // bridge resolves too: an attribute_definition's class reference names
5672
+ // a declared class.
5673
+ function checkTypedPayloads(standard) {
5674
+ const issues = [];
5675
+ const err = (check, message) => issues.push({ check, severity: 'error', message });
5676
+ const classFields = new Map();
5677
+ for (const c of standard.dataclasses ?? []) {
5678
+ classFields.set(c.id, new Set(c.attributes.map(a => a.id)));
5679
+ }
5680
+ // The power-type discipline reaches the typing bridge: an INSTANCE
5681
+ // is a class, and its shape is the fields of the class its `of`
5682
+ // chain terminates at (the prototype hop's mirror — an individual
5683
+ // typed by its definition's fields).
5684
+ const instanceShape = (id) => {
5685
+ const inst = (standard.instances ?? []).find(i => i.id === id);
5686
+ if (!inst) {
5687
+ return undefined;
5688
+ }
5689
+ let cur = inst;
5690
+ const seen = new Set([cur.id]);
5691
+ while (cur.of) {
5692
+ const next = (standard.instances ?? []).find(i => i.id === cur.of);
5693
+ if (!next || seen.has(next.id)) {
5694
+ break;
5695
+ }
5696
+ seen.add(next.id);
5697
+ cur = next;
5698
+ }
5699
+ return cur.of !== '' ? classFields.get(cur.of) : undefined;
5700
+ };
5701
+ const typedFields = (id) => classFields.get(id) ?? instanceShape(id);
5702
+ const checkDim = (owner, d) => {
5703
+ if (!d.payloadClass) {
5704
+ return;
5705
+ }
5706
+ const fields = typedFields(d.payloadClass);
5707
+ if (!fields) {
5708
+ err('C152', `${owner} dimension ${d.id}: payload_class "${d.payloadClass}" is not a declared class (payload-typed-by-class)`);
5709
+ return;
5710
+ }
5711
+ for (const v of d.values) {
5712
+ const keys = Object.keys(v.payload ?? {});
5713
+ if (keys.length === 0) {
5714
+ err('C152', `${owner} dimension ${d.id}: value ${v.id} carries no payload — a value of a payload_class dimension IS its definition (payload-typed-by-class)`);
5715
+ continue;
5716
+ }
5717
+ for (const key of keys) {
5718
+ if (!fields.has(key)) {
5719
+ err('C152', `${owner} dimension ${d.id}: value ${v.id} payload field "${key}" is not a field of class "${d.payloadClass}" (payload-typed-by-class)`);
5720
+ }
5721
+ }
5722
+ }
5723
+ };
5724
+ for (const inst of standard.instruments ?? []) {
5725
+ for (const d of inst.dimensions ?? []) {
5726
+ checkDim(`instrument ${inst.id}`, d);
5727
+ }
5728
+ }
5729
+ for (const d of standard.dimensions ?? []) {
5730
+ checkDim('top-level', d);
5731
+ }
5732
+ for (const a of standard.attributeDefinitions ?? []) {
5733
+ if (a.classRef && !typedFields(a.classRef)) {
5734
+ err('C152', `attribute_definition ${a.id}: class "${a.classRef}" is not a declared class (payload-typed-by-class)`);
5735
+ }
5736
+ }
5737
+ return issues;
5738
+ }
5739
+ // ── C150/C151: the attestation's references and claim lineage ───────
5740
+ // C150 attestation-references-resolve: the subject is a declared
5741
+ // instance, the promise set resolves in `Subject.promise_set_id` form,
5742
+ // every basis entry carries kind and id, and every claim's declaration
5743
+ // and verdict references are stated. C151
5744
+ // attestation-claim-lineage: every promise the certificate prints as
5745
+ // mandatory must be carried by a claim — a mandatory characteristic is
5746
+ // carried by lineage, never restated (clause 19).
5747
+ function checkAttestations(standard) {
5748
+ const issues = [];
5749
+ const err = (check, message) => issues.push({ check, severity: 'error', message });
5750
+ const roleIds = new Set((standard.roles ?? []).map(r => r.id));
5751
+ const instanceIds = new Set((standard.instances ?? []).map(i => i.id));
5752
+ const verdictIds = new Set((standard.verdicts ?? []).map(v => v.id));
5753
+ const setViews = new Map();
5754
+ for (const ps of standard.promiseSets ?? []) {
5755
+ setViews.set(ps.id, { promises: ps.promises });
5756
+ setViews.set(`${ps.id}.promise_set`, { promises: ps.promises });
5757
+ }
5758
+ for (const s of standard.subjects ?? []) {
5759
+ if ((s.is?.promises ?? []).length > 0) {
5760
+ setViews.set(s.id, { promises: s.is.promises });
5761
+ }
5762
+ }
5763
+ const resolveSet = (ref) => setViews.get(ref) ??
5764
+ setViews.get(ref.split('.').slice(1).join('.')) ??
5765
+ null;
5766
+ const mandatoryOf = (view) => {
5767
+ const out = new Set();
5768
+ for (const p of view.promises) {
5769
+ if (p.certificate?.obligation === 'mandatory') {
5770
+ out.add(p.id);
5771
+ }
5772
+ }
5773
+ return out;
5774
+ };
5775
+ for (const a of standard.attestations ?? []) {
5776
+ if (!a.subject) {
5777
+ err('C150', `attestation ${a.id}: no subject facet (attestation-references-resolve)`);
5778
+ }
5779
+ else if (!instanceIds.has(a.subject)) {
5780
+ err('C150', `attestation ${a.id}: subject "${a.subject}" is not a declared instance (attestation-references-resolve)`);
5781
+ }
5782
+ if (!a.promises) {
5783
+ err('C150', `attestation ${a.id}: no promises facet (attestation-references-resolve)`);
5784
+ }
5785
+ const set = a.promises ? resolveSet(a.promises) : null;
5786
+ if (a.promises && !set) {
5787
+ err('C150', `attestation ${a.id}: promises "${a.promises}" does not resolve to a declared promise set (attestation-references-resolve)`);
5788
+ }
5789
+ for (const b of a.basis) {
5790
+ if (!b.kind || !b.id) {
5791
+ err('C150', `attestation ${a.id}: a basis entry needs an evidence kind and an id (attestation-references-resolve)`);
5792
+ }
5793
+ }
5794
+ if (a.authority.role &&
5795
+ roleIds.size > 0 &&
5796
+ !roleIds.has(a.authority.role)) {
5797
+ err('C150', `attestation ${a.id}: authority role "${a.authority.role}" is not a declared role (attestation-references-resolve)`);
5798
+ }
5799
+ const carried = new Set(a.claims.map(c => c.promise));
5800
+ for (const c of a.claims) {
5801
+ if (set && !set.promises.some(p => p.id === c.promise)) {
5802
+ err('C150', `attestation ${a.id}: claim "${c.promise}" is not a promise of "${a.promises}" (attestation-references-resolve)`);
5803
+ }
5804
+ if (!c.declared) {
5805
+ err('C151', `attestation ${a.id}: claim "${c.promise}" carries no declaration reference (attestation-claim-lineage)`);
5806
+ }
5807
+ if (!c.validatedBy) {
5808
+ err('C151', `attestation ${a.id}: claim "${c.promise}" carries no verdict reference (attestation-claim-lineage)`);
5809
+ }
5810
+ else if (verdictIds.size > 0 &&
5811
+ !c.validatedBy.startsWith('/') &&
5812
+ !verdictIds.has(c.validatedBy)) {
5813
+ // Bare ids resolve inside the package; slash ids are the
5814
+ // requirement-anatomy path form and resolve in the linker.
5815
+ err('C150', `attestation ${a.id}: claim "${c.promise}" names verdict "${c.validatedBy}", which is not declared (attestation-references-resolve)`);
5816
+ }
5817
+ }
5818
+ if (set) {
5819
+ for (const pid of mandatoryOf(set)) {
5820
+ if (!carried.has(pid)) {
5821
+ err('C151', `attestation ${a.id}: the mandatory promise "${pid}" of "${a.promises}" is carried by no claim — a mandatory characteristic is carried by lineage, never restated (attestation-claim-lineage)`);
5822
+ }
5823
+ }
5824
+ }
5825
+ }
5826
+ return issues;
5827
+ }
5828
+ // ── C149: closed-derivation-references-declared ─────────────────────
5829
+ // The typed kernel's rule R3: a derivation expression names only
5830
+ // declared definitions — declared calculations, tables, symbols,
5831
+ // measurements/variables, data classes, enums, and attributes of the
5832
+ // model. The checker rejects an expression that references anything
5833
+ // else and names the missing declaration, so the undefined-reference
5834
+ // defect class cannot be authored.
5835
+ const CLOSED_DERIVATION_STOP = new Set([
5836
+ 'self',
5837
+ 'p',
5838
+ 'ocl',
5839
+ 'true',
5840
+ 'false',
5841
+ 'null',
5842
+ 'undefined',
5843
+ // OCL navigation and collection operators
5844
+ 'and',
5845
+ 'or',
5846
+ 'not',
5847
+ 'implies',
5848
+ 'if',
5849
+ 'then',
5850
+ 'else',
5851
+ 'endif',
5852
+ 'xor',
5853
+ 'let',
5854
+ 'in',
5855
+ 'exists',
5856
+ 'forAll',
5857
+ 'select',
5858
+ 'reject',
5859
+ 'collect',
5860
+ 'isEmpty',
5861
+ 'size',
5862
+ 'sum',
5863
+ 'min',
5864
+ 'max',
5865
+ 'abs',
5866
+ 'round',
5867
+ 'floor',
5868
+ 'sqrt',
5869
+ 'includes',
5870
+ 'excludes',
5871
+ 'includesAll',
5872
+ 'excludesAll',
5873
+ 'count',
5874
+ 'first',
5875
+ 'last',
5876
+ 'asSet',
5877
+ 'asOrderedSet',
5878
+ 'asSequence',
5879
+ 'asBag',
5880
+ 'sortedBy',
5881
+ 'iterate',
5882
+ 'oclIsUndefined',
5883
+ 'oclIsKindOf',
5884
+ 'oclIsTypeOf',
5885
+ 'allInstances',
5886
+ // table-lookup engine vocabulary (the lookup facet names these)
5887
+ 'lookup',
5888
+ 'profile',
5889
+ // OCL collection statistics and arithmetic
5890
+ 'average',
5891
+ 'mean',
5892
+ 'size',
5893
+ 'div',
5894
+ 'mod',
5895
+ 'collect',
5896
+ ]);
5897
+ // Attribute navigation: `head.field…` resolves when the HEAD is a
5898
+ // declared name (an input, a calculation, an attribute, a class-typed
5899
+ // value); the tail is navigation over that head's type, judged by the
5900
+ // class layer (C152), not by the closed-derivation rule.
5901
+ const CLOSED_DERIVATION_PATH_RE = /\b[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)+/g;
5902
+ const CLOSED_DERIVATION_IDENT_RE = /[A-Za-z_][A-Za-z0-9_]*/g;
5903
+ function checkClosedDerivations(standard) {
5904
+ const issues = [];
5905
+ const err = (check, message) => issues.push({ check, severity: 'error', message });
5906
+ // The declared universe every derivation may reference.
5907
+ const declared = new Set();
5908
+ for (const c of standard.calculations ?? []) {
5909
+ declared.add(c.id);
5910
+ declared.add(c.name);
5911
+ }
5912
+ for (const tb of standard.tables ?? []) {
5913
+ declared.add(tb.id);
5914
+ }
5915
+ for (const s of standard.symbols ?? []) {
5916
+ declared.add(s.id);
5917
+ }
5918
+ for (const v of standard.variables ?? []) {
5919
+ declared.add(v.id);
5920
+ }
5921
+ for (const a of standard.attributeDefinitions ?? []) {
5922
+ declared.add(a.id);
5923
+ }
5924
+ for (const e of standard.enums ?? []) {
5925
+ declared.add(e.id);
5926
+ }
5927
+ for (const d of standard.dataclasses ?? []) {
5928
+ declared.add(d.id);
5929
+ }
5930
+ for (const inst of standard.instruments ?? []) {
5931
+ for (const d of inst.dimensions ?? []) {
5932
+ declared.add(d.id);
5933
+ }
5934
+ }
5935
+ for (const d of standard.dimensions ?? []) {
5936
+ declared.add(d.id);
5937
+ }
5938
+ // A calculation's own output name is declared too (requirements bind
5939
+ // it), and so is every input of every calculation.
5940
+ for (const c of standard.calculations ?? []) {
5941
+ if (c.output?.name) {
5942
+ declared.add(c.output.name);
5943
+ }
5944
+ for (const i of c.inputs ?? []) {
5945
+ declared.add(i.name);
5946
+ }
5947
+ }
5948
+ const localsOf = (extra) => new Set([...declared, ...extra]);
5949
+ const checkExpression = (expr, locals, where) => {
5950
+ if (!expr) {
5951
+ return;
5952
+ }
5953
+ // Values and lambdas are not references: single-quoted literals are
5954
+ // values; an identifier before `|` is a lambda parameter.
5955
+ const noLiterals = expr.replace(/'[^']*'/g, ' ');
5956
+ const noLambdas = noLiterals.replace(/\b([A-Za-z_][A-Za-z0-9_]*)\s*\|/g, ' ');
5957
+ const stripped = noLambdas.replace(CLOSED_DERIVATION_PATH_RE, ' ');
5958
+ const seen = new Set();
5959
+ for (const raw of stripped.match(CLOSED_DERIVATION_IDENT_RE) ?? []) {
5960
+ if (CLOSED_DERIVATION_STOP.has(raw) ||
5961
+ locals.has(raw) ||
5962
+ seen.has(raw) ||
5963
+ /^[a-z][0-9]?$/.test(raw)) {
5964
+ continue;
5965
+ }
5966
+ seen.add(raw);
5967
+ err('C149', `${where}: expression references "${raw}", which no declared calculation, table, symbol, measurement, or attribute defines (closed-derivation-references-declared)`);
5968
+ }
5969
+ };
5970
+ for (const a of standard.attributeDefinitions ?? []) {
5971
+ checkExpression(a.derived, localsOf([]), `attribute_definition ${a.id}`);
5972
+ }
5973
+ for (const c of standard.calculations ?? []) {
5974
+ // The normative body is the declared expression; engine variants
5975
+ // are consumer code and outside the language's semantics.
5976
+ const inputs = (c.inputs ?? []).map(i => i.name);
5977
+ checkExpression(c.expression, localsOf(inputs), `calculation ${c.id}`);
5978
+ }
5979
+ for (const s of standard.symbols ?? []) {
5980
+ if (s.formula?.expression) {
5981
+ checkExpression(s.formula.expression, localsOf(s.formula.inputs ?? []), `symbol ${s.id}`);
5982
+ }
5983
+ }
5984
+ for (const v of standard.verdicts ?? []) {
5985
+ checkExpression(v.derive, localsOf(v.inputs ?? []), `verdict ${v.id}`);
5986
+ }
5987
+ return issues;
5988
+ }
5681
5989
  function checkSpellingCodes(standard) {
5682
5990
  const issues = [];
5683
5991
  const err = (check, message) => issues.push({ check, severity: 'error', message });