domainforge 0.13.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 (481) hide show
  1. package/.cargo/config.toml +6 -0
  2. package/.claude/settings.local.json +18 -0
  3. package/.coderabbit.yml +43 -0
  4. package/.codex/skills/release-management/SKILL.md +151 -0
  5. package/.codex/skills/release-management/agents/openai.yaml +4 -0
  6. package/.github/actions/decrypt-secrets/action.yml +121 -0
  7. package/.github/agents/Coder.agent.md +97 -0
  8. package/.github/agents/DeepResearch.agent.md +61 -0
  9. package/.github/chatmodes/tdd.vibepro.chatmode.md +1183 -0
  10. package/.github/copilot-instructions.md +13 -0
  11. package/.github/dependabot.yml +68 -0
  12. package/.github/workflows/README.md +165 -0
  13. package/.github/workflows/ci.yml +335 -0
  14. package/.github/workflows/dependabot-automerge.yml +114 -0
  15. package/.github/workflows/dependency-review.yml +27 -0
  16. package/.github/workflows/deploy.yml +87 -0
  17. package/.github/workflows/prepare-release.yml +168 -0
  18. package/.github/workflows/release-crates.yml +42 -0
  19. package/.github/workflows/release-npm.yml +137 -0
  20. package/.github/workflows/release-please.yml +29 -0
  21. package/.github/workflows/release-pypi.yml +96 -0
  22. package/.gitkeep +1 -0
  23. package/.release-please-manifest.json +5 -0
  24. package/.sea-registry.toml +10 -0
  25. package/.serena/project.yml +133 -0
  26. package/.sops.yaml +10 -0
  27. package/AGENTS.md +216 -0
  28. package/CHANGELOG.md +400 -0
  29. package/CLAUDE.md +62 -0
  30. package/CONTRIBUTING.md +323 -0
  31. package/Cargo.lock +3612 -0
  32. package/Cargo.toml +12 -0
  33. package/LICENSE +201 -0
  34. package/README.md +660 -0
  35. package/README_PYTHON.md +256 -0
  36. package/README_TYPESCRIPT.md +305 -0
  37. package/README_WASM.md +329 -0
  38. package/RELEASE_NOTES.md +41 -0
  39. package/bun.lock +378 -0
  40. package/bunfig.toml +11 -0
  41. package/check_output.txt +83 -0
  42. package/clippy_output.txt +80 -0
  43. package/commitlint.config.cjs +8 -0
  44. package/deny.toml +42 -0
  45. package/devbox.json +14 -0
  46. package/devbox.lock +76 -0
  47. package/docs/RELEASE_PROCESS.md +360 -0
  48. package/docs/diagnostics.md +161 -0
  49. package/docs/doc_guidelines.md +53 -0
  50. package/docs/explanations/README.md +21 -0
  51. package/docs/explanations/architecture-overview.md +109 -0
  52. package/docs/explanations/cross-language-binding-strategy.md +68 -0
  53. package/docs/explanations/graph-store-design.md +47 -0
  54. package/docs/explanations/performance-benchmarks.md +63 -0
  55. package/docs/explanations/policy-evaluation-logic.md +106 -0
  56. package/docs/explanations/semantic-modeling-concepts.md +109 -0
  57. package/docs/explanations/three-valued-logic.md +66 -0
  58. package/docs/explanations/versioning-strategy.md +45 -0
  59. package/docs/governance.md +168 -0
  60. package/docs/how-tos/README.md +46 -0
  61. package/docs/how-tos/ci-cd-validation.md +93 -0
  62. package/docs/how-tos/create-custom-units.md +125 -0
  63. package/docs/how-tos/define-policies.md +119 -0
  64. package/docs/how-tos/export-to-calm.md +110 -0
  65. package/docs/how-tos/export-to-protobuf.md +312 -0
  66. package/docs/how-tos/extend-grammar.md +133 -0
  67. package/docs/how-tos/generate-rdf-turtle.md +106 -0
  68. package/docs/how-tos/import-from-calm.md +114 -0
  69. package/docs/how-tos/import-from-sbvr.md +249 -0
  70. package/docs/how-tos/install-cli.md +126 -0
  71. package/docs/how-tos/parse-sea-files.md +132 -0
  72. package/docs/how-tos/policy-evaluation-modes.md +30 -0
  73. package/docs/how-tos/run-cross-language-tests.md +115 -0
  74. package/docs/how-tos/troubleshoot-napi-builds.md +55 -0
  75. package/docs/how-tos/use-modules-imports.md +285 -0
  76. package/docs/index.md +13 -0
  77. package/docs/plans/canonical-normalizer.md +121 -0
  78. package/docs/plans/cd_improvement.md +112 -0
  79. package/docs/plans/cli-ast.md +29 -0
  80. package/docs/plans/expression-bindings-and-normalizer-integration.md +174 -0
  81. package/docs/plans/protobuf_advanced_features_plan.md +597 -0
  82. package/docs/plans/protobuf_plan.yml +525 -0
  83. package/docs/plans/refactor_dsl_architecture.md +131 -0
  84. package/docs/plans/release-plan.md +163 -0
  85. package/docs/plans/sea_fmt_implementation_plan.md +516 -0
  86. package/docs/playbooks/README.md +18 -0
  87. package/docs/playbooks/adding-new-primitive.md +68 -0
  88. package/docs/playbooks/debugging-parser-failures.md +42 -0
  89. package/docs/playbooks/local-release-preparation.md +139 -0
  90. package/docs/playbooks/migrating-schema-versions.md +43 -0
  91. package/docs/playbooks/onboarding-contributors.md +64 -0
  92. package/docs/playbooks/releasing-beta.md +86 -0
  93. package/docs/playbooks/secret-management.md +64 -0
  94. package/docs/reference/README.md +199 -0
  95. package/docs/reference/ast-json-api.md +427 -0
  96. package/docs/reference/calm-mapping.md +519 -0
  97. package/docs/reference/cli-commands.md +588 -0
  98. package/docs/reference/configuration.md +202 -0
  99. package/docs/reference/error-codes.md +664 -0
  100. package/docs/reference/generated-artifacts-policy.md +53 -0
  101. package/docs/reference/grammar-spec.md +255 -0
  102. package/docs/reference/primitives-api.md +317 -0
  103. package/docs/reference/protobuf-api.md +426 -0
  104. package/docs/reference/python-api.md +485 -0
  105. package/docs/reference/registry.md +50 -0
  106. package/docs/reference/sea-dsl-ai-cheatsheet.yaml +913 -0
  107. package/docs/reference/security-model.md +74 -0
  108. package/docs/reference/typescript-api.md +508 -0
  109. package/docs/reference/wasm-api.md +420 -0
  110. package/docs/semantic-pack-review.md +144 -0
  111. package/docs/semantic-pack-signing.md +234 -0
  112. package/docs/semantic-packs.md +284 -0
  113. package/docs/specs/ADR-001-sea-dsl-semantic-source-of-truth.md +33 -0
  114. package/docs/specs/ADR-002-projection-first-class-construct.md +50 -0
  115. package/docs/specs/ADR-003-protobuf-projection-target.md +51 -0
  116. package/docs/specs/ADR-004-projection-compatibility-semantics.md +57 -0
  117. package/docs/specs/ADR-005-multi-language-support-strategy.md +112 -0
  118. package/docs/specs/ADR-006-error-handling-strategy.md +115 -0
  119. package/docs/specs/ADR-007-policy-evaluation-engine.md +95 -0
  120. package/docs/specs/ADR-008-knowledge-graph-integration.md +90 -0
  121. package/docs/specs/ADR-009-module-resolution-strategy.md +115 -0
  122. package/docs/specs/ADR-010-unit-system.md +106 -0
  123. package/docs/specs/PRD-001-sea-projection-framework.md +155 -0
  124. package/docs/specs/PRD-002-sea-cli-tooling.md +169 -0
  125. package/docs/specs/PRD-003-dsl-core-capabilities.md +275 -0
  126. package/docs/specs/README.md +62 -0
  127. package/docs/specs/SDS-001-protobuf-projection-engine.md +451 -0
  128. package/docs/specs/SDS-002-sea-core-architecture.md +268 -0
  129. package/docs/specs/SDS-003-parser-semantic-graph.md +377 -0
  130. package/docs/specs/SDS-004-policy-engine-design.md +362 -0
  131. package/docs/specs/SDS-005-knowledge-graph-module.md +364 -0
  132. package/docs/specs/SDS-006-calm-integration.md +367 -0
  133. package/docs/specs/SDS-007-sbvr-import.md +347 -0
  134. package/docs/templates/template_explanation.md +14 -0
  135. package/docs/templates/template_howto.md +21 -0
  136. package/docs/templates/template_playbook.md +21 -0
  137. package/docs/templates/template_reference.md +17 -0
  138. package/docs/templates/template_tutorial.md +24 -0
  139. package/docs/tutorials/README.md +12 -0
  140. package/docs/tutorials/first-sea-model.md +85 -0
  141. package/docs/tutorials/getting-started.md +98 -0
  142. package/docs/tutorials/python-binding-quickstart.md +107 -0
  143. package/docs/tutorials/typescript-binding-quickstart.md +91 -0
  144. package/docs/tutorials/wasm-in-browser.md +75 -0
  145. package/domainforge-core/CHANGELOG.md +138 -0
  146. package/domainforge-core/Cargo.toml +101 -0
  147. package/domainforge-core/MIGRATING.md +32 -0
  148. package/domainforge-core/README.md +197 -0
  149. package/domainforge-core/benchmark_results.txt +51 -0
  150. package/domainforge-core/build.rs +6 -0
  151. package/domainforge-core/deny.toml +31 -0
  152. package/domainforge-core/docs/specs/projections/sbvr_kg_mapping.md +43 -0
  153. package/domainforge-core/examples/basic.sea +7 -0
  154. package/domainforge-core/examples/cli/import_export_workflow.sh +38 -0
  155. package/domainforge-core/examples/cli/validate_example.sh +30 -0
  156. package/domainforge-core/examples/evolution_semantics.sea +31 -0
  157. package/domainforge-core/examples/parser_demo.rs +203 -0
  158. package/domainforge-core/grammar/sea.pest +408 -0
  159. package/domainforge-core/schemas/calm-v1.schema.json +170 -0
  160. package/domainforge-core/schemas/shacl/sea_shapes.ttl +19 -0
  161. package/domainforge-core/src/authority/compiler.rs +309 -0
  162. package/domainforge-core/src/authority/environment.rs +203 -0
  163. package/domainforge-core/src/authority/error.rs +164 -0
  164. package/domainforge-core/src/authority/fact_resolver.rs +224 -0
  165. package/domainforge-core/src/authority/mod.rs +25 -0
  166. package/domainforge-core/src/authority/pack.rs +133 -0
  167. package/domainforge-core/src/authority/policy.rs +224 -0
  168. package/domainforge-core/src/authority/resolver.rs +446 -0
  169. package/domainforge-core/src/authority/trace.rs +217 -0
  170. package/domainforge-core/src/authority/transform.rs +168 -0
  171. package/domainforge-core/src/authority/types.rs +617 -0
  172. package/domainforge-core/src/bin/domainforge.rs +25 -0
  173. package/domainforge-core/src/calm/export.rs +538 -0
  174. package/domainforge-core/src/calm/import.rs +1220 -0
  175. package/domainforge-core/src/calm/mod.rs +9 -0
  176. package/domainforge-core/src/calm/models.rs +108 -0
  177. package/domainforge-core/src/calm/sbvr_import.rs +9 -0
  178. package/domainforge-core/src/cli/authority.rs +149 -0
  179. package/domainforge-core/src/cli/format.rs +85 -0
  180. package/domainforge-core/src/cli/import.rs +133 -0
  181. package/domainforge-core/src/cli/mod.rs +64 -0
  182. package/domainforge-core/src/cli/normalize.rs +180 -0
  183. package/domainforge-core/src/cli/pack.rs +904 -0
  184. package/domainforge-core/src/cli/parse.rs +112 -0
  185. package/domainforge-core/src/cli/project.rs +294 -0
  186. package/domainforge-core/src/cli/registry.rs +41 -0
  187. package/domainforge-core/src/cli/test.rs +12 -0
  188. package/domainforge-core/src/cli/validate.rs +195 -0
  189. package/domainforge-core/src/cli/validate_kg.rs +80 -0
  190. package/domainforge-core/src/concept_id.rs +89 -0
  191. package/domainforge-core/src/error/diagnostics.rs +426 -0
  192. package/domainforge-core/src/error/fuzzy.rs +253 -0
  193. package/domainforge-core/src/error/mod.rs +13 -0
  194. package/domainforge-core/src/formatter/comments.rs +223 -0
  195. package/domainforge-core/src/formatter/config.rs +114 -0
  196. package/domainforge-core/src/formatter/mod.rs +22 -0
  197. package/domainforge-core/src/formatter/printer.rs +906 -0
  198. package/domainforge-core/src/graph/mod.rs +858 -0
  199. package/domainforge-core/src/graph/to_ast.rs +66 -0
  200. package/domainforge-core/src/kg.rs +1476 -0
  201. package/domainforge-core/src/kg_import.rs +251 -0
  202. package/domainforge-core/src/lib.rs +203 -0
  203. package/domainforge-core/src/module/mod.rs +1 -0
  204. package/domainforge-core/src/module/resolver.rs +260 -0
  205. package/domainforge-core/src/parser/ast.rs +2919 -0
  206. package/domainforge-core/src/parser/ast_convert.rs +494 -0
  207. package/domainforge-core/src/parser/ast_schema.rs +491 -0
  208. package/domainforge-core/src/parser/error.rs +291 -0
  209. package/domainforge-core/src/parser/lint.rs +39 -0
  210. package/domainforge-core/src/parser/mod.rs +193 -0
  211. package/domainforge-core/src/parser/printer.rs +702 -0
  212. package/domainforge-core/src/parser/profiles.rs +71 -0
  213. package/domainforge-core/src/parser/string_utils.rs +138 -0
  214. package/domainforge-core/src/patterns.rs +68 -0
  215. package/domainforge-core/src/policy/core.rs +1148 -0
  216. package/domainforge-core/src/policy/expression.rs +399 -0
  217. package/domainforge-core/src/policy/mod.rs +18 -0
  218. package/domainforge-core/src/policy/normalize.rs +1028 -0
  219. package/domainforge-core/src/policy/quantifier.rs +940 -0
  220. package/domainforge-core/src/policy/three_valued.rs +140 -0
  221. package/domainforge-core/src/policy/three_valued_microbench.rs +104 -0
  222. package/domainforge-core/src/policy/type_inference.rs +67 -0
  223. package/domainforge-core/src/policy/violation.rs +36 -0
  224. package/domainforge-core/src/primitives/concept_change.rs +61 -0
  225. package/domainforge-core/src/primitives/entity.rs +224 -0
  226. package/domainforge-core/src/primitives/flow.rs +111 -0
  227. package/domainforge-core/src/primitives/instance.rs +93 -0
  228. package/domainforge-core/src/primitives/mapping_contract.rs +50 -0
  229. package/domainforge-core/src/primitives/metric.rs +79 -0
  230. package/domainforge-core/src/primitives/mod.rs +25 -0
  231. package/domainforge-core/src/primitives/projection_contract.rs +50 -0
  232. package/domainforge-core/src/primitives/quantity.rs +56 -0
  233. package/domainforge-core/src/primitives/relation.rs +68 -0
  234. package/domainforge-core/src/primitives/resource.rs +237 -0
  235. package/domainforge-core/src/primitives/resource_instance.rs +88 -0
  236. package/domainforge-core/src/primitives/role.rs +49 -0
  237. package/domainforge-core/src/projection/buf.rs +404 -0
  238. package/domainforge-core/src/projection/contracts.rs +22 -0
  239. package/domainforge-core/src/projection/engine.rs +19 -0
  240. package/domainforge-core/src/projection/mod.rs +16 -0
  241. package/domainforge-core/src/projection/protobuf.rs +3331 -0
  242. package/domainforge-core/src/projection/registry.rs +43 -0
  243. package/domainforge-core/src/python/authority.rs +253 -0
  244. package/domainforge-core/src/python/error.rs +227 -0
  245. package/domainforge-core/src/python/formatter.rs +86 -0
  246. package/domainforge-core/src/python/graph.rs +366 -0
  247. package/domainforge-core/src/python/mod.rs +9 -0
  248. package/domainforge-core/src/python/policy.rs +651 -0
  249. package/domainforge-core/src/python/primitives.rs +796 -0
  250. package/domainforge-core/src/python/registry.rs +98 -0
  251. package/domainforge-core/src/python/semantic_pack.rs +619 -0
  252. package/domainforge-core/src/python/units.rs +96 -0
  253. package/domainforge-core/src/registry/mod.rs +432 -0
  254. package/domainforge-core/src/registry/tests.rs +210 -0
  255. package/domainforge-core/src/sbvr.rs +744 -0
  256. package/domainforge-core/src/semantic_pack/builder.rs +470 -0
  257. package/domainforge-core/src/semantic_pack/canonical_json.rs +184 -0
  258. package/domainforge-core/src/semantic_pack/diagnostics.rs +214 -0
  259. package/domainforge-core/src/semantic_pack/diff.rs +216 -0
  260. package/domainforge-core/src/semantic_pack/mod.rs +31 -0
  261. package/domainforge-core/src/semantic_pack/pack_set.rs +240 -0
  262. package/domainforge-core/src/semantic_pack/resolver.rs +437 -0
  263. package/domainforge-core/src/semantic_pack/review.rs +125 -0
  264. package/domainforge-core/src/semantic_pack/schema.rs +342 -0
  265. package/domainforge-core/src/semantic_pack/signing.rs +105 -0
  266. package/domainforge-core/src/semantic_pack/validator.rs +368 -0
  267. package/domainforge-core/src/semantic_version.rs +140 -0
  268. package/domainforge-core/src/test_utils.rs +12 -0
  269. package/domainforge-core/src/typescript/authority.rs +184 -0
  270. package/domainforge-core/src/typescript/error.rs +146 -0
  271. package/domainforge-core/src/typescript/formatter.rs +76 -0
  272. package/domainforge-core/src/typescript/graph.rs +391 -0
  273. package/domainforge-core/src/typescript/mod.rs +9 -0
  274. package/domainforge-core/src/typescript/policy.rs +564 -0
  275. package/domainforge-core/src/typescript/primitives.rs +784 -0
  276. package/domainforge-core/src/typescript/registry.rs +88 -0
  277. package/domainforge-core/src/typescript/semantic_pack.rs +470 -0
  278. package/domainforge-core/src/typescript/units.rs +76 -0
  279. package/domainforge-core/src/units/mod.rs +462 -0
  280. package/domainforge-core/src/uuid_module.rs +42 -0
  281. package/domainforge-core/src/validation_error.rs +818 -0
  282. package/domainforge-core/src/validation_result.rs +30 -0
  283. package/domainforge-core/src/wasm/authority.rs +192 -0
  284. package/domainforge-core/src/wasm/error.rs +145 -0
  285. package/domainforge-core/src/wasm/formatter.rs +69 -0
  286. package/domainforge-core/src/wasm/graph.rs +471 -0
  287. package/domainforge-core/src/wasm/mod.rs +16 -0
  288. package/domainforge-core/src/wasm/policy.rs +607 -0
  289. package/domainforge-core/src/wasm/primitives.rs +295 -0
  290. package/domainforge-core/src/wasm/semantic_pack.rs +471 -0
  291. package/domainforge-core/src/wasm/units.rs +62 -0
  292. package/domainforge-core/std/aws.sea +6 -0
  293. package/domainforge-core/std/core.sea +6 -0
  294. package/domainforge-core/std/http.sea +27 -0
  295. package/domainforge-core/tests/aggregation_enhanced_tests.rs +162 -0
  296. package/domainforge-core/tests/aggregation_eval_tests.rs +248 -0
  297. package/domainforge-core/tests/aggregation_integration_tests.rs +379 -0
  298. package/domainforge-core/tests/aggregation_parser_tests.rs +92 -0
  299. package/domainforge-core/tests/aggregation_tests.rs +102 -0
  300. package/domainforge-core/tests/authority_conformance_tests.rs +1173 -0
  301. package/domainforge-core/tests/calm_round_trip_tests.rs +283 -0
  302. package/domainforge-core/tests/calm_schema_validation_tests.rs +137 -0
  303. package/domainforge-core/tests/cast_operator_tests.rs +85 -0
  304. package/domainforge-core/tests/cli_binary_check.rs +37 -0
  305. package/domainforge-core/tests/cli_import_tests.rs +291 -0
  306. package/domainforge-core/tests/cli_path_traversal_tests.rs +124 -0
  307. package/domainforge-core/tests/cli_tests.rs +63 -0
  308. package/domainforge-core/tests/diagnostics_tests.rs +203 -0
  309. package/domainforge-core/tests/dimension_unit_tests.rs +80 -0
  310. package/domainforge-core/tests/entity_tests.rs +69 -0
  311. package/domainforge-core/tests/evolution_semantics_tests.rs +157 -0
  312. package/domainforge-core/tests/flow_tests.rs +78 -0
  313. package/domainforge-core/tests/flow_unit_validation_tests.rs +31 -0
  314. package/domainforge-core/tests/graph_integration_tests.rs +218 -0
  315. package/domainforge-core/tests/graph_tests.rs +626 -0
  316. package/domainforge-core/tests/import_parsing_tests.rs +23 -0
  317. package/domainforge-core/tests/instance_integration_tests.rs +98 -0
  318. package/domainforge-core/tests/instance_parsing_tests.rs +58 -0
  319. package/domainforge-core/tests/instance_tests.rs +61 -0
  320. package/domainforge-core/tests/kg_uri_encoding_tests.rs +53 -0
  321. package/domainforge-core/tests/lint_tests.rs +19 -0
  322. package/domainforge-core/tests/metric_tests.rs +143 -0
  323. package/domainforge-core/tests/module_resolution_tests.rs +100 -0
  324. package/domainforge-core/tests/namespace_registry_tests.rs +247 -0
  325. package/domainforge-core/tests/null_handling_tests.rs +26 -0
  326. package/domainforge-core/tests/parser_ast_v3.rs +53 -0
  327. package/domainforge-core/tests/parser_dimension_registry_tests.rs +20 -0
  328. package/domainforge-core/tests/parser_integration_tests.rs +294 -0
  329. package/domainforge-core/tests/parser_metadata_tests.rs +97 -0
  330. package/domainforge-core/tests/parser_resource_domain_only_graph_test.rs +21 -0
  331. package/domainforge-core/tests/parser_resource_limits_tests.rs +122 -0
  332. package/domainforge-core/tests/parser_tests.rs +512 -0
  333. package/domainforge-core/tests/pattern_semantics_tests.rs +87 -0
  334. package/domainforge-core/tests/phase_14_determinism_tests.rs +166 -0
  335. package/domainforge-core/tests/phase_15_validation_error_tests.rs +136 -0
  336. package/domainforge-core/tests/phase_16_unicode_tests.rs +248 -0
  337. package/domainforge-core/tests/phase_17_export_tests.rs +285 -0
  338. package/domainforge-core/tests/phase_17_round_trip_tests.rs +264 -0
  339. package/domainforge-core/tests/policy_tests.rs +635 -0
  340. package/domainforge-core/tests/primitives_integration_tests.rs +151 -0
  341. package/domainforge-core/tests/print_rdf_xml.rs +14 -0
  342. package/domainforge-core/tests/printer_tests.rs +204 -0
  343. package/domainforge-core/tests/profile_tests.rs +35 -0
  344. package/domainforge-core/tests/projection_contracts_tests.rs +154 -0
  345. package/domainforge-core/tests/protobuf_projection_tests.rs +199 -0
  346. package/domainforge-core/tests/quantity_tests.rs +41 -0
  347. package/domainforge-core/tests/rdf_xml_typed_literal_tests.rs +105 -0
  348. package/domainforge-core/tests/registry_schema_tests.rs +33 -0
  349. package/domainforge-core/tests/resource_tests.rs +50 -0
  350. package/domainforge-core/tests/resource_unit_tests.rs +24 -0
  351. package/domainforge-core/tests/roles_relations_tests.rs +61 -0
  352. package/domainforge-core/tests/round_trip_tests.rs +34 -0
  353. package/domainforge-core/tests/runtime_toggle_tests.rs +70 -0
  354. package/domainforge-core/tests/sbvr_fact_schema_tests.rs +60 -0
  355. package/domainforge-core/tests/sbvr_flow_facts_tests.rs +55 -0
  356. package/domainforge-core/tests/sbvr_parsing_tests.rs +53 -0
  357. package/domainforge-core/tests/semantic_pack_alias_resolution.rs +197 -0
  358. package/domainforge-core/tests/semantic_pack_build.rs +302 -0
  359. package/domainforge-core/tests/semantic_pack_consumer_smoke.rs +150 -0
  360. package/domainforge-core/tests/semantic_pack_pack_set.rs +160 -0
  361. package/domainforge-core/tests/semantic_pack_signing.rs +157 -0
  362. package/domainforge-core/tests/semantic_pack_three_valued.rs +250 -0
  363. package/domainforge-core/tests/semantic_pack_validate.rs +196 -0
  364. package/domainforge-core/tests/std_lib_tests.rs +37 -0
  365. package/domainforge-core/tests/temporal_evaluation_tests.rs +159 -0
  366. package/domainforge-core/tests/temporal_semantics_tests.rs +214 -0
  367. package/domainforge-core/tests/three_valued_quantifiers_tests.rs +164 -0
  368. package/domainforge-core/tests/turtle_entity_export_tests.rs +38 -0
  369. package/domainforge-core/tests/turtle_escaping_tests.rs +53 -0
  370. package/domainforge-core/tests/turtle_resource_export_tests.rs +34 -0
  371. package/domainforge-core/tests/type_inference_tests.rs +40 -0
  372. package/domainforge-core/tests/unicode_validation_tests.rs +169 -0
  373. package/domainforge-core/tests/unit_tests.rs +81 -0
  374. package/domainforge-core/tests/validate_tests.rs +38 -0
  375. package/domainforge-core/tests/validation_unit_mismatch_tests.rs +83 -0
  376. package/domainforge-core/tests/wasm_tests.rs +229 -0
  377. package/domainforge-python/CHANGELOG-python.md +12 -0
  378. package/domainforge-python/MIGRATING.md +24 -0
  379. package/domainforge-python/README.md +256 -0
  380. package/domainforge-python/domainforge/__init__.py +95 -0
  381. package/domainforge-python/domainforge/domainforge.pyi +519 -0
  382. package/domainforge-python/pyproject.toml +36 -0
  383. package/domainforge-typescript/CHANGELOG-typescript.md +12 -0
  384. package/domainforge-typescript/LICENSE +201 -0
  385. package/domainforge-typescript/MIGRATING.md +24 -0
  386. package/domainforge-typescript/README.md +305 -0
  387. package/domainforge-typescript/index.d.ts +452 -0
  388. package/domainforge-typescript/index.js +361 -0
  389. package/domainforge-typescript/package.json +60 -0
  390. package/example.js +61 -0
  391. package/examples/browser.html +366 -0
  392. package/examples/namespaces/finance/cashflow.sea +5 -0
  393. package/examples/namespaces/logistics/core.sea +7 -0
  394. package/examples/observability_metrics.sea +38 -0
  395. package/fixtures/semantic_packs/acme_procurement/domain/entities.sea +39 -0
  396. package/fixtures/semantic_packs/acme_procurement/domain/metrics.sea +11 -0
  397. package/fixtures/semantic_packs/acme_procurement/domain/relations.sea +7 -0
  398. package/fixtures/semantic_packs/acme_procurement/domain/resources.sea +9 -0
  399. package/fixtures/semantic_packs/acme_procurement/review/acme.procurement.semantic-review.jsonl +7 -0
  400. package/fixtures/semantic_packs/acme_procurement/tests/ambiguous_vendor_alias.sea +8 -0
  401. package/fixtures/semantic_packs/acme_procurement/tests/deprecated_vendor_alias.sea +8 -0
  402. package/fixtures/semantic_packs/acme_procurement/tests/invalid_relation.sea +3 -0
  403. package/fixtures/semantic_packs/acme_procurement/tests/proposed_concept.sea +8 -0
  404. package/fixtures/semantic_packs/acme_procurement/tests/rejected_concept.sea +8 -0
  405. package/fixtures/semantic_packs/acme_procurement/tests/unit_mismatch.sea +7 -0
  406. package/fixtures/semantic_packs/acme_procurement/tests/unknown_vendor_policy.sea +8 -0
  407. package/fixtures/semantic_packs/acme_procurement/tests/valid_purchase_policy.sea +8 -0
  408. package/index.d.ts +2 -0
  409. package/index.js +8 -0
  410. package/justfile +200 -0
  411. package/lefthook.yml +13 -0
  412. package/lib/validate_native_exports.d.ts +4 -0
  413. package/lib/validate_native_exports.js +12 -0
  414. package/package.json +22 -0
  415. package/pytest.ini +5 -0
  416. package/python/tests/test_registry.py +75 -0
  417. package/python/tests/test_units.py +18 -0
  418. package/release-please-config.json +49 -0
  419. package/requirements-dev.txt +3 -0
  420. package/requirements.txt +3 -0
  421. package/rust-toolchain.toml +3 -0
  422. package/schemas/ast-v1.schema.json +72 -0
  423. package/schemas/ast-v2.schema.json +1200 -0
  424. package/schemas/ast-v3.schema.json +1200 -0
  425. package/schemas/sea-registry.schema.json +45 -0
  426. package/scripts/build-python.sh +37 -0
  427. package/scripts/build-release.sh +279 -0
  428. package/scripts/build-typescript.sh +13 -0
  429. package/scripts/build-wasm.sh +113 -0
  430. package/scripts/bump-version.sh +245 -0
  431. package/scripts/check_unused_test_imports.py +85 -0
  432. package/scripts/ci_tasks.py +379 -0
  433. package/scripts/clear_debug_test.sh +10 -0
  434. package/scripts/create-github-release.sh +262 -0
  435. package/scripts/create-tag.sh +203 -0
  436. package/scripts/find_and_link_test_binary.sh +70 -0
  437. package/scripts/generate-changelog.sh +271 -0
  438. package/scripts/generate-release-notes.sh +205 -0
  439. package/scripts/lint_release_security.py +96 -0
  440. package/scripts/lint_release_workflows.py +82 -0
  441. package/scripts/lint_workflow_gates.py +113 -0
  442. package/scripts/optimized-wasm-build.sh +61 -0
  443. package/scripts/patch_napi_types.py +62 -0
  444. package/scripts/pre-release-check.sh +289 -0
  445. package/scripts/prepare_rust_debug.sh +52 -0
  446. package/scripts/release.sh +373 -0
  447. package/scripts/resolve_rust_binary.py +230 -0
  448. package/scripts/run_commitlint.sh +29 -0
  449. package/scripts/test-all.sh +77 -0
  450. package/scripts/update_launch_program.py +93 -0
  451. package/secrets/README.md +27 -0
  452. package/secrets/secrets.yaml +21 -0
  453. package/test_integration.py +67 -0
  454. package/tests/test_authority.py +328 -0
  455. package/tests/test_ci_tasks.py +143 -0
  456. package/tests/test_expression.py +256 -0
  457. package/tests/test_golden_payment_flow.py +42 -0
  458. package/tests/test_graph.py +127 -0
  459. package/tests/test_instance.py +136 -0
  460. package/tests/test_parser.py +82 -0
  461. package/tests/test_primitives.py +68 -0
  462. package/tests/test_role_relation_parity.py +56 -0
  463. package/tests/test_runtime_toggle.py +156 -0
  464. package/tests/test_semantic_pack.py +639 -0
  465. package/tests/test_three_valued_eval.py +159 -0
  466. package/tsconfig.json +30 -0
  467. package/typescript-tests/advanced.test.ts +165 -0
  468. package/typescript-tests/authority.test.ts +216 -0
  469. package/typescript-tests/expression.test.ts +228 -0
  470. package/typescript-tests/golden-payment-flow.test.ts +51 -0
  471. package/typescript-tests/graph.test.ts +142 -0
  472. package/typescript-tests/native-binding.test.ts +20 -0
  473. package/typescript-tests/primitives.test.ts +88 -0
  474. package/typescript-tests/registry.test.ts +122 -0
  475. package/typescript-tests/role_relation.test.ts +63 -0
  476. package/typescript-tests/runtime_toggle.test.ts +141 -0
  477. package/typescript-tests/semantic-pack.test.ts +556 -0
  478. package/typescript-tests/three_valued_eval.test.ts +135 -0
  479. package/typescript-tests/units.test.ts +36 -0
  480. package/vitest.config.ts +13 -0
  481. package/wasm_demo.html +225 -0
