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,140 @@
1
+ //! Three-valued boolean logic (SQL-like UNKNOWN) for SEA policy evaluation.
2
+
3
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
4
+ pub enum ThreeValuedBool {
5
+ True,
6
+ False,
7
+ Null,
8
+ }
9
+
10
+ impl ThreeValuedBool {
11
+ pub fn and(self, other: Self) -> Self {
12
+ use ThreeValuedBool::*;
13
+ match (self, other) {
14
+ (False, _) | (_, False) => False,
15
+ (True, True) => True,
16
+ (True, Null) | (Null, True) | (Null, Null) => Null,
17
+ }
18
+ }
19
+
20
+ pub fn or(self, other: Self) -> Self {
21
+ use ThreeValuedBool::*;
22
+ match (self, other) {
23
+ (True, _) | (_, True) => True,
24
+ (False, False) => False,
25
+ _ => Null,
26
+ }
27
+ }
28
+
29
+ #[allow(clippy::should_implement_trait)]
30
+ pub fn not(self) -> Self {
31
+ !self
32
+ }
33
+
34
+ pub fn implies(self, other: Self) -> Self {
35
+ // A -> B == (not A) or B
36
+ (!self).or(other)
37
+ }
38
+
39
+ pub fn from_option_bool(v: Option<bool>) -> Self {
40
+ match v {
41
+ Some(true) => ThreeValuedBool::True,
42
+ Some(false) => ThreeValuedBool::False,
43
+ None => ThreeValuedBool::Null,
44
+ }
45
+ }
46
+
47
+ pub fn into_option(self) -> Option<bool> {
48
+ match self {
49
+ ThreeValuedBool::True => Some(true),
50
+ ThreeValuedBool::False => Some(false),
51
+ ThreeValuedBool::Null => None,
52
+ }
53
+ }
54
+
55
+ pub fn fold_and<I: IntoIterator<Item = Self>>(iter: I) -> Self {
56
+ let mut seen_null = false;
57
+ for v in iter {
58
+ match v {
59
+ ThreeValuedBool::False => return ThreeValuedBool::False,
60
+ ThreeValuedBool::Null => seen_null = true,
61
+ ThreeValuedBool::True => {}
62
+ }
63
+ }
64
+ if seen_null {
65
+ ThreeValuedBool::Null
66
+ } else {
67
+ ThreeValuedBool::True
68
+ }
69
+ }
70
+
71
+ pub fn fold_or<I: IntoIterator<Item = Self>>(iter: I) -> Self {
72
+ let mut seen_null = false;
73
+ for v in iter {
74
+ match v {
75
+ ThreeValuedBool::True => return ThreeValuedBool::True,
76
+ ThreeValuedBool::Null => seen_null = true,
77
+ ThreeValuedBool::False => {}
78
+ }
79
+ }
80
+ if seen_null {
81
+ ThreeValuedBool::Null
82
+ } else {
83
+ ThreeValuedBool::False
84
+ }
85
+ }
86
+ }
87
+
88
+ impl std::ops::Not for ThreeValuedBool {
89
+ type Output = Self;
90
+
91
+ fn not(self) -> Self::Output {
92
+ use ThreeValuedBool::*;
93
+ match self {
94
+ True => False,
95
+ False => True,
96
+ Null => Null,
97
+ }
98
+ }
99
+ }
100
+
101
+ pub mod aggregators {
102
+ #![allow(dead_code)]
103
+ use rust_decimal::Decimal;
104
+
105
+ /// Sum that returns None (Null) if any element is missing.
106
+ pub fn sum_nullable(items: &[Option<Decimal>]) -> Option<Decimal> {
107
+ let mut total = Decimal::ZERO;
108
+ let mut any_null = false;
109
+ for item in items {
110
+ match item {
111
+ Some(v) => total += *v,
112
+ None => any_null = true,
113
+ }
114
+ }
115
+ if any_null {
116
+ None
117
+ } else {
118
+ Some(total)
119
+ }
120
+ }
121
+
122
+ /// Sum that ignores NULLs.
123
+ pub fn sum_nonnull(items: &[Option<Decimal>]) -> Decimal {
124
+ let mut total = Decimal::ZERO;
125
+ for v in items.iter().flatten() {
126
+ total += *v;
127
+ }
128
+ total
129
+ }
130
+
131
+ /// Count all items, including nulls.
132
+ pub fn count_all<T>(items: &[Option<T>]) -> usize {
133
+ items.len()
134
+ }
135
+
136
+ /// Count only non-null items.
137
+ pub fn count_nonnull<T>(items: &[Option<T>]) -> usize {
138
+ items.iter().filter(|x| x.is_some()).count()
139
+ }
140
+ }
@@ -0,0 +1,104 @@
1
+ use super::three_valued::aggregators::sum_nullable;
2
+ /// Simple micro-benchmark using std::time::Instant
3
+ /// Run with: cargo test --release -- --nocapture --ignored bench_microbench
4
+ use rust_decimal::Decimal;
5
+
6
+ #[cfg(test)]
7
+ mod microbench {
8
+ use super::*;
9
+ use std::time::Instant;
10
+
11
+ #[test]
12
+ #[ignore] // Run explicitly with --ignored
13
+ fn bench_microbench_sum_comparison() {
14
+ const ITERATIONS: usize = 10_000;
15
+ const DATA_SIZE: usize = 1_000;
16
+ const WARMUP_ITERS: usize = 100;
17
+
18
+ // Baseline: strict sum with manual loop (more comparable to nullable version)
19
+ let data_strict: Vec<Decimal> = (0..DATA_SIZE).map(|i| Decimal::new(i as i64, 0)).collect();
20
+
21
+ let expected_strict_sum: Decimal = data_strict.iter().copied().sum();
22
+
23
+ for _ in 0..WARMUP_ITERS {
24
+ let mut total = Decimal::ZERO;
25
+ for item in &data_strict {
26
+ total += *item;
27
+ }
28
+ std::hint::black_box(total);
29
+ }
30
+
31
+ let start = Instant::now();
32
+ let mut last_strict_total = Decimal::ZERO;
33
+ for _ in 0..ITERATIONS {
34
+ let mut total = Decimal::ZERO;
35
+ for item in &data_strict {
36
+ total += *item;
37
+ }
38
+ std::hint::black_box(total);
39
+ last_strict_total = total;
40
+ }
41
+ let baseline_duration = start.elapsed();
42
+ assert_eq!(
43
+ last_strict_total, expected_strict_sum,
44
+ "strict sum should equal the arithmetic series of {} elements",
45
+ DATA_SIZE
46
+ );
47
+
48
+ // Nullable sum with 10% nulls
49
+ let data_nullable: Vec<Option<Decimal>> = (0..DATA_SIZE)
50
+ .map(|i| {
51
+ if i % 10 == 0 {
52
+ None
53
+ } else {
54
+ Some(Decimal::new(i as i64, 0))
55
+ }
56
+ })
57
+ .collect();
58
+
59
+ let expected_nullable_sum = sum_nullable(&data_nullable);
60
+
61
+ for _ in 0..WARMUP_ITERS {
62
+ let result = sum_nullable(&data_nullable);
63
+ std::hint::black_box(result);
64
+ }
65
+
66
+ let start = Instant::now();
67
+ let mut last_nullable_result = None;
68
+ for _ in 0..ITERATIONS {
69
+ let result = sum_nullable(&data_nullable);
70
+ std::hint::black_box(result);
71
+ last_nullable_result = result;
72
+ }
73
+ let nullable_duration = start.elapsed();
74
+ assert_eq!(
75
+ last_nullable_result, expected_nullable_sum,
76
+ "nullable sum result should match expectation for data with 10% nulls"
77
+ );
78
+
79
+ // Calculate overhead
80
+ let baseline_nanos = baseline_duration.as_nanos();
81
+ let denom = baseline_nanos.max(1);
82
+ let nullable_nanos = nullable_duration.as_nanos();
83
+ let overhead_pct = ((nullable_nanos as f64 / denom as f64) - 1.0) * 100.0;
84
+
85
+ println!("\n=== Micro-Benchmark Results ===");
86
+ println!("Iterations: {}", ITERATIONS);
87
+ println!("Data size: {}", DATA_SIZE);
88
+ println!("Baseline (strict): {:?}", baseline_duration);
89
+ println!("Nullable (10% null): {:?}", nullable_duration);
90
+ println!("Overhead: {:.2}%", overhead_pct);
91
+ println!("================================\n");
92
+ println!("Note: Microbenchmarks show higher variance than Criterion.");
93
+ println!("Criterion benchmarks show ~7-10% overhead for this scenario.");
94
+
95
+ // Assert overhead is within acceptable range
96
+ // Note: Microbenchmarks typically show higher overhead than Criterion
97
+ // due to less sophisticated measurement techniques
98
+ assert!(
99
+ overhead_pct < 35.0,
100
+ "Overhead {:.2}% exceeds 35% threshold (microbench variance)",
101
+ overhead_pct
102
+ );
103
+ }
104
+ }
@@ -0,0 +1,67 @@
1
+ use crate::units::Dimension;
2
+ use thiserror::Error;
3
+
4
+ #[derive(Debug, Clone, PartialEq)]
5
+ pub enum ExprType {
6
+ Quantity { dimension: Dimension },
7
+ Numeric,
8
+ String,
9
+ Boolean,
10
+ Time,
11
+ Interval,
12
+ Collection(Box<ExprType>),
13
+ }
14
+
15
+ #[derive(Error, Debug, PartialEq)]
16
+ pub enum TypeError {
17
+ #[error("Unit mismatch: expected {expected}, found {found}. Hint: {hint}")]
18
+ UnitMismatch {
19
+ expected: Dimension,
20
+ found: Dimension,
21
+ hint: String,
22
+ },
23
+ #[error("Mixed quantity and numeric types. Hint: {hint}")]
24
+ MixedQuantityNumeric { hint: String },
25
+ #[error("Type mismatch: expected {expected}, found {found}")]
26
+ TypeMismatch { expected: String, found: String },
27
+ }
28
+
29
+ pub fn check_comparison(left: &ExprType, right: &ExprType) -> Result<(), TypeError> {
30
+ match (left, right) {
31
+ (ExprType::Quantity { dimension: d1 }, ExprType::Quantity { dimension: d2 }) => {
32
+ if d1 != d2 {
33
+ return Err(TypeError::UnitMismatch {
34
+ expected: d1.clone(),
35
+ found: d2.clone(),
36
+ hint: format!("Convert using 'as \"{}\"'", d1), // Simplified hint
37
+ });
38
+ }
39
+ }
40
+ (ExprType::Quantity { .. }, ExprType::Numeric) => {
41
+ return Err(TypeError::MixedQuantityNumeric {
42
+ hint: "Quantities require explicit units. Did you mean 'value as \"unit\"'?"
43
+ .to_string(),
44
+ });
45
+ }
46
+ (ExprType::Numeric, ExprType::Quantity { .. }) => {
47
+ return Err(TypeError::MixedQuantityNumeric {
48
+ hint: "Quantities require explicit units. Did you mean 'value as \"unit\"'?"
49
+ .to_string(),
50
+ });
51
+ }
52
+ (ExprType::Numeric, ExprType::Numeric) => {}
53
+ (ExprType::String, ExprType::String) => {}
54
+ (ExprType::Boolean, ExprType::Boolean) => {}
55
+ (ExprType::Time, ExprType::Time) => {} // Time before/after Time
56
+ (ExprType::Time, ExprType::Interval) => {} // Time during Interval
57
+ (ExprType::Interval, ExprType::Time) => {} // Interval contains Time (reverse)
58
+ (ExprType::Interval, ExprType::Interval) => {} // Interval comparisons
59
+ (t1, t2) => {
60
+ return Err(TypeError::TypeMismatch {
61
+ expected: format!("{:?}", t1),
62
+ found: format!("{:?}", t2),
63
+ });
64
+ }
65
+ }
66
+ Ok(())
67
+ }
@@ -0,0 +1,36 @@
1
+ use serde::{Deserialize, Serialize};
2
+
3
+ #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4
+ pub enum Severity {
5
+ Error,
6
+ Warning,
7
+ Info,
8
+ }
9
+
10
+ #[derive(Debug, Clone, Serialize, Deserialize)]
11
+ pub struct Violation {
12
+ pub policy_name: String,
13
+ pub message: String,
14
+ pub severity: Severity,
15
+ pub context: serde_json::Value,
16
+ }
17
+
18
+ impl Violation {
19
+ pub fn new(
20
+ policy_name: impl Into<String>,
21
+ message: impl Into<String>,
22
+ severity: Severity,
23
+ ) -> Self {
24
+ Self {
25
+ policy_name: policy_name.into(),
26
+ message: message.into(),
27
+ severity,
28
+ context: serde_json::json!({}),
29
+ }
30
+ }
31
+
32
+ pub fn with_context(mut self, context: serde_json::Value) -> Self {
33
+ self.context = context;
34
+ self
35
+ }
36
+ }
@@ -0,0 +1,61 @@
1
+ use crate::ConceptId;
2
+ use serde::{Deserialize, Serialize};
3
+
4
+ #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5
+ pub struct ConceptChange {
6
+ id: ConceptId,
7
+ name: String,
8
+ from_version: String,
9
+ to_version: String,
10
+ migration_policy: String,
11
+ breaking_change: bool,
12
+ }
13
+
14
+ impl ConceptChange {
15
+ pub fn new(
16
+ name: impl Into<String>,
17
+ from_version: impl Into<String>,
18
+ to_version: impl Into<String>,
19
+ migration_policy: impl Into<String>,
20
+ breaking_change: bool,
21
+ ) -> Self {
22
+ let name = name.into();
23
+ // Concept changes are usually global or tied to a namespace, but here we assume default namespace for simplicity
24
+ // or we could add namespace support. For now, let's assume global or default.
25
+ let namespace = "default";
26
+ let id = ConceptId::from_concept(namespace, &name);
27
+
28
+ Self {
29
+ id,
30
+ name,
31
+ from_version: from_version.into(),
32
+ to_version: to_version.into(),
33
+ migration_policy: migration_policy.into(),
34
+ breaking_change,
35
+ }
36
+ }
37
+
38
+ pub fn id(&self) -> &ConceptId {
39
+ &self.id
40
+ }
41
+
42
+ pub fn name(&self) -> &str {
43
+ &self.name
44
+ }
45
+
46
+ pub fn from_version(&self) -> &str {
47
+ &self.from_version
48
+ }
49
+
50
+ pub fn to_version(&self) -> &str {
51
+ &self.to_version
52
+ }
53
+
54
+ pub fn migration_policy(&self) -> &str {
55
+ &self.migration_policy
56
+ }
57
+
58
+ pub fn is_breaking_change(&self) -> bool {
59
+ self.breaking_change
60
+ }
61
+ }
@@ -0,0 +1,224 @@
1
+ use crate::ConceptId;
2
+ use crate::SemanticVersion;
3
+ use serde::{Deserialize, Serialize};
4
+ use serde_json::Value;
5
+ use std::collections::HashMap;
6
+ use uuid::Uuid;
7
+
8
+ /// Represents a business actor, location, or organizational unit.
9
+ ///
10
+ /// Entities are the "WHO" in enterprise models - the actors that perform
11
+ /// actions, hold resources, or participate in flows.
12
+ ///
13
+ /// # Examples
14
+ ///
15
+ /// Basic usage:
16
+ ///
17
+ /// ```
18
+ /// use domainforge_core::primitives::Entity;
19
+ ///
20
+ /// let warehouse = Entity::new_with_namespace("Main Warehouse", "default");
21
+ /// assert_eq!(warehouse.name(), "Main Warehouse");
22
+ /// assert_eq!(warehouse.namespace(), "default");
23
+ /// ```
24
+ ///
25
+ /// With namespace:
26
+ ///
27
+ /// ```
28
+ /// use domainforge_core::primitives::Entity;
29
+ ///
30
+ /// let warehouse = Entity::new_with_namespace("Warehouse A", "logistics");
31
+ /// assert_eq!(warehouse.namespace(), "logistics");
32
+ /// ```
33
+ ///
34
+ /// With custom attributes:
35
+ ///
36
+ /// ```
37
+ /// use domainforge_core::primitives::Entity;
38
+ /// use serde_json::json;
39
+ ///
40
+ /// let mut factory = Entity::new_with_namespace("Factory", "default");
41
+ /// factory.set_attribute("capacity", json!(5000));
42
+ /// factory.set_attribute("location", json!("Building 3"));
43
+ ///
44
+ /// assert_eq!(factory.get_attribute("capacity"), Some(&json!(5000)));
45
+ /// ```
46
+ ///
47
+ /// Serialization:
48
+ ///
49
+ /// ```
50
+ /// use domainforge_core::primitives::Entity;
51
+ ///
52
+ /// let entity = Entity::new_with_namespace("Test Entity", "default");
53
+ /// let json = serde_json::to_string(&entity).unwrap();
54
+ /// let deserialized: Entity = serde_json::from_str(&json).unwrap();
55
+ /// assert_eq!(entity.name(), deserialized.name());
56
+ /// ```
57
+ #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
58
+ pub struct Entity {
59
+ id: ConceptId,
60
+ name: String,
61
+ namespace: String,
62
+ version: Option<SemanticVersion>,
63
+ replaces: Option<String>,
64
+ changes: Vec<String>,
65
+ attributes: HashMap<String, Value>,
66
+ }
67
+
68
+ impl Entity {
69
+ /// Creates a new Entity with a generated UUID (deprecated - use new_with_namespace).
70
+ ///
71
+ /// # Examples
72
+ ///
73
+ /// ```
74
+ /// use domainforge_core::primitives::Entity;
75
+ ///
76
+ /// let entity = Entity::new_with_namespace("Warehouse", "default");
77
+ /// assert_eq!(entity.name(), "Warehouse");
78
+ /// ```
79
+ #[deprecated(note = "use new_with_namespace instead")]
80
+ pub fn new(name: impl Into<String>) -> Self {
81
+ let name = name.into();
82
+ let namespace = "default".to_string();
83
+ Self {
84
+ id: ConceptId::from_concept(&namespace, &name),
85
+ name,
86
+ namespace,
87
+ version: None,
88
+ replaces: None,
89
+ changes: Vec::new(),
90
+ attributes: HashMap::new(),
91
+ }
92
+ }
93
+
94
+ /// Creates a new Entity with a specific namespace.
95
+ ///
96
+ /// # Examples
97
+ ///
98
+ /// ```
99
+ /// use domainforge_core::primitives::Entity;
100
+ ///
101
+ /// let entity = Entity::new_with_namespace("Warehouse", "logistics");
102
+ /// assert_eq!(entity.namespace(), "logistics");
103
+ /// ```
104
+ pub fn new_with_namespace(name: impl Into<String>, namespace: impl Into<String>) -> Self {
105
+ let namespace = namespace.into();
106
+ let name = name.into();
107
+ let id = ConceptId::from_concept(&namespace, &name);
108
+
109
+ Self {
110
+ id,
111
+ name,
112
+ namespace,
113
+ version: None,
114
+ replaces: None,
115
+ changes: Vec::new(),
116
+ attributes: HashMap::new(),
117
+ }
118
+ }
119
+
120
+ /// Sets the entity version.
121
+ pub fn with_version(mut self, version: SemanticVersion) -> Self {
122
+ self.version = Some(version);
123
+ self
124
+ }
125
+
126
+ /// Sets the entity that this version replaces.
127
+ pub fn with_replaces(mut self, replaces: String) -> Self {
128
+ self.replaces = Some(replaces);
129
+ self
130
+ }
131
+
132
+ /// Sets the list of changes in this version.
133
+ pub fn with_changes(mut self, changes: Vec<String>) -> Self {
134
+ self.changes = changes;
135
+ self
136
+ }
137
+
138
+ /// Returns the entity version.
139
+ pub fn version(&self) -> Option<&SemanticVersion> {
140
+ self.version.as_ref()
141
+ }
142
+
143
+ /// Returns the entity that this version replaces.
144
+ pub fn replaces(&self) -> Option<&str> {
145
+ self.replaces.as_deref()
146
+ }
147
+
148
+ /// Returns the list of changes in this version.
149
+ pub fn changes(&self) -> &[String] {
150
+ &self.changes
151
+ }
152
+
153
+ /// Creates an Entity from a legacy UUID for backward compatibility.
154
+ pub fn from_legacy_uuid(
155
+ uuid: Uuid,
156
+ name: impl Into<String>,
157
+ namespace: impl Into<String>,
158
+ ) -> Self {
159
+ Self {
160
+ id: ConceptId::from_legacy_uuid(uuid),
161
+ name: name.into(),
162
+ namespace: namespace.into(),
163
+ version: None,
164
+ replaces: None,
165
+ changes: Vec::new(),
166
+ attributes: HashMap::new(),
167
+ }
168
+ }
169
+
170
+ /// Returns the entity's unique identifier.
171
+ pub fn id(&self) -> &ConceptId {
172
+ &self.id
173
+ }
174
+
175
+ /// Returns the entity's name.
176
+ pub fn name(&self) -> &str {
177
+ &self.name
178
+ }
179
+
180
+ /// Returns the entity's namespace.
181
+ pub fn namespace(&self) -> &str {
182
+ &self.namespace
183
+ }
184
+
185
+ /// Sets a custom attribute.
186
+ ///
187
+ /// # Examples
188
+ ///
189
+ /// ```
190
+ /// use domainforge_core::primitives::Entity;
191
+ /// use serde_json::json;
192
+ ///
193
+ /// let mut entity = Entity::new_with_namespace("Factory", "default");
194
+ /// entity.set_attribute("capacity", json!(5000));
195
+ /// assert_eq!(entity.get_attribute("capacity"), Some(&json!(5000)));
196
+ /// ```
197
+ pub fn set_attribute(&mut self, key: impl Into<String>, value: Value) {
198
+ self.attributes.insert(key.into(), value);
199
+ }
200
+
201
+ /// Gets a custom attribute.
202
+ ///
203
+ /// Returns `None` if the attribute doesn't exist.
204
+ ///
205
+ /// # Examples
206
+ ///
207
+ /// ```
208
+ /// use domainforge_core::primitives::Entity;
209
+ /// use serde_json::json;
210
+ ///
211
+ /// let mut entity = Entity::new_with_namespace("Factory", "default");
212
+ /// entity.set_attribute("capacity", json!(5000));
213
+ /// assert_eq!(entity.get_attribute("capacity"), Some(&json!(5000)));
214
+ /// assert_eq!(entity.get_attribute("missing"), None);
215
+ /// ```
216
+ pub fn get_attribute(&self, key: &str) -> Option<&Value> {
217
+ self.attributes.get(key)
218
+ }
219
+
220
+ /// Returns all attributes as a reference.
221
+ pub fn attributes(&self) -> &HashMap<String, Value> {
222
+ &self.attributes
223
+ }
224
+ }