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,904 @@
1
+ use crate::semantic_pack::diagnostics::{DeprecatedPolicy, UnknownConceptPolicy};
2
+ use crate::semantic_pack::diff::DiffClassification;
3
+ use crate::semantic_pack::schema::{ConceptDefinition, ReviewRecord};
4
+ use crate::semantic_pack::{
5
+ build_semantic_pack, compute_pack_content_hash, derive_signer_id, diff_packs, sign_pack,
6
+ validate_graph_with_pack, validate_semantic_pack, verify_pack_signature, ApprovalState,
7
+ ConceptDef, ConceptKind, ConceptStatus, DiagnosticSeverity, PackBuildInput, SemanticDiagnostic,
8
+ SemanticPack, SignatureState, ValidationMode, ValidationOptions,
9
+ };
10
+ use crate::{parse_to_graph, Graph};
11
+ use anyhow::{Context, Result};
12
+ use clap::{Args, Subcommand, ValueEnum};
13
+ use colored::Colorize;
14
+ use std::fs;
15
+ use std::path::{Path, PathBuf};
16
+
17
+ #[allow(dead_code)]
18
+ const EXIT_PASSED: i32 = 0;
19
+ const EXIT_SEMANTIC_FAILED: i32 = 1;
20
+ const EXIT_PARSE_ERROR: i32 = 2;
21
+ const EXIT_PACK_UNAVAILABLE: i32 = 3;
22
+ const EXIT_SIGNATURE_FAILURE: i32 = 4;
23
+ #[allow(dead_code)]
24
+ const EXIT_CONFIG_ERROR: i32 = 5;
25
+ #[allow(dead_code)]
26
+ const EXIT_INTERNAL_ERROR: i32 = 6;
27
+
28
+ #[derive(Debug, Args)]
29
+ pub struct PackArgs {
30
+ #[command(subcommand)]
31
+ pub command: PackCommands,
32
+ }
33
+
34
+ #[derive(Debug, Subcommand)]
35
+ pub enum PackCommands {
36
+ #[command(name = "build")]
37
+ Build(BuildArgs),
38
+ #[command(name = "validate")]
39
+ Validate(PackValidateArgs),
40
+ #[command(name = "inspect")]
41
+ Inspect(InspectArgs),
42
+ #[command(name = "diff")]
43
+ Diff(DiffArgs),
44
+ #[command(name = "sign")]
45
+ Sign(SignArgs),
46
+ #[command(name = "verify")]
47
+ Verify(VerifyArgs),
48
+ }
49
+
50
+ #[derive(Debug, Args)]
51
+ pub struct BuildArgs {
52
+ #[arg(long, required = true, num_args = 1..)]
53
+ pub source: Vec<String>,
54
+ #[arg(long)]
55
+ pub org: String,
56
+ #[arg(long)]
57
+ pub domain: String,
58
+ #[arg(long)]
59
+ pub version: String,
60
+ #[arg(long)]
61
+ pub meaning_version: String,
62
+ #[arg(long, value_enum, default_value_t = ApprovalChoice::Candidate)]
63
+ pub approval: ApprovalChoice,
64
+ #[arg(long)]
65
+ pub review: Option<PathBuf>,
66
+ #[arg(long)]
67
+ pub out: Option<PathBuf>,
68
+ #[arg(long)]
69
+ pub previous_pack: Option<PathBuf>,
70
+ #[arg(long)]
71
+ pub allow_first_approved_version: bool,
72
+ #[arg(long, value_enum, default_value_t = PackOutputFormat::Human)]
73
+ pub format: PackOutputFormat,
74
+ }
75
+
76
+ #[derive(Debug, Args)]
77
+ pub struct PackValidateArgs {
78
+ #[arg(long)]
79
+ pub pack: PathBuf,
80
+ #[arg(long, value_enum, default_value_t = ValidationModeChoice::Warn)]
81
+ pub mode: ValidationModeChoice,
82
+ #[arg(long, value_enum, default_value_t = DeprecatedPolicyChoice::Warn)]
83
+ pub deprecated_policy: DeprecatedPolicyChoice,
84
+ #[arg(long)]
85
+ pub require_signature: bool,
86
+ #[arg(long)]
87
+ pub expected_hash: Option<String>,
88
+ #[arg(long, value_enum, default_value_t = PackOutputFormat::Human)]
89
+ pub format: PackOutputFormat,
90
+ #[arg(required = false)]
91
+ pub inputs: Vec<PathBuf>,
92
+ }
93
+
94
+ #[derive(Debug, Args)]
95
+ pub struct InspectArgs {
96
+ #[arg(long, value_enum, default_value_t = PackOutputFormat::Human)]
97
+ pub format: PackOutputFormat,
98
+ pub pack: PathBuf,
99
+ }
100
+
101
+ #[derive(Debug, Args)]
102
+ pub struct DiffArgs {
103
+ #[arg(long, value_enum, default_value_t = PackOutputFormat::Human)]
104
+ pub format: PackOutputFormat,
105
+ pub old: PathBuf,
106
+ pub new: PathBuf,
107
+ }
108
+
109
+ #[derive(Debug, Args)]
110
+ pub struct SignArgs {
111
+ pub pack: PathBuf,
112
+ #[arg(long)]
113
+ pub key: PathBuf,
114
+ #[arg(long)]
115
+ pub out: Option<PathBuf>,
116
+ }
117
+
118
+ #[derive(Debug, Args)]
119
+ pub struct VerifyArgs {
120
+ pub pack: PathBuf,
121
+ #[arg(long)]
122
+ pub key: PathBuf,
123
+ }
124
+
125
+ #[derive(ValueEnum, Clone, Debug, Copy)]
126
+ pub enum ApprovalChoice {
127
+ Candidate,
128
+ Approved,
129
+ }
130
+
131
+ #[derive(ValueEnum, Clone, Debug, Copy)]
132
+ pub enum ValidationModeChoice {
133
+ Off,
134
+ Warn,
135
+ Strict,
136
+ }
137
+
138
+ #[derive(ValueEnum, Clone, Debug, Copy)]
139
+ pub enum DeprecatedPolicyChoice {
140
+ Allow,
141
+ Warn,
142
+ ErrorInStrict,
143
+ ErrorAlways,
144
+ }
145
+
146
+ #[derive(ValueEnum, Clone, Debug, Copy)]
147
+ pub enum PackOutputFormat {
148
+ Human,
149
+ Json,
150
+ Jsonl,
151
+ }
152
+
153
+ pub fn run(args: PackArgs) -> Result<()> {
154
+ match args.command {
155
+ PackCommands::Build(a) => run_build(a),
156
+ PackCommands::Validate(a) => run_validate(a),
157
+ PackCommands::Inspect(a) => run_inspect(a),
158
+ PackCommands::Diff(a) => run_diff(a),
159
+ PackCommands::Sign(a) => run_sign(a),
160
+ PackCommands::Verify(a) => run_verify(a),
161
+ }
162
+ }
163
+
164
+ #[allow(dead_code)]
165
+ fn exit_with_code(code: i32, message: &str) -> Result<()> {
166
+ if code != 0 {
167
+ Err(anyhow::anyhow!("{}", message))
168
+ } else {
169
+ println!("{}", message);
170
+ Ok(())
171
+ }
172
+ }
173
+
174
+ fn load_pack_json(path: &Path) -> Result<SemanticPack> {
175
+ let data = fs::read_to_string(path)
176
+ .with_context(|| format!("Failed to read pack file: {}", path.display()))?;
177
+ serde_json::from_str(&data)
178
+ .with_context(|| format!("Failed to parse pack JSON from: {}", path.display()))
179
+ }
180
+
181
+ fn collect_sea_files(globs: &[String]) -> Result<Vec<PathBuf>> {
182
+ let mut files = Vec::new();
183
+ for pattern in globs {
184
+ let parent = std::path::Path::new(pattern)
185
+ .parent()
186
+ .unwrap_or(std::path::Path::new("."));
187
+ let file_pattern = std::path::Path::new(pattern)
188
+ .file_name()
189
+ .and_then(|f| f.to_str())
190
+ .unwrap_or("**/*.sea");
191
+
192
+ let is_glob = pattern.contains('*') || pattern.contains('?') || pattern.contains('[');
193
+
194
+ if is_glob {
195
+ for entry in globwalk::glob(parent.join(file_pattern).to_string_lossy().as_ref())
196
+ .with_context(|| format!("Invalid glob pattern: {}", pattern))?
197
+ {
198
+ let entry =
199
+ entry.with_context(|| format!("Error reading glob entry for: {}", pattern))?;
200
+ if entry.path().extension().and_then(|e| e.to_str()) == Some("sea") {
201
+ files.push(entry.path().to_path_buf());
202
+ }
203
+ }
204
+ } else {
205
+ let path = PathBuf::from(pattern);
206
+ if path.exists() {
207
+ files.push(path);
208
+ } else {
209
+ anyhow::bail!("Source file not found: {}", pattern);
210
+ }
211
+ }
212
+ }
213
+ files.sort();
214
+ files.dedup();
215
+ Ok(files)
216
+ }
217
+
218
+ fn parse_sea_files(files: &[PathBuf]) -> Result<Graph> {
219
+ let mut combined = Graph::new();
220
+ for path in files {
221
+ let source = fs::read_to_string(path)
222
+ .with_context(|| format!("Failed to read: {}", path.display()))?;
223
+ let graph = parse_to_graph(&source)
224
+ .map_err(|e| anyhow::anyhow!("Parse error in {}: {}", path.display(), e))?;
225
+ combined
226
+ .extend(graph)
227
+ .map_err(|e| anyhow::anyhow!("Merge error from {}: {}", path.display(), e))?;
228
+ }
229
+ Ok(combined)
230
+ }
231
+
232
+ fn graph_to_concepts(graph: &Graph) -> Vec<ConceptDef> {
233
+ let mut concepts = Vec::new();
234
+
235
+ for entity in graph.all_entities() {
236
+ concepts.push(make_concept_def(
237
+ entity.id().to_string(),
238
+ entity.name().to_string(),
239
+ ConceptKind::Entity,
240
+ ));
241
+ }
242
+ for resource in graph.all_resources() {
243
+ concepts.push(make_concept_def(
244
+ resource.id().to_string(),
245
+ resource.name().to_string(),
246
+ ConceptKind::Resource,
247
+ ));
248
+ }
249
+ for role in graph.all_roles() {
250
+ concepts.push(make_concept_def(
251
+ role.id().to_string(),
252
+ role.name().to_string(),
253
+ ConceptKind::Role,
254
+ ));
255
+ }
256
+ for flow in graph.all_flows() {
257
+ concepts.push(make_concept_def(
258
+ flow.id().to_string(),
259
+ flow.id().to_string(),
260
+ ConceptKind::Flow,
261
+ ));
262
+ }
263
+ for policy in graph.all_policies() {
264
+ concepts.push(make_concept_def(
265
+ policy.id.to_string(),
266
+ policy.name.to_string(),
267
+ ConceptKind::Policy,
268
+ ));
269
+ }
270
+ for metric in graph.all_metrics() {
271
+ concepts.push(make_concept_def(
272
+ metric.id().to_string(),
273
+ metric.name.to_string(),
274
+ ConceptKind::Metric,
275
+ ));
276
+ }
277
+
278
+ concepts
279
+ }
280
+
281
+ fn make_concept_def(id: String, canonical_name: String, kind: ConceptKind) -> ConceptDef {
282
+ ConceptDef {
283
+ id,
284
+ canonical_name,
285
+ kind,
286
+ status: ConceptStatus::Active,
287
+ definition: ConceptDefinition {
288
+ text: String::new(),
289
+ definition_hash: String::new(),
290
+ decision_ref: String::new(),
291
+ },
292
+ owner: String::new(),
293
+ source_refs: vec![],
294
+ examples: vec![],
295
+ counterexamples: vec![],
296
+ allowed_predicates: vec![],
297
+ valid_contexts: vec![],
298
+ }
299
+ }
300
+
301
+ fn load_review_records(path: &Path) -> Result<Vec<ReviewRecord>> {
302
+ let data = fs::read_to_string(path)
303
+ .with_context(|| format!("Failed to read review file: {}", path.display()))?;
304
+ let mut records = Vec::new();
305
+ for (line_num, line) in data.lines().enumerate() {
306
+ let trimmed = line.trim();
307
+ if trimmed.is_empty() {
308
+ continue;
309
+ }
310
+ let record: ReviewRecord = serde_json::from_str(trimmed).with_context(|| {
311
+ format!(
312
+ "Failed to parse review JSONL at line {} in {}",
313
+ line_num + 1,
314
+ path.display()
315
+ )
316
+ })?;
317
+ records.push(record);
318
+ }
319
+ Ok(records)
320
+ }
321
+
322
+ fn compute_graph_hash(graph: &Graph) -> String {
323
+ use sha2::{Digest, Sha256};
324
+ let json = serde_json::to_string(graph).unwrap_or_default();
325
+ let mut hasher = Sha256::new();
326
+ hasher.update(json.as_bytes());
327
+ let result = hasher.finalize();
328
+ format!("sha256:{:x}", result)
329
+ }
330
+
331
+ fn run_build(args: BuildArgs) -> Result<()> {
332
+ let files = collect_sea_files(&args.source)?;
333
+ if files.is_empty() {
334
+ anyhow::bail!("No .sea files matched the provided source patterns");
335
+ }
336
+
337
+ let graph = match parse_sea_files(&files) {
338
+ Ok(g) => g,
339
+ Err(err) => {
340
+ eprintln!("Parse error: {}", err);
341
+ std::process::exit(EXIT_PARSE_ERROR);
342
+ }
343
+ };
344
+
345
+ let concepts = graph_to_concepts(&graph);
346
+ let source_graph_hash = compute_graph_hash(&graph);
347
+
348
+ let review_records = match args.review {
349
+ Some(ref p) => load_review_records(p)?,
350
+ None => vec![],
351
+ };
352
+
353
+ let previous_pack = match args.previous_pack {
354
+ Some(ref p) => Some(load_pack_json(p)?),
355
+ None => None,
356
+ };
357
+
358
+ let approval = match args.approval {
359
+ ApprovalChoice::Candidate => ApprovalState::Candidate,
360
+ ApprovalChoice::Approved => ApprovalState::Approved,
361
+ };
362
+
363
+ let input = PackBuildInput {
364
+ org_id: args.org,
365
+ domain_id: args.domain,
366
+ pack_version: args.version,
367
+ meaning_version: args.meaning_version,
368
+ approval,
369
+ concepts,
370
+ relations: vec![],
371
+ metrics: vec![],
372
+ dimensions: vec![],
373
+ units: vec![],
374
+ aliases: vec![],
375
+ mapping_rules: vec![],
376
+ review_records,
377
+ previous_pack,
378
+ allow_first_approved_version: args.allow_first_approved_version,
379
+ source_graph_hash,
380
+ };
381
+
382
+ let output = match build_semantic_pack(input) {
383
+ Ok(o) => o,
384
+ Err(diagnostics) => {
385
+ print_diagnostics(&diagnostics, args.format);
386
+ std::process::exit(EXIT_SEMANTIC_FAILED);
387
+ }
388
+ };
389
+
390
+ if !output.pre_pack_diagnostics.is_empty() {
391
+ print_diagnostics(&output.pre_pack_diagnostics, args.format);
392
+ }
393
+ if !output.build_warnings.is_empty() {
394
+ print_diagnostics(&output.build_warnings, args.format);
395
+ }
396
+
397
+ let pack_json =
398
+ serde_json::to_string_pretty(&output.pack).context("Failed to serialize pack")?;
399
+
400
+ match args.out {
401
+ Some(ref p) => {
402
+ fs::write(p, &pack_json)
403
+ .with_context(|| format!("Failed to write pack to: {}", p.display()))?;
404
+ }
405
+ None => println!("{}", pack_json),
406
+ }
407
+
408
+ match args.format {
409
+ PackOutputFormat::Human => {
410
+ eprintln!(
411
+ "Built pack: {} (hash: {})",
412
+ output.pack.pack_id, output.pack_content_hash
413
+ );
414
+ eprintln!(
415
+ " {} concepts, meaning_fingerprint: {}",
416
+ output.pack.concepts.len(),
417
+ output.meaning_fingerprint
418
+ );
419
+ }
420
+ PackOutputFormat::Json => {
421
+ let meta = serde_json::json!({
422
+ "pack_id": output.pack.pack_id,
423
+ "content_hash": output.pack_content_hash,
424
+ "meaning_fingerprint": output.meaning_fingerprint,
425
+ "concept_count": output.pack.concepts.len(),
426
+ });
427
+ eprintln!("{}", serde_json::to_string_pretty(&meta).unwrap());
428
+ }
429
+ PackOutputFormat::Jsonl => {
430
+ eprintln!(
431
+ "{{\"pack_id\":\"{}\",\"content_hash\":\"{}\",\"concept_count\":{}}}",
432
+ output.pack.pack_id,
433
+ output.pack_content_hash,
434
+ output.pack.concepts.len()
435
+ );
436
+ }
437
+ }
438
+
439
+ Ok(())
440
+ }
441
+
442
+ fn run_validate(args: PackValidateArgs) -> Result<()> {
443
+ let pack = load_pack_json(&args.pack)?;
444
+
445
+ let content_hash = compute_pack_content_hash(&pack);
446
+ if let Some(ref expected) = args.expected_hash {
447
+ if *expected != content_hash {
448
+ let msg = format!(
449
+ "Pack content hash mismatch: expected '{}', got '{}'",
450
+ expected, content_hash
451
+ );
452
+ match args.format {
453
+ PackOutputFormat::Json => {
454
+ let out = serde_json::json!({
455
+ "status": "hash_mismatch",
456
+ "expected": expected,
457
+ "actual": content_hash,
458
+ });
459
+ println!("{}", serde_json::to_string_pretty(&out).unwrap());
460
+ }
461
+ _ => eprintln!("{}", msg.red()),
462
+ }
463
+ std::process::exit(EXIT_SIGNATURE_FAILURE);
464
+ }
465
+ }
466
+
467
+ if args.require_signature && pack.trust.signature_state != SignatureState::Signed {
468
+ let msg = format!(
469
+ "Pack '{}' is unsigned but --require-signature was set",
470
+ pack.pack_id
471
+ );
472
+ match args.format {
473
+ PackOutputFormat::Json => {
474
+ let out = serde_json::json!({
475
+ "status": "unsigned",
476
+ "pack_id": pack.pack_id,
477
+ });
478
+ println!("{}", serde_json::to_string_pretty(&out).unwrap());
479
+ }
480
+ _ => eprintln!("{}", msg.red()),
481
+ }
482
+ std::process::exit(EXIT_PACK_UNAVAILABLE);
483
+ }
484
+
485
+ let validation_mode = match args.mode {
486
+ ValidationModeChoice::Off => ValidationMode::Off,
487
+ ValidationModeChoice::Warn => ValidationMode::Warn,
488
+ ValidationModeChoice::Strict => ValidationMode::Strict,
489
+ };
490
+ let deprecated_policy = match args.deprecated_policy {
491
+ DeprecatedPolicyChoice::Allow => DeprecatedPolicy::Allow,
492
+ DeprecatedPolicyChoice::Warn => DeprecatedPolicy::Warn,
493
+ DeprecatedPolicyChoice::ErrorInStrict => DeprecatedPolicy::ErrorInStrict,
494
+ DeprecatedPolicyChoice::ErrorAlways => DeprecatedPolicy::ErrorAlways,
495
+ };
496
+
497
+ let options = ValidationOptions {
498
+ mode: validation_mode,
499
+ unknown_concept_policy: UnknownConceptPolicy::Warning,
500
+ deprecated_policy,
501
+ require_signed_pack: args.require_signature,
502
+ allow_unsigned_test_fixtures: false,
503
+ };
504
+
505
+ let pack_diagnostics = validate_semantic_pack(&pack)
506
+ .map_err(|e| anyhow::anyhow!("Pack validation error: {:?}", e))?;
507
+
508
+ let mut all_diagnostics = pack_diagnostics;
509
+
510
+ let mut combined_graph = Graph::new();
511
+ for input_path in &args.inputs {
512
+ let source = fs::read_to_string(input_path)
513
+ .with_context(|| format!("Failed to read: {}", input_path.display()))?;
514
+ let graph = parse_to_graph(&source)
515
+ .map_err(|e| anyhow::anyhow!("Parse error in {}: {}", input_path.display(), e))?;
516
+ combined_graph
517
+ .extend(graph)
518
+ .map_err(|e| anyhow::anyhow!("Merge error: {}", e))?;
519
+ }
520
+
521
+ if !combined_graph.is_empty() {
522
+ let source_uri = args
523
+ .inputs
524
+ .first()
525
+ .map(|p| p.display().to_string())
526
+ .unwrap_or_default();
527
+ let result = validate_graph_with_pack(&pack, &source_uri, &options);
528
+ all_diagnostics.extend(result.diagnostics);
529
+ }
530
+
531
+ let has_errors = all_diagnostics
532
+ .iter()
533
+ .any(|d| d.severity == DiagnosticSeverity::Error);
534
+
535
+ match args.format {
536
+ PackOutputFormat::Json => {
537
+ let out = serde_json::json!({
538
+ "pack_id": pack.pack_id,
539
+ "content_hash": content_hash,
540
+ "diagnostic_count": all_diagnostics.len(),
541
+ "has_errors": has_errors,
542
+ "diagnostics": all_diagnostics.iter().map(diagnostics_to_json).collect::<Vec<_>>(),
543
+ });
544
+ println!("{}", serde_json::to_string_pretty(&out).unwrap());
545
+ }
546
+ PackOutputFormat::Jsonl => {
547
+ for d in &all_diagnostics {
548
+ let json = serde_json::to_string(&diagnostics_to_json(d)).unwrap();
549
+ println!("{}", json);
550
+ }
551
+ }
552
+ PackOutputFormat::Human => {
553
+ if all_diagnostics.is_empty() {
554
+ println!(
555
+ "Pack validation passed for '{}' ({})",
556
+ pack.pack_id, content_hash
557
+ );
558
+ if !args.inputs.is_empty() {
559
+ println!(
560
+ " {} input file(s) validated against pack",
561
+ args.inputs.len()
562
+ );
563
+ }
564
+ } else {
565
+ let label = if has_errors {
566
+ "FAILED".red().to_string()
567
+ } else {
568
+ "WARNINGS".yellow().to_string()
569
+ };
570
+ println!(
571
+ "Pack validation {} for '{}' ({}): {} diagnostic(s)",
572
+ label,
573
+ pack.pack_id,
574
+ content_hash,
575
+ all_diagnostics.len()
576
+ );
577
+ for d in &all_diagnostics {
578
+ let sev = format_severity(d.severity);
579
+ println!(
580
+ " [{}] {} ({}): {}",
581
+ sev,
582
+ d.code.as_str(),
583
+ d.source_ref.uri,
584
+ d.message
585
+ );
586
+ }
587
+ }
588
+ }
589
+ }
590
+
591
+ if has_errors {
592
+ std::process::exit(EXIT_SEMANTIC_FAILED);
593
+ }
594
+ Ok(())
595
+ }
596
+
597
+ fn run_inspect(args: InspectArgs) -> Result<()> {
598
+ let pack = load_pack_json(&args.pack)?;
599
+ let content_hash = compute_pack_content_hash(&pack);
600
+
601
+ match args.format {
602
+ PackOutputFormat::Json => {
603
+ let out = serde_json::json!({
604
+ "schema_version": pack.schema_version,
605
+ "pack_id": pack.pack_id,
606
+ "org_id": pack.org_id,
607
+ "domain_id": pack.domain_id,
608
+ "pack_version": pack.pack_version,
609
+ "meaning_version": pack.meaning_version,
610
+ "meaning_fingerprint": pack.meaning_fingerprint,
611
+ "content_hash": content_hash,
612
+ "source_graph_hash": pack.source_graph_hash,
613
+ "created_at": pack.created_at,
614
+ "generator": pack.generator,
615
+ "trust": pack.trust,
616
+ "counts": {
617
+ "concepts": pack.concepts.len(),
618
+ "relations": pack.relations.len(),
619
+ "metrics": pack.metrics.len(),
620
+ "dimensions": pack.dimensions.len(),
621
+ "units": pack.units.len(),
622
+ "aliases": pack.aliases.len(),
623
+ "mapping_rules": pack.mapping_rules.len(),
624
+ },
625
+ });
626
+ println!("{}", serde_json::to_string_pretty(&out).unwrap());
627
+ }
628
+ PackOutputFormat::Jsonl => {
629
+ let row = serde_json::json!({
630
+ "pack_id": pack.pack_id,
631
+ "content_hash": content_hash,
632
+ "concepts": pack.concepts.len(),
633
+ "relations": pack.relations.len(),
634
+ "metrics": pack.metrics.len(),
635
+ "dimensions": pack.dimensions.len(),
636
+ "units": pack.units.len(),
637
+ "aliases": pack.aliases.len(),
638
+ "mapping_rules": pack.mapping_rules.len(),
639
+ });
640
+ println!("{}", serde_json::to_string(&row).unwrap());
641
+ }
642
+ PackOutputFormat::Human => {
643
+ println!("{}", "Semantic Pack".bold());
644
+ println!("{:<25} {}", "Pack ID:".dimmed(), pack.pack_id);
645
+ println!("{:<25} {}", "Schema Version:".dimmed(), pack.schema_version);
646
+ println!(
647
+ "{:<25} {}",
648
+ "Org / Domain:".dimmed(),
649
+ format_args!("{}/{}", pack.org_id, pack.domain_id)
650
+ );
651
+ println!("{:<25} {}", "Pack Version:".dimmed(), pack.pack_version);
652
+ println!(
653
+ "{:<25} {}",
654
+ "Meaning Version:".dimmed(),
655
+ pack.meaning_version
656
+ );
657
+ println!(
658
+ "{:<25} {}",
659
+ "Meaning Fingerprint:".dimmed(),
660
+ pack.meaning_fingerprint
661
+ );
662
+ println!("{:<25} {}", "Content Hash:".dimmed(), content_hash);
663
+ println!(
664
+ "{:<25} {}",
665
+ "Source Graph Hash:".dimmed(),
666
+ pack.source_graph_hash
667
+ );
668
+ println!("{:<25} {}", "Created At:".dimmed(), pack.created_at);
669
+ println!(
670
+ "{:<25} {} {}",
671
+ "Generator:".dimmed(),
672
+ pack.generator.name,
673
+ pack.generator.version
674
+ );
675
+ println!(
676
+ "{:<25} {:?} / {:?}",
677
+ "Trust:".dimmed(),
678
+ pack.trust.approval_state,
679
+ pack.trust.signature_state,
680
+ );
681
+ println!();
682
+ println!("{}", "Counts".bold());
683
+ println!("{:<25} {}", "Concepts:".dimmed(), pack.concepts.len());
684
+ println!("{:<25} {}", "Relations:".dimmed(), pack.relations.len());
685
+ println!("{:<25} {}", "Metrics:".dimmed(), pack.metrics.len());
686
+ println!("{:<25} {}", "Dimensions:".dimmed(), pack.dimensions.len());
687
+ println!("{:<25} {}", "Units:".dimmed(), pack.units.len());
688
+ println!("{:<25} {}", "Aliases:".dimmed(), pack.aliases.len());
689
+ println!(
690
+ "{:<25} {}",
691
+ "Mapping Rules:".dimmed(),
692
+ pack.mapping_rules.len()
693
+ );
694
+
695
+ if !pack.concepts.is_empty() {
696
+ println!();
697
+ println!("{}", "Concepts".bold());
698
+ for c in &pack.concepts {
699
+ let status = format!("{:?}", c.status).to_lowercase();
700
+ let kind = format!("{:?}", c.kind).to_lowercase();
701
+ println!(
702
+ " {} {} [{}] {}",
703
+ c.id.cyan(),
704
+ c.canonical_name,
705
+ kind.dimmed(),
706
+ status
707
+ );
708
+ }
709
+ }
710
+ }
711
+ }
712
+
713
+ Ok(())
714
+ }
715
+
716
+ fn run_diff(args: DiffArgs) -> Result<()> {
717
+ let old = load_pack_json(&args.old)?;
718
+ let new = load_pack_json(&args.new)?;
719
+
720
+ let diff_result = diff_packs(&old, &new);
721
+
722
+ match args.format {
723
+ PackOutputFormat::Json => {
724
+ let out =
725
+ serde_json::to_string_pretty(&diff_result).context("Failed to serialize diff")?;
726
+ println!("{}", out);
727
+ }
728
+ PackOutputFormat::Jsonl => {
729
+ for entry in &diff_result.entries {
730
+ let json = serde_json::to_string(&entry).unwrap();
731
+ println!("{}", json);
732
+ }
733
+ }
734
+ PackOutputFormat::Human => {
735
+ println!(
736
+ "Diff: {} -> {}",
737
+ diff_result.old_pack_id, diff_result.new_pack_id
738
+ );
739
+ println!();
740
+ println!(
741
+ "{} additive, {} definitional, {} deprecating, {} breaking, {} governance, {} signature-only",
742
+ diff_result.summary.additive_count.to_string().green(),
743
+ diff_result.summary.definitional_change_count.to_string().yellow(),
744
+ diff_result.summary.deprecating_count.to_string().magenta(),
745
+ diff_result.summary.breaking_count.to_string().red(),
746
+ diff_result.summary.governance_critical_count.to_string().red().bold(),
747
+ diff_result.summary.signature_only_count,
748
+ );
749
+
750
+ if diff_result.entries.is_empty() {
751
+ println!("\nNo differences found.");
752
+ } else {
753
+ println!();
754
+ for entry in &diff_result.entries {
755
+ let classification = format_classification(entry.classification);
756
+ println!(
757
+ " [{}] {}: {}",
758
+ classification, entry.subject_id, entry.detail,
759
+ );
760
+ }
761
+ }
762
+ }
763
+ }
764
+
765
+ let has_breaking = diff_result
766
+ .entries
767
+ .iter()
768
+ .any(|e| matches!(e.classification, DiffClassification::Breaking));
769
+ if has_breaking {
770
+ std::process::exit(EXIT_SEMANTIC_FAILED);
771
+ }
772
+ Ok(())
773
+ }
774
+
775
+ fn run_sign(args: SignArgs) -> Result<()> {
776
+ let pack = load_pack_json(&args.pack)?;
777
+ let key_pem = fs::read(&args.key)
778
+ .with_context(|| format!("Failed to read private key: {}", args.key.display()))?;
779
+
780
+ let sign_output = match sign_pack(&pack, &key_pem) {
781
+ Ok(o) => o,
782
+ Err(e) => {
783
+ let msg = format!("Signing failed: {:?}", e);
784
+ eprintln!("{}", msg.red());
785
+ std::process::exit(EXIT_SIGNATURE_FAILURE);
786
+ }
787
+ };
788
+
789
+ let signer_id = match derive_signer_id(&key_pem) {
790
+ Ok(id) => id,
791
+ Err(e) => {
792
+ let msg = format!("Failed to derive signer identity: {:?}", e);
793
+ eprintln!("{}", msg.red());
794
+ std::process::exit(EXIT_SIGNATURE_FAILURE);
795
+ }
796
+ };
797
+
798
+ let mut signed_pack = pack;
799
+ signed_pack.trust.signature_state = SignatureState::Signed;
800
+ signed_pack.trust.signature = Some(sign_output.signature);
801
+ signed_pack.trust.signature_alg = Some(sign_output.signature_alg);
802
+ signed_pack.trust.signed_by = Some(signer_id);
803
+
804
+ let pack_json =
805
+ serde_json::to_string_pretty(&signed_pack).context("Failed to serialize signed pack")?;
806
+
807
+ match args.out {
808
+ Some(ref p) => {
809
+ fs::write(p, &pack_json)
810
+ .with_context(|| format!("Failed to write signed pack to: {}", p.display()))?;
811
+ eprintln!("Signed pack written to: {}", p.display());
812
+ }
813
+ None => println!("{}", pack_json),
814
+ }
815
+
816
+ Ok(())
817
+ }
818
+
819
+ fn run_verify(args: VerifyArgs) -> Result<()> {
820
+ let pack = load_pack_json(&args.pack)?;
821
+ let key_pem = fs::read(&args.key)
822
+ .with_context(|| format!("Failed to read public key: {}", args.key.display()))?;
823
+
824
+ match verify_pack_signature(&pack, &key_pem) {
825
+ Ok(()) => {
826
+ println!(
827
+ "Signature verified for pack '{}' ({})",
828
+ pack.pack_id,
829
+ pack.trust.signature_alg.as_deref().unwrap_or("unknown")
830
+ );
831
+ Ok(())
832
+ }
833
+ Err(e) => {
834
+ let msg = format!(
835
+ "Signature verification failed for pack '{}': {:?}",
836
+ pack.pack_id, e
837
+ );
838
+ eprintln!("{}", msg.red());
839
+ std::process::exit(EXIT_SIGNATURE_FAILURE);
840
+ }
841
+ }
842
+ }
843
+
844
+ fn print_diagnostics(diagnostics: &[SemanticDiagnostic], format: PackOutputFormat) {
845
+ match format {
846
+ PackOutputFormat::Json => {
847
+ let out: Vec<_> = diagnostics.iter().map(diagnostics_to_json).collect();
848
+ eprintln!("{}", serde_json::to_string_pretty(&out).unwrap());
849
+ }
850
+ PackOutputFormat::Jsonl => {
851
+ for d in diagnostics {
852
+ let json = serde_json::to_string(&diagnostics_to_json(d)).unwrap();
853
+ eprintln!("{}", json);
854
+ }
855
+ }
856
+ PackOutputFormat::Human => {
857
+ for d in diagnostics {
858
+ let sev = format_severity(d.severity);
859
+ eprintln!(
860
+ "[{}] {} ({}): {}",
861
+ sev,
862
+ d.code.as_str(),
863
+ d.source_ref.uri,
864
+ d.message
865
+ );
866
+ if !d.recoverability_hint.is_empty() {
867
+ eprintln!(" hint: {}", d.recoverability_hint.dimmed());
868
+ }
869
+ }
870
+ }
871
+ }
872
+ }
873
+
874
+ fn diagnostics_to_json(d: &SemanticDiagnostic) -> serde_json::Value {
875
+ serde_json::json!({
876
+ "code": d.code.as_str(),
877
+ "severity": format!("{:?}", d.severity).to_lowercase(),
878
+ "semantic_truth": format!("{:?}", d.semantic_truth).to_lowercase(),
879
+ "message": d.message,
880
+ "source_ref": d.source_ref.uri,
881
+ "pack_ref": d.pack_ref.pack_id,
882
+ "recoverability_hint": d.recoverability_hint,
883
+ })
884
+ }
885
+
886
+ fn format_severity(severity: DiagnosticSeverity) -> String {
887
+ match severity {
888
+ DiagnosticSeverity::Error => "ERROR".red().to_string(),
889
+ DiagnosticSeverity::Warning => "WARN".yellow().to_string(),
890
+ DiagnosticSeverity::Info => "INFO".blue().to_string(),
891
+ DiagnosticSeverity::Hint => "HINT".dimmed().to_string(),
892
+ }
893
+ }
894
+
895
+ fn format_classification(c: DiffClassification) -> String {
896
+ match c {
897
+ DiffClassification::Additive => "ADD".green().to_string(),
898
+ DiffClassification::DefinitionalChange => "DEF".yellow().to_string(),
899
+ DiffClassification::Deprecating => "DEP".magenta().to_string(),
900
+ DiffClassification::Breaking => "BRK".red().to_string(),
901
+ DiffClassification::GovernanceCritical => "GOV".red().bold().to_string(),
902
+ DiffClassification::SignatureOnly => "SIG".dimmed().to_string(),
903
+ }
904
+ }