@@ -0,0 +1,556 @@
1
+ /**
2
+ * Tests for the new Semantic Pack API exports added in this PR.
3
+ *
4
+ * Covers:
5
+ * - Enum exports: SemanticTruth, DiagnosticSeverity, ValidationMode, ApprovalState,
6
+ * SignatureState, ConceptStatus, ConceptKind, AliasStatus, SemanticValidationStatus
7
+ * - Functions: semanticPackBuild, semanticPackValidate, semanticPackValidateGraph,
8
+ * semanticPackHash, semanticNormalizeKey, semanticResolveConcept, semanticPackDiff,
9
+ * semanticPackSign, semanticPackVerify
10
+ */
11
+
12
+ import { describe, it, expect } from 'vitest';
13
+ import {
14
+ SemanticTruth,
15
+ DiagnosticSeverity,
16
+ ValidationMode,
17
+ ApprovalState,
18
+ SignatureState,
19
+ ConceptStatus,
20
+ ConceptKind,
21
+ AliasStatus,
22
+ SemanticValidationStatus,
23
+ semanticPackBuild,
24
+ semanticPackValidate,
25
+ semanticPackValidateGraph,
26
+ semanticPackHash,
27
+ semanticNormalizeKey,
28
+ semanticResolveConcept,
29
+ semanticPackDiff,
30
+ semanticPackSign,
31
+ semanticPackVerify,
32
+ } from '../index.js';
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Helpers
36
+ // ---------------------------------------------------------------------------
37
+
38
+ function makeMinimalPackJson(): string {
39
+ return JSON.stringify({
40
+ schema_version: '0.3',
41
+ pack_id: 'test-org/test-domain/1.0.0',
42
+ org_id: 'test-org',
43
+ domain_id: 'test-domain',
44
+ pack_version: '1.0.0',
45
+ meaning_version: '1.0.0',
46
+ meaning_fingerprint: '',
47
+ source_graph_hash: 'sha256:test',
48
+ build_config_hash: 'sha256:cfg',
49
+ review_manifest_hash: 'sha256:rev',
50
+ created_at: '2026-06-07T00:00:00Z',
51
+ generator: { name: 'domainforge-core', version: '0.3' },
52
+ trust: { approval_state: 'candidate', signature_state: 'unsigned' },
53
+ concepts: [
54
+ {
55
+ id: 'supplier',
56
+ canonical_name: 'Supplier',
57
+ kind: 'entity',
58
+ status: 'active',
59
+ definition: {
60
+ text: 'A party that provides goods or services.',
61
+ definition_hash: '',
62
+ decision_ref: 'dec_supplier',
63
+ },
64
+ owner: 'owner@test.com',
65
+ source_refs: [],
66
+ examples: [],
67
+ counterexamples: [],
68
+ allowed_predicates: [],
69
+ valid_contexts: [],
70
+ },
71
+ ],
72
+ relations: [],
73
+ metrics: [],
74
+ dimensions: [],
75
+ units: [],
76
+ aliases: [],
77
+ mapping_rules: [],
78
+ compatibility: {},
79
+ });
80
+ }
81
+
82
+ function makeMinimalBuildInputJson(): string {
83
+ return JSON.stringify({
84
+ org_id: 'test-org',
85
+ domain_id: 'test-domain',
86
+ pack_version: '1.0.0',
87
+ meaning_version: '1.0.0',
88
+ approval: 'candidate',
89
+ concepts: [
90
+ {
91
+ id: 'supplier',
92
+ canonical_name: 'Supplier',
93
+ kind: 'entity',
94
+ status: 'active',
95
+ definition: {
96
+ text: 'A party that provides goods or services.',
97
+ definition_hash: '',
98
+ decision_ref: 'dec_supplier',
99
+ },
100
+ owner: 'owner@test.com',
101
+ source_refs: [],
102
+ examples: [],
103
+ counterexamples: [],
104
+ allowed_predicates: [],
105
+ valid_contexts: [],
106
+ },
107
+ ],
108
+ relations: [],
109
+ metrics: [],
110
+ dimensions: [],
111
+ units: [],
112
+ aliases: [],
113
+ mapping_rules: [],
114
+ review_records: [],
115
+ previous_pack: null,
116
+ allow_first_approved_version: false,
117
+ source_graph_hash: 'sha256:test',
118
+ });
119
+ }
120
+
121
+ function makeDefaultOptionsJson(): string {
122
+ return JSON.stringify({ mode: 'warn', deprecated_policy: 'warn' });
123
+ }
124
+
125
+ // ---------------------------------------------------------------------------
126
+ // Enum value tests
127
+ // ---------------------------------------------------------------------------
128
+
129
+ describe('SemanticTruth enum', () => {
130
+ it('exports Valid=0, Invalid=1, Unknown=2', () => {
131
+ expect(SemanticTruth.Valid).toBe(0);
132
+ expect(SemanticTruth.Invalid).toBe(1);
133
+ expect(SemanticTruth.Unknown).toBe(2);
134
+ });
135
+
136
+ it('has exactly three members', () => {
137
+ const keys = Object.keys(SemanticTruth).filter((k) => isNaN(Number(k)));
138
+ expect(keys).toHaveLength(3);
139
+ });
140
+ });
141
+
142
+ describe('DiagnosticSeverity enum', () => {
143
+ it('exports Error=0, Warning=1, Info=2, Hint=3', () => {
144
+ expect(DiagnosticSeverity.Error).toBe(0);
145
+ expect(DiagnosticSeverity.Warning).toBe(1);
146
+ expect(DiagnosticSeverity.Info).toBe(2);
147
+ expect(DiagnosticSeverity.Hint).toBe(3);
148
+ });
149
+ });
150
+
151
+ describe('ValidationMode enum', () => {
152
+ it('exports Off=0, Warn=1, Strict=2', () => {
153
+ expect(ValidationMode.Off).toBe(0);
154
+ expect(ValidationMode.Warn).toBe(1);
155
+ expect(ValidationMode.Strict).toBe(2);
156
+ });
157
+ });
158
+
159
+ describe('ApprovalState enum', () => {
160
+ it('exports Candidate=0, Approved=1, Rejected=2', () => {
161
+ expect(ApprovalState.Candidate).toBe(0);
162
+ expect(ApprovalState.Approved).toBe(1);
163
+ expect(ApprovalState.Rejected).toBe(2);
164
+ });
165
+ });
166
+
167
+ describe('SignatureState enum', () => {
168
+ it('exports Unsigned=0, Signed=1, InvalidSignature=2', () => {
169
+ expect(SignatureState.Unsigned).toBe(0);
170
+ expect(SignatureState.Signed).toBe(1);
171
+ expect(SignatureState.InvalidSignature).toBe(2);
172
+ });
173
+ });
174
+
175
+ describe('ConceptStatus enum', () => {
176
+ it('exports five statuses with correct numeric values', () => {
177
+ expect(ConceptStatus.Active).toBe(0);
178
+ expect(ConceptStatus.Proposed).toBe(1);
179
+ expect(ConceptStatus.Deprecated).toBe(2);
180
+ expect(ConceptStatus.Rejected).toBe(3);
181
+ expect(ConceptStatus.ExternalOnly).toBe(4);
182
+ });
183
+ });
184
+
185
+ describe('ConceptKind enum', () => {
186
+ it('exports nine kinds with correct numeric values', () => {
187
+ expect(ConceptKind.Entity).toBe(0);
188
+ expect(ConceptKind.Resource).toBe(1);
189
+ expect(ConceptKind.Role).toBe(2);
190
+ expect(ConceptKind.Flow).toBe(3);
191
+ expect(ConceptKind.Policy).toBe(4);
192
+ expect(ConceptKind.Metric).toBe(5);
193
+ expect(ConceptKind.Dimension).toBe(6);
194
+ expect(ConceptKind.Unit).toBe(7);
195
+ expect(ConceptKind.External).toBe(8);
196
+ });
197
+ });
198
+
199
+ describe('AliasStatus enum', () => {
200
+ it('exports Approved=0, Deprecated=1, Ambiguous=2, Blocked=3', () => {
201
+ expect(AliasStatus.Approved).toBe(0);
202
+ expect(AliasStatus.Deprecated).toBe(1);
203
+ expect(AliasStatus.Ambiguous).toBe(2);
204
+ expect(AliasStatus.Blocked).toBe(3);
205
+ });
206
+ });
207
+
208
+ describe('SemanticValidationStatus enum', () => {
209
+ it('exports Passed=0, Failed=1, Unknown=2, Blocked=3', () => {
210
+ expect(SemanticValidationStatus.Passed).toBe(0);
211
+ expect(SemanticValidationStatus.Failed).toBe(1);
212
+ expect(SemanticValidationStatus.Unknown).toBe(2);
213
+ expect(SemanticValidationStatus.Blocked).toBe(3);
214
+ });
215
+ });
216
+
217
+ // ---------------------------------------------------------------------------
218
+ // semanticNormalizeKey
219
+ // ---------------------------------------------------------------------------
220
+
221
+ describe('semanticNormalizeKey', () => {
222
+ it('is a function', () => {
223
+ expect(typeof semanticNormalizeKey).toBe('function');
224
+ });
225
+
226
+ it('collapses multiple spaces into one and trims', () => {
227
+ expect(semanticNormalizeKey(' Hello World ')).toBe('hello world');
228
+ });
229
+
230
+ it('lowercases the input', () => {
231
+ expect(semanticNormalizeKey('Supplier')).toBe('supplier');
232
+ expect(semanticNormalizeKey('PURCHASE_ORDER')).toBe('purchase_order');
233
+ });
234
+
235
+ it('returns empty string for empty input', () => {
236
+ expect(semanticNormalizeKey('')).toBe('');
237
+ });
238
+
239
+ it('handles single-word input', () => {
240
+ const result = semanticNormalizeKey('Warehouse');
241
+ expect(result).toBe('warehouse');
242
+ });
243
+
244
+ it('is idempotent: normalizing twice gives the same result', () => {
245
+ const once = semanticNormalizeKey(' Purchase Order ');
246
+ const twice = semanticNormalizeKey(once);
247
+ expect(once).toBe(twice);
248
+ });
249
+
250
+ it('handles leading/trailing whitespace only', () => {
251
+ const result = semanticNormalizeKey(' ');
252
+ expect(typeof result).toBe('string');
253
+ });
254
+ });
255
+
256
+ // ---------------------------------------------------------------------------
257
+ // semanticPackBuild
258
+ // ---------------------------------------------------------------------------
259
+
260
+ describe('semanticPackBuild', () => {
261
+ it('is a function', () => {
262
+ expect(typeof semanticPackBuild).toBe('function');
263
+ });
264
+
265
+ it('builds a candidate pack and returns JSON with expected fields', () => {
266
+ const resultJson = semanticPackBuild(makeMinimalBuildInputJson());
267
+ const result = JSON.parse(resultJson);
268
+ expect(result).toHaveProperty('pack');
269
+ expect(result).toHaveProperty('pack_content_hash');
270
+ expect(result).toHaveProperty('meaning_fingerprint');
271
+ });
272
+
273
+ it('returns a pack with the correct org_id and domain_id', () => {
274
+ const resultJson = semanticPackBuild(makeMinimalBuildInputJson());
275
+ const { pack } = JSON.parse(resultJson);
276
+ expect(pack.org_id).toBe('test-org');
277
+ expect(pack.domain_id).toBe('test-domain');
278
+ });
279
+
280
+ it('returned pack has schema_version 0.3', () => {
281
+ const resultJson = semanticPackBuild(makeMinimalBuildInputJson());
282
+ const { pack } = JSON.parse(resultJson);
283
+ expect(pack.schema_version).toBe('0.3');
284
+ });
285
+
286
+ it('returned pack has approval state candidate', () => {
287
+ const resultJson = semanticPackBuild(makeMinimalBuildInputJson());
288
+ const { pack } = JSON.parse(resultJson);
289
+ expect(pack.trust.approval_state).toBe('candidate');
290
+ });
291
+
292
+ it('throws on invalid JSON input', () => {
293
+ expect(() => semanticPackBuild('not valid json')).toThrow();
294
+ });
295
+
296
+ it('throws on empty string input', () => {
297
+ expect(() => semanticPackBuild('')).toThrow();
298
+ });
299
+
300
+ it('two builds from identical inputs are deterministic', () => {
301
+ const input = makeMinimalBuildInputJson();
302
+ const r1 = JSON.parse(semanticPackBuild(input));
303
+ const r2 = JSON.parse(semanticPackBuild(input));
304
+ expect(r1.meaning_fingerprint).toBe(r2.meaning_fingerprint);
305
+ expect(r1.pack_content_hash).toBe(r2.pack_content_hash);
306
+ });
307
+ });
308
+
309
+ // ---------------------------------------------------------------------------
310
+ // semanticPackValidate
311
+ // ---------------------------------------------------------------------------
312
+
313
+ describe('semanticPackValidate', () => {
314
+ it('is a function', () => {
315
+ expect(typeof semanticPackValidate).toBe('function');
316
+ });
317
+
318
+ it('returns a JSON string for a valid pack', () => {
319
+ const diagnosticsJson = semanticPackValidate(makeMinimalPackJson());
320
+ expect(() => JSON.parse(diagnosticsJson)).not.toThrow();
321
+ });
322
+
323
+ it('returns an array (possibly empty) for a well-formed pack', () => {
324
+ const diagnosticsJson = semanticPackValidate(makeMinimalPackJson());
325
+ const diagnostics = JSON.parse(diagnosticsJson);
326
+ expect(Array.isArray(diagnostics)).toBe(true);
327
+ });
328
+
329
+ it('throws on invalid JSON input', () => {
330
+ expect(() => semanticPackValidate('not json')).toThrow();
331
+ });
332
+
333
+ it('reports errors for a pack with wrong schema version', () => {
334
+ const pack = JSON.parse(makeMinimalPackJson());
335
+ pack.schema_version = '9.9';
336
+ const diagnosticsJson = semanticPackValidate(JSON.stringify(pack));
337
+ const diagnostics = JSON.parse(diagnosticsJson);
338
+ expect(diagnostics.length).toBeGreaterThan(0);
339
+ });
340
+ });
341
+
342
+ // ---------------------------------------------------------------------------
343
+ // semanticPackHash
344
+ // ---------------------------------------------------------------------------
345
+
346
+ describe('semanticPackHash', () => {
347
+ it('is a function', () => {
348
+ expect(typeof semanticPackHash).toBe('function');
349
+ });
350
+
351
+ it('returns a string starting with sha256:', () => {
352
+ const hash = semanticPackHash(makeMinimalPackJson());
353
+ expect(typeof hash).toBe('string');
354
+ expect(hash).toMatch(/^sha256:/);
355
+ });
356
+
357
+ it('returns the same hash for identical packs', () => {
358
+ const packJson = makeMinimalPackJson();
359
+ expect(semanticPackHash(packJson)).toBe(semanticPackHash(packJson));
360
+ });
361
+
362
+ it('throws on invalid JSON', () => {
363
+ expect(() => semanticPackHash('not json')).toThrow();
364
+ });
365
+
366
+ it('hash is stable regardless of signature fields', () => {
367
+ const pack1 = JSON.parse(makeMinimalPackJson());
368
+ const hash1 = semanticPackHash(JSON.stringify(pack1));
369
+ // Add signature fields — content hash should remain unchanged
370
+ pack1.trust.signature = 'some-base64-sig';
371
+ pack1.trust.signature_state = 'signed';
372
+ const hash2 = semanticPackHash(JSON.stringify(pack1));
373
+ expect(hash1).toBe(hash2);
374
+ });
375
+ });
376
+
377
+ // ---------------------------------------------------------------------------
378
+ // semanticPackValidateGraph
379
+ // ---------------------------------------------------------------------------
380
+
381
+ describe('semanticPackValidateGraph', () => {
382
+ it('is a function', () => {
383
+ expect(typeof semanticPackValidateGraph).toBe('function');
384
+ });
385
+
386
+ it('returns a JSON string for a valid pack', () => {
387
+ const resultJson = semanticPackValidateGraph(
388
+ makeMinimalPackJson(),
389
+ 'test://source',
390
+ makeDefaultOptionsJson(),
391
+ );
392
+ expect(() => JSON.parse(resultJson)).not.toThrow();
393
+ });
394
+
395
+ it('throws on invalid pack JSON', () => {
396
+ expect(() =>
397
+ semanticPackValidateGraph('bad json', 'test://source', makeDefaultOptionsJson()),
398
+ ).toThrow();
399
+ });
400
+
401
+ it('throws on invalid options JSON', () => {
402
+ expect(() =>
403
+ semanticPackValidateGraph(makeMinimalPackJson(), 'test://source', 'bad options'),
404
+ ).toThrow();
405
+ });
406
+ });
407
+
408
+ // ---------------------------------------------------------------------------
409
+ // semanticPackDiff
410
+ // ---------------------------------------------------------------------------
411
+
412
+ describe('semanticPackDiff', () => {
413
+ it('is a function', () => {
414
+ expect(typeof semanticPackDiff).toBe('function');
415
+ });
416
+
417
+ it('returns a parseable JSON string when comparing two packs', () => {
418
+ const packJson = makeMinimalPackJson();
419
+ const diffJson = semanticPackDiff(packJson, packJson);
420
+ expect(() => JSON.parse(diffJson)).not.toThrow();
421
+ });
422
+
423
+ it('reports no changes when comparing a pack to itself', () => {
424
+ const packJson = makeMinimalPackJson();
425
+ const diff = JSON.parse(semanticPackDiff(packJson, packJson));
426
+ // No breaking changes when packs are identical
427
+ const entries = diff.entries ?? diff;
428
+ if (Array.isArray(entries)) {
429
+ // Any entries should not be classified as breaking
430
+ const breaking = entries.filter((e: { classification: string }) => e.classification === 'breaking');
431
+ expect(breaking).toHaveLength(0);
432
+ }
433
+ });
434
+
435
+ it('detects an added concept when new pack has extra concept', () => {
436
+ const oldPack = JSON.parse(makeMinimalPackJson());
437
+ const newPack = JSON.parse(makeMinimalPackJson());
438
+ newPack.concepts.push({
439
+ id: 'warehouse',
440
+ canonical_name: 'Warehouse',
441
+ kind: 'entity',
442
+ status: 'active',
443
+ definition: {
444
+ text: 'A storage facility.',
445
+ definition_hash: '',
446
+ decision_ref: 'dec_warehouse',
447
+ },
448
+ owner: 'owner@test.com',
449
+ source_refs: [],
450
+ examples: [],
451
+ counterexamples: [],
452
+ allowed_predicates: [],
453
+ valid_contexts: [],
454
+ });
455
+ const diffJson = semanticPackDiff(JSON.stringify(oldPack), JSON.stringify(newPack));
456
+ const diff = JSON.parse(diffJson);
457
+ const entries = diff.entries ?? diff;
458
+ if (Array.isArray(entries)) {
459
+ const additive = entries.filter((e: { classification: string }) =>
460
+ e.classification === 'additive' || e.classification === 'add',
461
+ );
462
+ expect(additive.length).toBeGreaterThan(0);
463
+ } else {
464
+ // Diff result parsed fine; structure may vary
465
+ expect(diffJson).toBeTruthy();
466
+ }
467
+ });
468
+
469
+ it('throws on invalid old pack JSON', () => {
470
+ expect(() => semanticPackDiff('bad json', makeMinimalPackJson())).toThrow();
471
+ });
472
+
473
+ it('throws on invalid new pack JSON', () => {
474
+ expect(() => semanticPackDiff(makeMinimalPackJson(), 'bad json')).toThrow();
475
+ });
476
+ });
477
+
478
+ // ---------------------------------------------------------------------------
479
+ // semanticResolveConcept
480
+ // ---------------------------------------------------------------------------
481
+
482
+ describe('semanticResolveConcept', () => {
483
+ it('is a function', () => {
484
+ expect(typeof semanticResolveConcept).toBe('function');
485
+ });
486
+
487
+ it('resolves a known concept and returns valid semantic_truth', () => {
488
+ const resultJson = semanticResolveConcept(
489
+ 'Supplier',
490
+ makeMinimalPackJson(),
491
+ makeDefaultOptionsJson(),
492
+ );
493
+ const result = JSON.parse(resultJson);
494
+ expect(result).toHaveProperty('semantic_truth');
495
+ // Active approved concept → "Valid"
496
+ expect(result.semantic_truth).toMatch(/valid/i);
497
+ });
498
+
499
+ it('returns unknown semantic_truth for an unrecognized term', () => {
500
+ const resultJson = semanticResolveConcept(
501
+ 'CompletelyUnknownTerm',
502
+ makeMinimalPackJson(),
503
+ makeDefaultOptionsJson(),
504
+ );
505
+ const result = JSON.parse(resultJson);
506
+ expect(result.semantic_truth).toMatch(/unknown/i);
507
+ expect(result.resolved_concept_id).toBeNull();
508
+ });
509
+
510
+ it('throws on invalid pack JSON', () => {
511
+ expect(() =>
512
+ semanticResolveConcept('Supplier', 'bad json', makeDefaultOptionsJson()),
513
+ ).toThrow();
514
+ });
515
+
516
+ it('throws on invalid options JSON', () => {
517
+ expect(() =>
518
+ semanticResolveConcept('Supplier', makeMinimalPackJson(), 'bad options'),
519
+ ).toThrow();
520
+ });
521
+
522
+ it('normalizes the lookup key before resolution', () => {
523
+ // " supplier " (with spaces and mixed case) should resolve the same as "Supplier"
524
+ const r1 = JSON.parse(
525
+ semanticResolveConcept('Supplier', makeMinimalPackJson(), makeDefaultOptionsJson()),
526
+ );
527
+ const r2 = JSON.parse(
528
+ semanticResolveConcept(' supplier ', makeMinimalPackJson(), makeDefaultOptionsJson()),
529
+ );
530
+ expect(r1.resolved_concept_id).toBe(r2.resolved_concept_id);
531
+ });
532
+ });
533
+
534
+ // ---------------------------------------------------------------------------
535
+ // semanticPackSign / semanticPackVerify
536
+ // ---------------------------------------------------------------------------
537
+
538
+ describe('semanticPackSign and semanticPackVerify', () => {
539
+ it('semanticPackSign is a function', () => {
540
+ expect(typeof semanticPackSign).toBe('function');
541
+ });
542
+
543
+ it('semanticPackVerify is a function', () => {
544
+ expect(typeof semanticPackVerify).toBe('function');
545
+ });
546
+
547
+ it('semanticPackSign throws on invalid pack JSON', () => {
548
+ const fakePem = '-----BEGIN PRIVATE KEY-----\nnot-real\n-----END PRIVATE KEY-----';
549
+ expect(() => semanticPackSign('bad json', fakePem)).toThrow();
550
+ });
551
+
552
+ it('semanticPackVerify throws on invalid pack JSON', () => {
553
+ const fakePem = '-----BEGIN PUBLIC KEY-----\nnot-real\n-----END PUBLIC KEY-----';
554
+ expect(() => semanticPackVerify('bad json', fakePem)).toThrow();
555
+ });
556
+ });
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Test three-valued logic evaluation semantics for policy evaluation.
3
+ *
4
+ * This test validates that the EvaluationResult correctly handles:
5
+ * - True evaluations (policy satisfied)
6
+ * - False evaluations (policy violated)
7
+ * - Null evaluations (policy evaluation unknown/indeterminate)
8
+ */
9
+
10
+ import { describe, it, expect } from 'vitest';
11
+ import { Graph, Severity } from '../index.js';
12
+
13
+ describe('Three-valued policy evaluation', () => {
14
+ it('should return is_satisfied=true and tristate=true when policy is satisfied', () => {
15
+ const graph = new Graph();
16
+
17
+ // Create a simple policy that always evaluates to true
18
+ const policy = {
19
+ id: '00000000-0000-0000-0000-000000000001',
20
+ name: 'AlwaysTrue',
21
+ namespace: 'test',
22
+ version: { major: 1, minor: 0, patch: 0 },
23
+ expression: { Literal: true },
24
+ modality: 'Obligation',
25
+ kind: 'Constraint',
26
+ priority: 0,
27
+ rationale: null,
28
+ tags: [],
29
+ };
30
+
31
+ const result = graph.evaluatePolicy(JSON.stringify(policy));
32
+
33
+ expect(result.isSatisfied).toBe(true);
34
+ expect(result.isSatisfiedTristate).toBe(true);
35
+ expect(result.violations).toHaveLength(0);
36
+ });
37
+
38
+ it('should return is_satisfied=false and tristate=false when policy is violated', () => {
39
+ const graph = new Graph();
40
+
41
+ // Create a simple policy that always evaluates to false
42
+ const policy = {
43
+ id: '00000000-0000-0000-0000-000000000002',
44
+ name: 'AlwaysFalse',
45
+ namespace: 'test',
46
+ version: { major: 1, minor: 0, patch: 0 },
47
+ expression: { Literal: false },
48
+ modality: 'Obligation',
49
+ kind: 'Constraint',
50
+ priority: 0,
51
+ rationale: null,
52
+ tags: [],
53
+ };
54
+
55
+ const result = graph.evaluatePolicy(JSON.stringify(policy));
56
+
57
+ expect(result.isSatisfied).toBe(false);
58
+ expect(result.isSatisfiedTristate).toBe(false);
59
+ expect(result.violations).toHaveLength(1);
60
+ expect(result.violations[0].name).toBe('AlwaysFalse');
61
+ expect(result.violations[0].severity).toBe(Severity.Error);
62
+ });
63
+
64
+ it('should return is_satisfied=false and tristate=null when evaluation is unknown', () => {
65
+ const graph = new Graph();
66
+
67
+ // Create a policy that references a non-existent entity attribute
68
+ // This should evaluate to NULL when three_valued_logic feature is enabled
69
+ const policy = {
70
+ id: '00000000-0000-0000-0000-000000000003',
71
+ name: 'NullEvaluation',
72
+ namespace: 'test',
73
+ version: { major: 1, minor: 0, patch: 0 },
74
+ expression: {
75
+ MemberAccess: {
76
+ object: 'NonExistentEntity',
77
+ member: 'someAttribute',
78
+ },
79
+ },
80
+ modality: 'Obligation',
81
+ kind: 'Constraint',
82
+ priority: 0,
83
+ rationale: null,
84
+ tags: [],
85
+ };
86
+
87
+ const result = graph.evaluatePolicy(JSON.stringify(policy));
88
+
89
+ // When evaluation is NULL, is_satisfied defaults to false for backwards compatibility
90
+ expect(result.isSatisfied).toBe(false);
91
+ // The tristate field should be undefined (missing) to indicate indeterminate result
92
+ expect(result.isSatisfiedTristate).toBeUndefined();
93
+ // Violation severity follows the policy modality even when evaluation is NULL
94
+ expect(result.violations).toHaveLength(1);
95
+ expect(
96
+ result.violations[0].message.includes('UNKNOWN') ||
97
+ result.violations[0].message.includes('NULL')
98
+ ).toBe(true);
99
+ expect(result.violations[0].severity).toBe(Severity.Error);
100
+ });
101
+
102
+ it('should handle invalid policy JSON', () => {
103
+ const graph = new Graph();
104
+
105
+ expect(() => {
106
+ graph.evaluatePolicy('invalid json');
107
+ }).toThrow();
108
+ });
109
+
110
+ it('should include violation details', () => {
111
+ const graph = new Graph();
112
+
113
+ // Ensure violation messaging reflects the modality (Prohibition) rather than a generic failure.
114
+ const policy = {
115
+ id: '00000000-0000-0000-0000-000000000005',
116
+ name: 'ViolatedPolicy',
117
+ namespace: 'test',
118
+ version: { major: 1, minor: 0, patch: 0 },
119
+ expression: { Literal: false },
120
+ modality: 'Prohibition',
121
+ kind: 'Constraint',
122
+ priority: 0,
123
+ rationale: null,
124
+ tags: [],
125
+ };
126
+
127
+ const result = graph.evaluatePolicy(JSON.stringify(policy));
128
+
129
+ expect(result.violations.length).toBeGreaterThan(0);
130
+ const violation = result.violations[0];
131
+ expect(violation.name).toBe('ViolatedPolicy');
132
+ expect(violation.message).toMatch(new RegExp(policy.name, 'i'));
133
+ expect(violation.severity).toBe(Severity.Error);
134
+ });
135
+ });