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.
- package/.cargo/config.toml +6 -0
- package/.claude/settings.local.json +18 -0
- package/.coderabbit.yml +43 -0
- package/.codex/skills/release-management/SKILL.md +151 -0
- package/.codex/skills/release-management/agents/openai.yaml +4 -0
- package/.github/actions/decrypt-secrets/action.yml +121 -0
- package/.github/agents/Coder.agent.md +97 -0
- package/.github/agents/DeepResearch.agent.md +61 -0
- package/.github/chatmodes/tdd.vibepro.chatmode.md +1183 -0
- package/.github/copilot-instructions.md +13 -0
- package/.github/dependabot.yml +68 -0
- package/.github/workflows/README.md +165 -0
- package/.github/workflows/ci.yml +335 -0
- package/.github/workflows/dependabot-automerge.yml +114 -0
- package/.github/workflows/dependency-review.yml +27 -0
- package/.github/workflows/deploy.yml +87 -0
- package/.github/workflows/prepare-release.yml +168 -0
- package/.github/workflows/release-crates.yml +42 -0
- package/.github/workflows/release-npm.yml +137 -0
- package/.github/workflows/release-please.yml +29 -0
- package/.github/workflows/release-pypi.yml +96 -0
- package/.gitkeep +1 -0
- package/.release-please-manifest.json +5 -0
- package/.sea-registry.toml +10 -0
- package/.serena/project.yml +133 -0
- package/.sops.yaml +10 -0
- package/AGENTS.md +216 -0
- package/CHANGELOG.md +400 -0
- package/CLAUDE.md +62 -0
- package/CONTRIBUTING.md +323 -0
- package/Cargo.lock +3612 -0
- package/Cargo.toml +12 -0
- package/LICENSE +201 -0
- package/README.md +660 -0
- package/README_PYTHON.md +256 -0
- package/README_TYPESCRIPT.md +305 -0
- package/README_WASM.md +329 -0
- package/RELEASE_NOTES.md +41 -0
- package/bun.lock +378 -0
- package/bunfig.toml +11 -0
- package/check_output.txt +83 -0
- package/clippy_output.txt +80 -0
- package/commitlint.config.cjs +8 -0
- package/deny.toml +42 -0
- package/devbox.json +14 -0
- package/devbox.lock +76 -0
- package/docs/RELEASE_PROCESS.md +360 -0
- package/docs/diagnostics.md +161 -0
- package/docs/doc_guidelines.md +53 -0
- package/docs/explanations/README.md +21 -0
- package/docs/explanations/architecture-overview.md +109 -0
- package/docs/explanations/cross-language-binding-strategy.md +68 -0
- package/docs/explanations/graph-store-design.md +47 -0
- package/docs/explanations/performance-benchmarks.md +63 -0
- package/docs/explanations/policy-evaluation-logic.md +106 -0
- package/docs/explanations/semantic-modeling-concepts.md +109 -0
- package/docs/explanations/three-valued-logic.md +66 -0
- package/docs/explanations/versioning-strategy.md +45 -0
- package/docs/governance.md +168 -0
- package/docs/how-tos/README.md +46 -0
- package/docs/how-tos/ci-cd-validation.md +93 -0
- package/docs/how-tos/create-custom-units.md +125 -0
- package/docs/how-tos/define-policies.md +119 -0
- package/docs/how-tos/export-to-calm.md +110 -0
- package/docs/how-tos/export-to-protobuf.md +312 -0
- package/docs/how-tos/extend-grammar.md +133 -0
- package/docs/how-tos/generate-rdf-turtle.md +106 -0
- package/docs/how-tos/import-from-calm.md +114 -0
- package/docs/how-tos/import-from-sbvr.md +249 -0
- package/docs/how-tos/install-cli.md +126 -0
- package/docs/how-tos/parse-sea-files.md +132 -0
- package/docs/how-tos/policy-evaluation-modes.md +30 -0
- package/docs/how-tos/run-cross-language-tests.md +115 -0
- package/docs/how-tos/troubleshoot-napi-builds.md +55 -0
- package/docs/how-tos/use-modules-imports.md +285 -0
- package/docs/index.md +13 -0
- package/docs/plans/canonical-normalizer.md +121 -0
- package/docs/plans/cd_improvement.md +112 -0
- package/docs/plans/cli-ast.md +29 -0
- package/docs/plans/expression-bindings-and-normalizer-integration.md +174 -0
- package/docs/plans/protobuf_advanced_features_plan.md +597 -0
- package/docs/plans/protobuf_plan.yml +525 -0
- package/docs/plans/refactor_dsl_architecture.md +131 -0
- package/docs/plans/release-plan.md +163 -0
- package/docs/plans/sea_fmt_implementation_plan.md +516 -0
- package/docs/playbooks/README.md +18 -0
- package/docs/playbooks/adding-new-primitive.md +68 -0
- package/docs/playbooks/debugging-parser-failures.md +42 -0
- package/docs/playbooks/local-release-preparation.md +139 -0
- package/docs/playbooks/migrating-schema-versions.md +43 -0
- package/docs/playbooks/onboarding-contributors.md +64 -0
- package/docs/playbooks/releasing-beta.md +86 -0
- package/docs/playbooks/secret-management.md +64 -0
- package/docs/reference/README.md +199 -0
- package/docs/reference/ast-json-api.md +427 -0
- package/docs/reference/calm-mapping.md +519 -0
- package/docs/reference/cli-commands.md +588 -0
- package/docs/reference/configuration.md +202 -0
- package/docs/reference/error-codes.md +664 -0
- package/docs/reference/generated-artifacts-policy.md +53 -0
- package/docs/reference/grammar-spec.md +255 -0
- package/docs/reference/primitives-api.md +317 -0
- package/docs/reference/protobuf-api.md +426 -0
- package/docs/reference/python-api.md +485 -0
- package/docs/reference/registry.md +50 -0
- package/docs/reference/sea-dsl-ai-cheatsheet.yaml +913 -0
- package/docs/reference/security-model.md +74 -0
- package/docs/reference/typescript-api.md +508 -0
- package/docs/reference/wasm-api.md +420 -0
- package/docs/semantic-pack-review.md +144 -0
- package/docs/semantic-pack-signing.md +234 -0
- package/docs/semantic-packs.md +284 -0
- package/docs/specs/ADR-001-sea-dsl-semantic-source-of-truth.md +33 -0
- package/docs/specs/ADR-002-projection-first-class-construct.md +50 -0
- package/docs/specs/ADR-003-protobuf-projection-target.md +51 -0
- package/docs/specs/ADR-004-projection-compatibility-semantics.md +57 -0
- package/docs/specs/ADR-005-multi-language-support-strategy.md +112 -0
- package/docs/specs/ADR-006-error-handling-strategy.md +115 -0
- package/docs/specs/ADR-007-policy-evaluation-engine.md +95 -0
- package/docs/specs/ADR-008-knowledge-graph-integration.md +90 -0
- package/docs/specs/ADR-009-module-resolution-strategy.md +115 -0
- package/docs/specs/ADR-010-unit-system.md +106 -0
- package/docs/specs/PRD-001-sea-projection-framework.md +155 -0
- package/docs/specs/PRD-002-sea-cli-tooling.md +169 -0
- package/docs/specs/PRD-003-dsl-core-capabilities.md +275 -0
- package/docs/specs/README.md +62 -0
- package/docs/specs/SDS-001-protobuf-projection-engine.md +451 -0
- package/docs/specs/SDS-002-sea-core-architecture.md +268 -0
- package/docs/specs/SDS-003-parser-semantic-graph.md +377 -0
- package/docs/specs/SDS-004-policy-engine-design.md +362 -0
- package/docs/specs/SDS-005-knowledge-graph-module.md +364 -0
- package/docs/specs/SDS-006-calm-integration.md +367 -0
- package/docs/specs/SDS-007-sbvr-import.md +347 -0
- package/docs/templates/template_explanation.md +14 -0
- package/docs/templates/template_howto.md +21 -0
- package/docs/templates/template_playbook.md +21 -0
- package/docs/templates/template_reference.md +17 -0
- package/docs/templates/template_tutorial.md +24 -0
- package/docs/tutorials/README.md +12 -0
- package/docs/tutorials/first-sea-model.md +85 -0
- package/docs/tutorials/getting-started.md +98 -0
- package/docs/tutorials/python-binding-quickstart.md +107 -0
- package/docs/tutorials/typescript-binding-quickstart.md +91 -0
- package/docs/tutorials/wasm-in-browser.md +75 -0
- package/domainforge-core/CHANGELOG.md +138 -0
- package/domainforge-core/Cargo.toml +101 -0
- package/domainforge-core/MIGRATING.md +32 -0
- package/domainforge-core/README.md +197 -0
- package/domainforge-core/benchmark_results.txt +51 -0
- package/domainforge-core/build.rs +6 -0
- package/domainforge-core/deny.toml +31 -0
- package/domainforge-core/docs/specs/projections/sbvr_kg_mapping.md +43 -0
- package/domainforge-core/examples/basic.sea +7 -0
- package/domainforge-core/examples/cli/import_export_workflow.sh +38 -0
- package/domainforge-core/examples/cli/validate_example.sh +30 -0
- package/domainforge-core/examples/evolution_semantics.sea +31 -0
- package/domainforge-core/examples/parser_demo.rs +203 -0
- package/domainforge-core/grammar/sea.pest +408 -0
- package/domainforge-core/schemas/calm-v1.schema.json +170 -0
- package/domainforge-core/schemas/shacl/sea_shapes.ttl +19 -0
- package/domainforge-core/src/authority/compiler.rs +309 -0
- package/domainforge-core/src/authority/environment.rs +203 -0
- package/domainforge-core/src/authority/error.rs +164 -0
- package/domainforge-core/src/authority/fact_resolver.rs +224 -0
- package/domainforge-core/src/authority/mod.rs +25 -0
- package/domainforge-core/src/authority/pack.rs +133 -0
- package/domainforge-core/src/authority/policy.rs +224 -0
- package/domainforge-core/src/authority/resolver.rs +446 -0
- package/domainforge-core/src/authority/trace.rs +217 -0
- package/domainforge-core/src/authority/transform.rs +168 -0
- package/domainforge-core/src/authority/types.rs +617 -0
- package/domainforge-core/src/bin/domainforge.rs +25 -0
- package/domainforge-core/src/calm/export.rs +538 -0
- package/domainforge-core/src/calm/import.rs +1220 -0
- package/domainforge-core/src/calm/mod.rs +9 -0
- package/domainforge-core/src/calm/models.rs +108 -0
- package/domainforge-core/src/calm/sbvr_import.rs +9 -0
- package/domainforge-core/src/cli/authority.rs +149 -0
- package/domainforge-core/src/cli/format.rs +85 -0
- package/domainforge-core/src/cli/import.rs +133 -0
- package/domainforge-core/src/cli/mod.rs +64 -0
- package/domainforge-core/src/cli/normalize.rs +180 -0
- package/domainforge-core/src/cli/pack.rs +904 -0
- package/domainforge-core/src/cli/parse.rs +112 -0
- package/domainforge-core/src/cli/project.rs +294 -0
- package/domainforge-core/src/cli/registry.rs +41 -0
- package/domainforge-core/src/cli/test.rs +12 -0
- package/domainforge-core/src/cli/validate.rs +195 -0
- package/domainforge-core/src/cli/validate_kg.rs +80 -0
- package/domainforge-core/src/concept_id.rs +89 -0
- package/domainforge-core/src/error/diagnostics.rs +426 -0
- package/domainforge-core/src/error/fuzzy.rs +253 -0
- package/domainforge-core/src/error/mod.rs +13 -0
- package/domainforge-core/src/formatter/comments.rs +223 -0
- package/domainforge-core/src/formatter/config.rs +114 -0
- package/domainforge-core/src/formatter/mod.rs +22 -0
- package/domainforge-core/src/formatter/printer.rs +906 -0
- package/domainforge-core/src/graph/mod.rs +858 -0
- package/domainforge-core/src/graph/to_ast.rs +66 -0
- package/domainforge-core/src/kg.rs +1476 -0
- package/domainforge-core/src/kg_import.rs +251 -0
- package/domainforge-core/src/lib.rs +203 -0
- package/domainforge-core/src/module/mod.rs +1 -0
- package/domainforge-core/src/module/resolver.rs +260 -0
- package/domainforge-core/src/parser/ast.rs +2919 -0
- package/domainforge-core/src/parser/ast_convert.rs +494 -0
- package/domainforge-core/src/parser/ast_schema.rs +491 -0
- package/domainforge-core/src/parser/error.rs +291 -0
- package/domainforge-core/src/parser/lint.rs +39 -0
- package/domainforge-core/src/parser/mod.rs +193 -0
- package/domainforge-core/src/parser/printer.rs +702 -0
- package/domainforge-core/src/parser/profiles.rs +71 -0
- package/domainforge-core/src/parser/string_utils.rs +138 -0
- package/domainforge-core/src/patterns.rs +68 -0
- package/domainforge-core/src/policy/core.rs +1148 -0
- package/domainforge-core/src/policy/expression.rs +399 -0
- package/domainforge-core/src/policy/mod.rs +18 -0
- package/domainforge-core/src/policy/normalize.rs +1028 -0
- package/domainforge-core/src/policy/quantifier.rs +940 -0
- package/domainforge-core/src/policy/three_valued.rs +140 -0
- package/domainforge-core/src/policy/three_valued_microbench.rs +104 -0
- package/domainforge-core/src/policy/type_inference.rs +67 -0
- package/domainforge-core/src/policy/violation.rs +36 -0
- package/domainforge-core/src/primitives/concept_change.rs +61 -0
- package/domainforge-core/src/primitives/entity.rs +224 -0
- package/domainforge-core/src/primitives/flow.rs +111 -0
- package/domainforge-core/src/primitives/instance.rs +93 -0
- package/domainforge-core/src/primitives/mapping_contract.rs +50 -0
- package/domainforge-core/src/primitives/metric.rs +79 -0
- package/domainforge-core/src/primitives/mod.rs +25 -0
- package/domainforge-core/src/primitives/projection_contract.rs +50 -0
- package/domainforge-core/src/primitives/quantity.rs +56 -0
- package/domainforge-core/src/primitives/relation.rs +68 -0
- package/domainforge-core/src/primitives/resource.rs +237 -0
- package/domainforge-core/src/primitives/resource_instance.rs +88 -0
- package/domainforge-core/src/primitives/role.rs +49 -0
- package/domainforge-core/src/projection/buf.rs +404 -0
- package/domainforge-core/src/projection/contracts.rs +22 -0
- package/domainforge-core/src/projection/engine.rs +19 -0
- package/domainforge-core/src/projection/mod.rs +16 -0
- package/domainforge-core/src/projection/protobuf.rs +3331 -0
- package/domainforge-core/src/projection/registry.rs +43 -0
- package/domainforge-core/src/python/authority.rs +253 -0
- package/domainforge-core/src/python/error.rs +227 -0
- package/domainforge-core/src/python/formatter.rs +86 -0
- package/domainforge-core/src/python/graph.rs +366 -0
- package/domainforge-core/src/python/mod.rs +9 -0
- package/domainforge-core/src/python/policy.rs +651 -0
- package/domainforge-core/src/python/primitives.rs +796 -0
- package/domainforge-core/src/python/registry.rs +98 -0
- package/domainforge-core/src/python/semantic_pack.rs +619 -0
- package/domainforge-core/src/python/units.rs +96 -0
- package/domainforge-core/src/registry/mod.rs +432 -0
- package/domainforge-core/src/registry/tests.rs +210 -0
- package/domainforge-core/src/sbvr.rs +744 -0
- package/domainforge-core/src/semantic_pack/builder.rs +470 -0
- package/domainforge-core/src/semantic_pack/canonical_json.rs +184 -0
- package/domainforge-core/src/semantic_pack/diagnostics.rs +214 -0
- package/domainforge-core/src/semantic_pack/diff.rs +216 -0
- package/domainforge-core/src/semantic_pack/mod.rs +31 -0
- package/domainforge-core/src/semantic_pack/pack_set.rs +240 -0
- package/domainforge-core/src/semantic_pack/resolver.rs +437 -0
- package/domainforge-core/src/semantic_pack/review.rs +125 -0
- package/domainforge-core/src/semantic_pack/schema.rs +342 -0
- package/domainforge-core/src/semantic_pack/signing.rs +105 -0
- package/domainforge-core/src/semantic_pack/validator.rs +368 -0
- package/domainforge-core/src/semantic_version.rs +140 -0
- package/domainforge-core/src/test_utils.rs +12 -0
- package/domainforge-core/src/typescript/authority.rs +184 -0
- package/domainforge-core/src/typescript/error.rs +146 -0
- package/domainforge-core/src/typescript/formatter.rs +76 -0
- package/domainforge-core/src/typescript/graph.rs +391 -0
- package/domainforge-core/src/typescript/mod.rs +9 -0
- package/domainforge-core/src/typescript/policy.rs +564 -0
- package/domainforge-core/src/typescript/primitives.rs +784 -0
- package/domainforge-core/src/typescript/registry.rs +88 -0
- package/domainforge-core/src/typescript/semantic_pack.rs +470 -0
- package/domainforge-core/src/typescript/units.rs +76 -0
- package/domainforge-core/src/units/mod.rs +462 -0
- package/domainforge-core/src/uuid_module.rs +42 -0
- package/domainforge-core/src/validation_error.rs +818 -0
- package/domainforge-core/src/validation_result.rs +30 -0
- package/domainforge-core/src/wasm/authority.rs +192 -0
- package/domainforge-core/src/wasm/error.rs +145 -0
- package/domainforge-core/src/wasm/formatter.rs +69 -0
- package/domainforge-core/src/wasm/graph.rs +471 -0
- package/domainforge-core/src/wasm/mod.rs +16 -0
- package/domainforge-core/src/wasm/policy.rs +607 -0
- package/domainforge-core/src/wasm/primitives.rs +295 -0
- package/domainforge-core/src/wasm/semantic_pack.rs +471 -0
- package/domainforge-core/src/wasm/units.rs +62 -0
- package/domainforge-core/std/aws.sea +6 -0
- package/domainforge-core/std/core.sea +6 -0
- package/domainforge-core/std/http.sea +27 -0
- package/domainforge-core/tests/aggregation_enhanced_tests.rs +162 -0
- package/domainforge-core/tests/aggregation_eval_tests.rs +248 -0
- package/domainforge-core/tests/aggregation_integration_tests.rs +379 -0
- package/domainforge-core/tests/aggregation_parser_tests.rs +92 -0
- package/domainforge-core/tests/aggregation_tests.rs +102 -0
- package/domainforge-core/tests/authority_conformance_tests.rs +1173 -0
- package/domainforge-core/tests/calm_round_trip_tests.rs +283 -0
- package/domainforge-core/tests/calm_schema_validation_tests.rs +137 -0
- package/domainforge-core/tests/cast_operator_tests.rs +85 -0
- package/domainforge-core/tests/cli_binary_check.rs +37 -0
- package/domainforge-core/tests/cli_import_tests.rs +291 -0
- package/domainforge-core/tests/cli_path_traversal_tests.rs +124 -0
- package/domainforge-core/tests/cli_tests.rs +63 -0
- package/domainforge-core/tests/diagnostics_tests.rs +203 -0
- package/domainforge-core/tests/dimension_unit_tests.rs +80 -0
- package/domainforge-core/tests/entity_tests.rs +69 -0
- package/domainforge-core/tests/evolution_semantics_tests.rs +157 -0
- package/domainforge-core/tests/flow_tests.rs +78 -0
- package/domainforge-core/tests/flow_unit_validation_tests.rs +31 -0
- package/domainforge-core/tests/graph_integration_tests.rs +218 -0
- package/domainforge-core/tests/graph_tests.rs +626 -0
- package/domainforge-core/tests/import_parsing_tests.rs +23 -0
- package/domainforge-core/tests/instance_integration_tests.rs +98 -0
- package/domainforge-core/tests/instance_parsing_tests.rs +58 -0
- package/domainforge-core/tests/instance_tests.rs +61 -0
- package/domainforge-core/tests/kg_uri_encoding_tests.rs +53 -0
- package/domainforge-core/tests/lint_tests.rs +19 -0
- package/domainforge-core/tests/metric_tests.rs +143 -0
- package/domainforge-core/tests/module_resolution_tests.rs +100 -0
- package/domainforge-core/tests/namespace_registry_tests.rs +247 -0
- package/domainforge-core/tests/null_handling_tests.rs +26 -0
- package/domainforge-core/tests/parser_ast_v3.rs +53 -0
- package/domainforge-core/tests/parser_dimension_registry_tests.rs +20 -0
- package/domainforge-core/tests/parser_integration_tests.rs +294 -0
- package/domainforge-core/tests/parser_metadata_tests.rs +97 -0
- package/domainforge-core/tests/parser_resource_domain_only_graph_test.rs +21 -0
- package/domainforge-core/tests/parser_resource_limits_tests.rs +122 -0
- package/domainforge-core/tests/parser_tests.rs +512 -0
- package/domainforge-core/tests/pattern_semantics_tests.rs +87 -0
- package/domainforge-core/tests/phase_14_determinism_tests.rs +166 -0
- package/domainforge-core/tests/phase_15_validation_error_tests.rs +136 -0
- package/domainforge-core/tests/phase_16_unicode_tests.rs +248 -0
- package/domainforge-core/tests/phase_17_export_tests.rs +285 -0
- package/domainforge-core/tests/phase_17_round_trip_tests.rs +264 -0
- package/domainforge-core/tests/policy_tests.rs +635 -0
- package/domainforge-core/tests/primitives_integration_tests.rs +151 -0
- package/domainforge-core/tests/print_rdf_xml.rs +14 -0
- package/domainforge-core/tests/printer_tests.rs +204 -0
- package/domainforge-core/tests/profile_tests.rs +35 -0
- package/domainforge-core/tests/projection_contracts_tests.rs +154 -0
- package/domainforge-core/tests/protobuf_projection_tests.rs +199 -0
- package/domainforge-core/tests/quantity_tests.rs +41 -0
- package/domainforge-core/tests/rdf_xml_typed_literal_tests.rs +105 -0
- package/domainforge-core/tests/registry_schema_tests.rs +33 -0
- package/domainforge-core/tests/resource_tests.rs +50 -0
- package/domainforge-core/tests/resource_unit_tests.rs +24 -0
- package/domainforge-core/tests/roles_relations_tests.rs +61 -0
- package/domainforge-core/tests/round_trip_tests.rs +34 -0
- package/domainforge-core/tests/runtime_toggle_tests.rs +70 -0
- package/domainforge-core/tests/sbvr_fact_schema_tests.rs +60 -0
- package/domainforge-core/tests/sbvr_flow_facts_tests.rs +55 -0
- package/domainforge-core/tests/sbvr_parsing_tests.rs +53 -0
- package/domainforge-core/tests/semantic_pack_alias_resolution.rs +197 -0
- package/domainforge-core/tests/semantic_pack_build.rs +302 -0
- package/domainforge-core/tests/semantic_pack_consumer_smoke.rs +150 -0
- package/domainforge-core/tests/semantic_pack_pack_set.rs +160 -0
- package/domainforge-core/tests/semantic_pack_signing.rs +157 -0
- package/domainforge-core/tests/semantic_pack_three_valued.rs +250 -0
- package/domainforge-core/tests/semantic_pack_validate.rs +196 -0
- package/domainforge-core/tests/std_lib_tests.rs +37 -0
- package/domainforge-core/tests/temporal_evaluation_tests.rs +159 -0
- package/domainforge-core/tests/temporal_semantics_tests.rs +214 -0
- package/domainforge-core/tests/three_valued_quantifiers_tests.rs +164 -0
- package/domainforge-core/tests/turtle_entity_export_tests.rs +38 -0
- package/domainforge-core/tests/turtle_escaping_tests.rs +53 -0
- package/domainforge-core/tests/turtle_resource_export_tests.rs +34 -0
- package/domainforge-core/tests/type_inference_tests.rs +40 -0
- package/domainforge-core/tests/unicode_validation_tests.rs +169 -0
- package/domainforge-core/tests/unit_tests.rs +81 -0
- package/domainforge-core/tests/validate_tests.rs +38 -0
- package/domainforge-core/tests/validation_unit_mismatch_tests.rs +83 -0
- package/domainforge-core/tests/wasm_tests.rs +229 -0
- package/domainforge-python/CHANGELOG-python.md +12 -0
- package/domainforge-python/MIGRATING.md +24 -0
- package/domainforge-python/README.md +256 -0
- package/domainforge-python/domainforge/__init__.py +95 -0
- package/domainforge-python/domainforge/domainforge.pyi +519 -0
- package/domainforge-python/pyproject.toml +36 -0
- package/domainforge-typescript/CHANGELOG-typescript.md +12 -0
- package/domainforge-typescript/LICENSE +201 -0
- package/domainforge-typescript/MIGRATING.md +24 -0
- package/domainforge-typescript/README.md +305 -0
- package/domainforge-typescript/index.d.ts +452 -0
- package/domainforge-typescript/index.js +361 -0
- package/domainforge-typescript/package.json +60 -0
- package/example.js +61 -0
- package/examples/browser.html +366 -0
- package/examples/namespaces/finance/cashflow.sea +5 -0
- package/examples/namespaces/logistics/core.sea +7 -0
- package/examples/observability_metrics.sea +38 -0
- package/fixtures/semantic_packs/acme_procurement/domain/entities.sea +39 -0
- package/fixtures/semantic_packs/acme_procurement/domain/metrics.sea +11 -0
- package/fixtures/semantic_packs/acme_procurement/domain/relations.sea +7 -0
- package/fixtures/semantic_packs/acme_procurement/domain/resources.sea +9 -0
- package/fixtures/semantic_packs/acme_procurement/review/acme.procurement.semantic-review.jsonl +7 -0
- package/fixtures/semantic_packs/acme_procurement/tests/ambiguous_vendor_alias.sea +8 -0
- package/fixtures/semantic_packs/acme_procurement/tests/deprecated_vendor_alias.sea +8 -0
- package/fixtures/semantic_packs/acme_procurement/tests/invalid_relation.sea +3 -0
- package/fixtures/semantic_packs/acme_procurement/tests/proposed_concept.sea +8 -0
- package/fixtures/semantic_packs/acme_procurement/tests/rejected_concept.sea +8 -0
- package/fixtures/semantic_packs/acme_procurement/tests/unit_mismatch.sea +7 -0
- package/fixtures/semantic_packs/acme_procurement/tests/unknown_vendor_policy.sea +8 -0
- package/fixtures/semantic_packs/acme_procurement/tests/valid_purchase_policy.sea +8 -0
- package/index.d.ts +2 -0
- package/index.js +8 -0
- package/justfile +200 -0
- package/lefthook.yml +13 -0
- package/lib/validate_native_exports.d.ts +4 -0
- package/lib/validate_native_exports.js +12 -0
- package/package.json +22 -0
- package/pytest.ini +5 -0
- package/python/tests/test_registry.py +75 -0
- package/python/tests/test_units.py +18 -0
- package/release-please-config.json +49 -0
- package/requirements-dev.txt +3 -0
- package/requirements.txt +3 -0
- package/rust-toolchain.toml +3 -0
- package/schemas/ast-v1.schema.json +72 -0
- package/schemas/ast-v2.schema.json +1200 -0
- package/schemas/ast-v3.schema.json +1200 -0
- package/schemas/sea-registry.schema.json +45 -0
- package/scripts/build-python.sh +37 -0
- package/scripts/build-release.sh +279 -0
- package/scripts/build-typescript.sh +13 -0
- package/scripts/build-wasm.sh +113 -0
- package/scripts/bump-version.sh +245 -0
- package/scripts/check_unused_test_imports.py +85 -0
- package/scripts/ci_tasks.py +379 -0
- package/scripts/clear_debug_test.sh +10 -0
- package/scripts/create-github-release.sh +262 -0
- package/scripts/create-tag.sh +203 -0
- package/scripts/find_and_link_test_binary.sh +70 -0
- package/scripts/generate-changelog.sh +271 -0
- package/scripts/generate-release-notes.sh +205 -0
- package/scripts/lint_release_security.py +96 -0
- package/scripts/lint_release_workflows.py +82 -0
- package/scripts/lint_workflow_gates.py +113 -0
- package/scripts/optimized-wasm-build.sh +61 -0
- package/scripts/patch_napi_types.py +62 -0
- package/scripts/pre-release-check.sh +289 -0
- package/scripts/prepare_rust_debug.sh +52 -0
- package/scripts/release.sh +373 -0
- package/scripts/resolve_rust_binary.py +230 -0
- package/scripts/run_commitlint.sh +29 -0
- package/scripts/test-all.sh +77 -0
- package/scripts/update_launch_program.py +93 -0
- package/secrets/README.md +27 -0
- package/secrets/secrets.yaml +21 -0
- package/test_integration.py +67 -0
- package/tests/test_authority.py +328 -0
- package/tests/test_ci_tasks.py +143 -0
- package/tests/test_expression.py +256 -0
- package/tests/test_golden_payment_flow.py +42 -0
- package/tests/test_graph.py +127 -0
- package/tests/test_instance.py +136 -0
- package/tests/test_parser.py +82 -0
- package/tests/test_primitives.py +68 -0
- package/tests/test_role_relation_parity.py +56 -0
- package/tests/test_runtime_toggle.py +156 -0
- package/tests/test_semantic_pack.py +639 -0
- package/tests/test_three_valued_eval.py +159 -0
- package/tsconfig.json +30 -0
- package/typescript-tests/advanced.test.ts +165 -0
- package/typescript-tests/authority.test.ts +216 -0
- package/typescript-tests/expression.test.ts +228 -0
- package/typescript-tests/golden-payment-flow.test.ts +51 -0
- package/typescript-tests/graph.test.ts +142 -0
- package/typescript-tests/native-binding.test.ts +20 -0
- package/typescript-tests/primitives.test.ts +88 -0
- package/typescript-tests/registry.test.ts +122 -0
- package/typescript-tests/role_relation.test.ts +63 -0
- package/typescript-tests/runtime_toggle.test.ts +141 -0
- package/typescript-tests/semantic-pack.test.ts +556 -0
- package/typescript-tests/three_valued_eval.test.ts +135 -0
- package/typescript-tests/units.test.ts +36 -0
- package/vitest.config.ts +13 -0
- package/wasm_demo.html +225 -0
|
@@ -0,0 +1,639 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for the new Semantic Pack API exports added in this PR.
|
|
3
|
+
|
|
4
|
+
Covers:
|
|
5
|
+
- Enum exports: SemanticTruth, DiagnosticSeverity, ValidationMode, ApprovalState,
|
|
6
|
+
SignatureState, ConceptStatus, ConceptKind, AliasStatus, SemanticValidationStatus
|
|
7
|
+
- Functions: normalize_lookup_key, build_semantic_pack, validate_semantic_pack,
|
|
8
|
+
validate_graph_with_pack, compute_pack_hash, diff_packs, resolve_concept,
|
|
9
|
+
sign_pack, verify_pack_signature
|
|
10
|
+
- Classes: SemanticPack, SemanticValidationResult
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import pytest
|
|
15
|
+
import domainforge
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
# Helpers
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
def make_minimal_pack_json() -> str:
|
|
23
|
+
return json.dumps({
|
|
24
|
+
"schema_version": "0.3",
|
|
25
|
+
"pack_id": "test-org/test-domain/1.0.0",
|
|
26
|
+
"org_id": "test-org",
|
|
27
|
+
"domain_id": "test-domain",
|
|
28
|
+
"pack_version": "1.0.0",
|
|
29
|
+
"meaning_version": "1.0.0",
|
|
30
|
+
"meaning_fingerprint": "",
|
|
31
|
+
"source_graph_hash": "sha256:test",
|
|
32
|
+
"build_config_hash": "sha256:cfg",
|
|
33
|
+
"review_manifest_hash": "sha256:rev",
|
|
34
|
+
"created_at": "2026-06-07T00:00:00Z",
|
|
35
|
+
"generator": {"name": "domainforge-core", "version": "0.3"},
|
|
36
|
+
"trust": {"approval_state": "candidate", "signature_state": "unsigned"},
|
|
37
|
+
"concepts": [
|
|
38
|
+
{
|
|
39
|
+
"id": "supplier",
|
|
40
|
+
"canonical_name": "Supplier",
|
|
41
|
+
"kind": "entity",
|
|
42
|
+
"status": "active",
|
|
43
|
+
"definition": {
|
|
44
|
+
"text": "A party that provides goods or services.",
|
|
45
|
+
"definition_hash": "",
|
|
46
|
+
"decision_ref": "dec_supplier",
|
|
47
|
+
},
|
|
48
|
+
"owner": "owner@test.com",
|
|
49
|
+
"source_refs": [],
|
|
50
|
+
"examples": [],
|
|
51
|
+
"counterexamples": [],
|
|
52
|
+
"allowed_predicates": [],
|
|
53
|
+
"valid_contexts": [],
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"relations": [],
|
|
57
|
+
"metrics": [],
|
|
58
|
+
"dimensions": [],
|
|
59
|
+
"units": [],
|
|
60
|
+
"aliases": [],
|
|
61
|
+
"mapping_rules": [],
|
|
62
|
+
"compatibility": {},
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def make_minimal_build_input_json() -> str:
|
|
67
|
+
return json.dumps({
|
|
68
|
+
"org_id": "test-org",
|
|
69
|
+
"domain_id": "test-domain",
|
|
70
|
+
"pack_version": "1.0.0",
|
|
71
|
+
"meaning_version": "1.0.0",
|
|
72
|
+
"approval": "candidate",
|
|
73
|
+
"concepts": [
|
|
74
|
+
{
|
|
75
|
+
"id": "supplier",
|
|
76
|
+
"canonical_name": "Supplier",
|
|
77
|
+
"kind": "entity",
|
|
78
|
+
"status": "active",
|
|
79
|
+
"definition": {
|
|
80
|
+
"text": "A party that provides goods or services.",
|
|
81
|
+
"definition_hash": "",
|
|
82
|
+
"decision_ref": "dec_supplier",
|
|
83
|
+
},
|
|
84
|
+
"owner": "owner@test.com",
|
|
85
|
+
"source_refs": [],
|
|
86
|
+
"examples": [],
|
|
87
|
+
"counterexamples": [],
|
|
88
|
+
"allowed_predicates": [],
|
|
89
|
+
"valid_contexts": [],
|
|
90
|
+
}
|
|
91
|
+
],
|
|
92
|
+
"relations": [],
|
|
93
|
+
"metrics": [],
|
|
94
|
+
"dimensions": [],
|
|
95
|
+
"units": [],
|
|
96
|
+
"aliases": [],
|
|
97
|
+
"mapping_rules": [],
|
|
98
|
+
"review_records": [],
|
|
99
|
+
"previous_pack": None,
|
|
100
|
+
"allow_first_approved_version": False,
|
|
101
|
+
"source_graph_hash": "sha256:test",
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def make_default_options_json() -> str:
|
|
106
|
+
return json.dumps({"mode": "warn", "deprecated_policy": "warn"})
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# ---------------------------------------------------------------------------
|
|
110
|
+
# Enum import tests
|
|
111
|
+
# ---------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
def test_semantic_truth_enum_importable():
|
|
114
|
+
"""SemanticTruth enum is importable from domainforge."""
|
|
115
|
+
assert hasattr(domainforge, "SemanticTruth")
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def test_semantic_truth_enum_values():
|
|
119
|
+
"""SemanticTruth has Valid, Invalid, Unknown members."""
|
|
120
|
+
assert hasattr(domainforge.SemanticTruth, "Valid")
|
|
121
|
+
assert hasattr(domainforge.SemanticTruth, "Invalid")
|
|
122
|
+
assert hasattr(domainforge.SemanticTruth, "Unknown")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_semantic_truth_equality():
|
|
126
|
+
"""SemanticTruth enum members are equal to themselves."""
|
|
127
|
+
assert domainforge.SemanticTruth.Valid == domainforge.SemanticTruth.Valid
|
|
128
|
+
assert domainforge.SemanticTruth.Invalid != domainforge.SemanticTruth.Unknown
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_diagnostic_severity_enum_importable():
|
|
132
|
+
"""DiagnosticSeverity enum is importable from domainforge."""
|
|
133
|
+
assert hasattr(domainforge, "DiagnosticSeverity")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def test_diagnostic_severity_enum_values():
|
|
137
|
+
"""DiagnosticSeverity has Error, Warning, Info, Hint members."""
|
|
138
|
+
assert hasattr(domainforge.DiagnosticSeverity, "Error")
|
|
139
|
+
assert hasattr(domainforge.DiagnosticSeverity, "Warning")
|
|
140
|
+
assert hasattr(domainforge.DiagnosticSeverity, "Info")
|
|
141
|
+
assert hasattr(domainforge.DiagnosticSeverity, "Hint")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def test_validation_mode_enum_importable():
|
|
145
|
+
"""ValidationMode enum is importable from domainforge."""
|
|
146
|
+
assert hasattr(domainforge, "ValidationMode")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def test_validation_mode_enum_values():
|
|
150
|
+
"""ValidationMode has Off, Warn, Strict members."""
|
|
151
|
+
assert hasattr(domainforge.ValidationMode, "Off")
|
|
152
|
+
assert hasattr(domainforge.ValidationMode, "Warn")
|
|
153
|
+
assert hasattr(domainforge.ValidationMode, "Strict")
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_approval_state_enum_values():
|
|
157
|
+
"""ApprovalState has Candidate, Approved, Rejected members."""
|
|
158
|
+
assert hasattr(domainforge.ApprovalState, "Candidate")
|
|
159
|
+
assert hasattr(domainforge.ApprovalState, "Approved")
|
|
160
|
+
assert hasattr(domainforge.ApprovalState, "Rejected")
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def test_signature_state_enum_values():
|
|
164
|
+
"""SignatureState has Unsigned, Signed, InvalidSignature members."""
|
|
165
|
+
assert hasattr(domainforge.SignatureState, "Unsigned")
|
|
166
|
+
assert hasattr(domainforge.SignatureState, "Signed")
|
|
167
|
+
assert hasattr(domainforge.SignatureState, "InvalidSignature")
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def test_concept_status_enum_values():
|
|
171
|
+
"""ConceptStatus has all five status values."""
|
|
172
|
+
assert hasattr(domainforge.ConceptStatus, "Active")
|
|
173
|
+
assert hasattr(domainforge.ConceptStatus, "Proposed")
|
|
174
|
+
assert hasattr(domainforge.ConceptStatus, "Deprecated")
|
|
175
|
+
assert hasattr(domainforge.ConceptStatus, "Rejected")
|
|
176
|
+
assert hasattr(domainforge.ConceptStatus, "ExternalOnly")
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def test_concept_kind_enum_values():
|
|
180
|
+
"""ConceptKind has all nine kind values."""
|
|
181
|
+
for kind in ["Entity", "Resource", "Role", "Flow", "Policy",
|
|
182
|
+
"Metric", "Dimension", "Unit", "External"]:
|
|
183
|
+
assert hasattr(domainforge.ConceptKind, kind), f"Missing ConceptKind.{kind}"
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def test_alias_status_enum_values():
|
|
187
|
+
"""AliasStatus has Approved, Deprecated, Ambiguous, Blocked members."""
|
|
188
|
+
assert hasattr(domainforge.AliasStatus, "Approved")
|
|
189
|
+
assert hasattr(domainforge.AliasStatus, "Deprecated")
|
|
190
|
+
assert hasattr(domainforge.AliasStatus, "Ambiguous")
|
|
191
|
+
assert hasattr(domainforge.AliasStatus, "Blocked")
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def test_semantic_validation_status_enum_values():
|
|
195
|
+
"""SemanticValidationStatus has Passed, Failed, Unknown, Blocked members."""
|
|
196
|
+
assert hasattr(domainforge.SemanticValidationStatus, "Passed")
|
|
197
|
+
assert hasattr(domainforge.SemanticValidationStatus, "Failed")
|
|
198
|
+
assert hasattr(domainforge.SemanticValidationStatus, "Unknown")
|
|
199
|
+
assert hasattr(domainforge.SemanticValidationStatus, "Blocked")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def test_enum_members_are_distinct():
|
|
203
|
+
"""Different enum members are not equal to each other."""
|
|
204
|
+
assert domainforge.SemanticTruth.Valid != domainforge.SemanticTruth.Invalid
|
|
205
|
+
assert domainforge.ValidationMode.Off != domainforge.ValidationMode.Strict
|
|
206
|
+
assert domainforge.ApprovalState.Candidate != domainforge.ApprovalState.Approved
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# ---------------------------------------------------------------------------
|
|
210
|
+
# normalize_lookup_key
|
|
211
|
+
# ---------------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
def test_normalize_lookup_key_is_callable():
|
|
214
|
+
"""normalize_lookup_key is a callable function in domainforge."""
|
|
215
|
+
assert callable(domainforge.normalize_lookup_key)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def test_normalize_lookup_key_lowercases():
|
|
219
|
+
"""normalize_lookup_key lowercases the input."""
|
|
220
|
+
result = domainforge.normalize_lookup_key("Supplier")
|
|
221
|
+
assert result == "supplier"
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def test_normalize_lookup_key_trims_and_collapses_spaces():
|
|
225
|
+
"""normalize_lookup_key trims and collapses multiple spaces."""
|
|
226
|
+
result = domainforge.normalize_lookup_key(" Hello World ")
|
|
227
|
+
assert result == "hello world"
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def test_normalize_lookup_key_empty_string():
|
|
231
|
+
"""normalize_lookup_key handles empty string input."""
|
|
232
|
+
result = domainforge.normalize_lookup_key("")
|
|
233
|
+
assert result == ""
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def test_normalize_lookup_key_single_word():
|
|
237
|
+
"""normalize_lookup_key handles single word input."""
|
|
238
|
+
assert domainforge.normalize_lookup_key("Warehouse") == "warehouse"
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def test_normalize_lookup_key_is_idempotent():
|
|
242
|
+
"""normalize_lookup_key is idempotent."""
|
|
243
|
+
first = domainforge.normalize_lookup_key(" Purchase Order ")
|
|
244
|
+
second = domainforge.normalize_lookup_key(first)
|
|
245
|
+
assert first == second
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def test_normalize_lookup_key_preserves_underscores():
|
|
249
|
+
"""normalize_lookup_key passes through underscores."""
|
|
250
|
+
result = domainforge.normalize_lookup_key("PURCHASE_ORDER")
|
|
251
|
+
assert result == "purchase_order"
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
# ---------------------------------------------------------------------------
|
|
255
|
+
# build_semantic_pack
|
|
256
|
+
# ---------------------------------------------------------------------------
|
|
257
|
+
|
|
258
|
+
def test_build_semantic_pack_is_callable():
|
|
259
|
+
"""build_semantic_pack is a callable function in domainforge."""
|
|
260
|
+
assert callable(domainforge.build_semantic_pack)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def test_build_semantic_pack_returns_tuple():
|
|
264
|
+
"""build_semantic_pack returns a tuple of (pack_json, errors)."""
|
|
265
|
+
result = domainforge.build_semantic_pack(make_minimal_build_input_json())
|
|
266
|
+
assert isinstance(result, tuple)
|
|
267
|
+
assert len(result) == 2
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def test_build_semantic_pack_returns_valid_json():
|
|
271
|
+
"""build_semantic_pack returns a valid JSON pack string."""
|
|
272
|
+
pack_json, errors = domainforge.build_semantic_pack(make_minimal_build_input_json())
|
|
273
|
+
parsed = json.loads(pack_json)
|
|
274
|
+
assert parsed["org_id"] == "test-org"
|
|
275
|
+
assert parsed["domain_id"] == "test-domain"
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def test_build_semantic_pack_schema_version():
|
|
279
|
+
"""Built pack has schema_version 0.3."""
|
|
280
|
+
pack_json, _ = domainforge.build_semantic_pack(make_minimal_build_input_json())
|
|
281
|
+
pack = json.loads(pack_json)
|
|
282
|
+
assert pack["schema_version"] == "0.3"
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def test_build_semantic_pack_approval_state():
|
|
286
|
+
"""Built candidate pack has approval_state=candidate."""
|
|
287
|
+
pack_json, _ = domainforge.build_semantic_pack(make_minimal_build_input_json())
|
|
288
|
+
pack = json.loads(pack_json)
|
|
289
|
+
assert pack["trust"]["approval_state"] == "candidate"
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def test_build_semantic_pack_errors_is_list():
|
|
293
|
+
"""build_semantic_pack errors is a list."""
|
|
294
|
+
_, errors = domainforge.build_semantic_pack(make_minimal_build_input_json())
|
|
295
|
+
assert isinstance(errors, list)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def test_build_semantic_pack_raises_on_invalid_json():
|
|
299
|
+
"""build_semantic_pack raises ValueError on invalid JSON."""
|
|
300
|
+
with pytest.raises((ValueError, Exception)):
|
|
301
|
+
domainforge.build_semantic_pack("not valid json")
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def test_build_semantic_pack_is_deterministic():
|
|
305
|
+
"""Two builds from identical inputs produce the same pack content hash."""
|
|
306
|
+
input_json = make_minimal_build_input_json()
|
|
307
|
+
pack1, _ = domainforge.build_semantic_pack(input_json)
|
|
308
|
+
pack2, _ = domainforge.build_semantic_pack(input_json)
|
|
309
|
+
p1 = json.loads(pack1)
|
|
310
|
+
p2 = json.loads(pack2)
|
|
311
|
+
# The meaning fingerprint should be identical
|
|
312
|
+
assert p1["meaning_fingerprint"] == p2["meaning_fingerprint"]
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
# ---------------------------------------------------------------------------
|
|
316
|
+
# validate_semantic_pack
|
|
317
|
+
# ---------------------------------------------------------------------------
|
|
318
|
+
|
|
319
|
+
def test_validate_semantic_pack_is_callable():
|
|
320
|
+
"""validate_semantic_pack is a callable function in domainforge."""
|
|
321
|
+
assert callable(domainforge.validate_semantic_pack)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def test_validate_semantic_pack_returns_list():
|
|
325
|
+
"""validate_semantic_pack returns a list of diagnostic strings."""
|
|
326
|
+
result = domainforge.validate_semantic_pack(make_minimal_pack_json())
|
|
327
|
+
assert isinstance(result, list)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def test_validate_semantic_pack_raises_on_invalid_json():
|
|
331
|
+
"""validate_semantic_pack raises on invalid JSON."""
|
|
332
|
+
with pytest.raises((ValueError, Exception)):
|
|
333
|
+
domainforge.validate_semantic_pack("not json")
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def test_validate_semantic_pack_reports_schema_mismatch():
|
|
337
|
+
"""validate_semantic_pack reports errors for wrong schema version."""
|
|
338
|
+
pack = json.loads(make_minimal_pack_json())
|
|
339
|
+
pack["schema_version"] = "9.9"
|
|
340
|
+
diagnostics = domainforge.validate_semantic_pack(json.dumps(pack))
|
|
341
|
+
assert len(diagnostics) > 0
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
# ---------------------------------------------------------------------------
|
|
345
|
+
# compute_pack_hash
|
|
346
|
+
# ---------------------------------------------------------------------------
|
|
347
|
+
|
|
348
|
+
def test_compute_pack_hash_is_callable():
|
|
349
|
+
"""compute_pack_hash is a callable function in domainforge."""
|
|
350
|
+
assert callable(domainforge.compute_pack_hash)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def test_compute_pack_hash_returns_sha256_string():
|
|
354
|
+
"""compute_pack_hash returns a string starting with sha256:."""
|
|
355
|
+
result = domainforge.compute_pack_hash(make_minimal_pack_json())
|
|
356
|
+
assert isinstance(result, str)
|
|
357
|
+
assert result.startswith("sha256:")
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def test_compute_pack_hash_is_consistent():
|
|
361
|
+
"""compute_pack_hash returns the same hash for the same pack."""
|
|
362
|
+
pack_json = make_minimal_pack_json()
|
|
363
|
+
h1 = domainforge.compute_pack_hash(pack_json)
|
|
364
|
+
h2 = domainforge.compute_pack_hash(pack_json)
|
|
365
|
+
assert h1 == h2
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def test_compute_pack_hash_raises_on_invalid_json():
|
|
369
|
+
"""compute_pack_hash raises on invalid JSON."""
|
|
370
|
+
with pytest.raises((ValueError, Exception)):
|
|
371
|
+
domainforge.compute_pack_hash("not json")
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def test_compute_pack_hash_excludes_signature_fields():
|
|
375
|
+
"""compute_pack_hash is stable regardless of signature fields."""
|
|
376
|
+
pack1 = json.loads(make_minimal_pack_json())
|
|
377
|
+
h1 = domainforge.compute_pack_hash(json.dumps(pack1))
|
|
378
|
+
|
|
379
|
+
# Add a signature field — the hash should remain unchanged
|
|
380
|
+
pack1["trust"]["signature"] = "some-base64-signature"
|
|
381
|
+
pack1["trust"]["signature_state"] = "signed"
|
|
382
|
+
h2 = domainforge.compute_pack_hash(json.dumps(pack1))
|
|
383
|
+
|
|
384
|
+
assert h1 == h2
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
# ---------------------------------------------------------------------------
|
|
388
|
+
# validate_graph_with_pack
|
|
389
|
+
# ---------------------------------------------------------------------------
|
|
390
|
+
|
|
391
|
+
def test_validate_graph_with_pack_is_callable():
|
|
392
|
+
"""validate_graph_with_pack is a callable function in domainforge."""
|
|
393
|
+
assert callable(domainforge.validate_graph_with_pack)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def test_validate_graph_with_pack_returns_json_string():
|
|
397
|
+
"""validate_graph_with_pack returns a parseable JSON string."""
|
|
398
|
+
result = domainforge.validate_graph_with_pack(
|
|
399
|
+
make_minimal_pack_json(),
|
|
400
|
+
"test://source",
|
|
401
|
+
make_default_options_json(),
|
|
402
|
+
)
|
|
403
|
+
assert isinstance(result, str)
|
|
404
|
+
parsed = json.loads(result)
|
|
405
|
+
assert "status" in parsed
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def test_validate_graph_with_pack_raises_on_invalid_pack_json():
|
|
409
|
+
"""validate_graph_with_pack raises on invalid pack JSON."""
|
|
410
|
+
with pytest.raises((ValueError, Exception)):
|
|
411
|
+
domainforge.validate_graph_with_pack("bad json", "test://source", make_default_options_json())
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def test_validate_graph_with_pack_raises_on_invalid_options_json():
|
|
415
|
+
"""validate_graph_with_pack raises on invalid options JSON."""
|
|
416
|
+
with pytest.raises((ValueError, Exception)):
|
|
417
|
+
domainforge.validate_graph_with_pack(make_minimal_pack_json(), "test://source", "bad options")
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
# ---------------------------------------------------------------------------
|
|
421
|
+
# diff_packs
|
|
422
|
+
# ---------------------------------------------------------------------------
|
|
423
|
+
|
|
424
|
+
def test_diff_packs_is_callable():
|
|
425
|
+
"""diff_packs is a callable function in domainforge."""
|
|
426
|
+
assert callable(domainforge.diff_packs)
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
def test_diff_packs_returns_json_string():
|
|
430
|
+
"""diff_packs returns a parseable JSON string."""
|
|
431
|
+
pack_json = make_minimal_pack_json()
|
|
432
|
+
result = domainforge.diff_packs(pack_json, pack_json)
|
|
433
|
+
assert isinstance(result, str)
|
|
434
|
+
json.loads(result) # must parse without error
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def test_diff_packs_same_pack_has_no_breaking_changes():
|
|
438
|
+
"""diff_packs reports no breaking changes when comparing a pack to itself."""
|
|
439
|
+
pack_json = make_minimal_pack_json()
|
|
440
|
+
diff = json.loads(domainforge.diff_packs(pack_json, pack_json))
|
|
441
|
+
entries = diff.get("entries", diff) if isinstance(diff, dict) else diff
|
|
442
|
+
if isinstance(entries, list):
|
|
443
|
+
breaking = [e for e in entries if e.get("classification") == "breaking"]
|
|
444
|
+
assert len(breaking) == 0
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def test_diff_packs_detects_added_concept():
|
|
448
|
+
"""diff_packs detects a new concept added to the new pack."""
|
|
449
|
+
old_pack = json.loads(make_minimal_pack_json())
|
|
450
|
+
new_pack = json.loads(make_minimal_pack_json())
|
|
451
|
+
new_pack["concepts"].append({
|
|
452
|
+
"id": "warehouse",
|
|
453
|
+
"canonical_name": "Warehouse",
|
|
454
|
+
"kind": "entity",
|
|
455
|
+
"status": "active",
|
|
456
|
+
"definition": {
|
|
457
|
+
"text": "A storage facility.",
|
|
458
|
+
"definition_hash": "",
|
|
459
|
+
"decision_ref": "dec_warehouse",
|
|
460
|
+
},
|
|
461
|
+
"owner": "owner@test.com",
|
|
462
|
+
"source_refs": [],
|
|
463
|
+
"examples": [],
|
|
464
|
+
"counterexamples": [],
|
|
465
|
+
"allowed_predicates": [],
|
|
466
|
+
"valid_contexts": [],
|
|
467
|
+
})
|
|
468
|
+
diff_str = domainforge.diff_packs(json.dumps(old_pack), json.dumps(new_pack))
|
|
469
|
+
diff = json.loads(diff_str)
|
|
470
|
+
entries = diff.get("entries", diff) if isinstance(diff, dict) else diff
|
|
471
|
+
if isinstance(entries, list):
|
|
472
|
+
additive = [e for e in entries if e.get("classification") in ("additive", "add")]
|
|
473
|
+
assert len(additive) > 0
|
|
474
|
+
else:
|
|
475
|
+
assert diff_str # at minimum, a non-empty response
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def test_diff_packs_raises_on_invalid_old_json():
|
|
479
|
+
"""diff_packs raises on invalid old pack JSON."""
|
|
480
|
+
with pytest.raises((ValueError, Exception)):
|
|
481
|
+
domainforge.diff_packs("bad json", make_minimal_pack_json())
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def test_diff_packs_raises_on_invalid_new_json():
|
|
485
|
+
"""diff_packs raises on invalid new pack JSON."""
|
|
486
|
+
with pytest.raises((ValueError, Exception)):
|
|
487
|
+
domainforge.diff_packs(make_minimal_pack_json(), "bad json")
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
# ---------------------------------------------------------------------------
|
|
491
|
+
# resolve_concept
|
|
492
|
+
# ---------------------------------------------------------------------------
|
|
493
|
+
|
|
494
|
+
def test_resolve_concept_is_callable():
|
|
495
|
+
"""resolve_concept is a callable function in domainforge."""
|
|
496
|
+
assert callable(domainforge.resolve_concept)
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def test_resolve_concept_returns_json_string():
|
|
500
|
+
"""resolve_concept returns a parseable JSON string."""
|
|
501
|
+
result = domainforge.resolve_concept("Supplier", make_minimal_pack_json(), make_default_options_json())
|
|
502
|
+
assert isinstance(result, str)
|
|
503
|
+
parsed = json.loads(result)
|
|
504
|
+
assert "semantic_truth" in parsed
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
def test_resolve_concept_known_term_is_valid():
|
|
508
|
+
"""resolve_concept returns valid semantic_truth for a known active concept."""
|
|
509
|
+
result = domainforge.resolve_concept("Supplier", make_minimal_pack_json(), make_default_options_json())
|
|
510
|
+
parsed = json.loads(result)
|
|
511
|
+
assert "valid" in parsed["semantic_truth"].lower()
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def test_resolve_concept_unknown_term_is_unknown():
|
|
515
|
+
"""resolve_concept returns unknown semantic_truth for an unrecognized term."""
|
|
516
|
+
result = domainforge.resolve_concept("CompletelyUnknownTerm", make_minimal_pack_json(), make_default_options_json())
|
|
517
|
+
parsed = json.loads(result)
|
|
518
|
+
assert "unknown" in parsed["semantic_truth"].lower()
|
|
519
|
+
assert parsed["resolved_concept_id"] is None
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def test_resolve_concept_normalizes_lookup_key():
|
|
523
|
+
"""resolve_concept normalizes the input term before lookup."""
|
|
524
|
+
r1 = json.loads(domainforge.resolve_concept("Supplier", make_minimal_pack_json(), make_default_options_json()))
|
|
525
|
+
r2 = json.loads(domainforge.resolve_concept(" supplier ", make_minimal_pack_json(), make_default_options_json()))
|
|
526
|
+
assert r1["resolved_concept_id"] == r2["resolved_concept_id"]
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
def test_resolve_concept_raises_on_invalid_pack_json():
|
|
530
|
+
"""resolve_concept raises on invalid pack JSON."""
|
|
531
|
+
with pytest.raises((ValueError, Exception)):
|
|
532
|
+
domainforge.resolve_concept("Supplier", "bad json", make_default_options_json())
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def test_resolve_concept_raises_on_invalid_options_json():
|
|
536
|
+
"""resolve_concept raises on invalid options JSON."""
|
|
537
|
+
with pytest.raises((ValueError, Exception)):
|
|
538
|
+
domainforge.resolve_concept("Supplier", make_minimal_pack_json(), "bad options")
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
# ---------------------------------------------------------------------------
|
|
542
|
+
# SemanticPack class
|
|
543
|
+
# ---------------------------------------------------------------------------
|
|
544
|
+
|
|
545
|
+
def test_semantic_pack_class_importable():
|
|
546
|
+
"""SemanticPack class is importable from domainforge."""
|
|
547
|
+
assert hasattr(domainforge, "SemanticPack")
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
def test_semantic_pack_from_json():
|
|
551
|
+
"""SemanticPack.from_json parses a valid pack JSON string."""
|
|
552
|
+
pack = domainforge.SemanticPack.from_json(make_minimal_pack_json())
|
|
553
|
+
assert pack is not None
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
def test_semantic_pack_pack_id():
|
|
557
|
+
"""SemanticPack.pack_id() returns the pack identifier."""
|
|
558
|
+
pack = domainforge.SemanticPack.from_json(make_minimal_pack_json())
|
|
559
|
+
assert pack.pack_id() == "test-org/test-domain/1.0.0"
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def test_semantic_pack_schema_version():
|
|
563
|
+
"""SemanticPack.schema_version() returns '0.3'."""
|
|
564
|
+
pack = domainforge.SemanticPack.from_json(make_minimal_pack_json())
|
|
565
|
+
assert pack.schema_version() == "0.3"
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
def test_semantic_pack_approval_state():
|
|
569
|
+
"""SemanticPack.approval_state() returns ApprovalState.Candidate."""
|
|
570
|
+
pack = domainforge.SemanticPack.from_json(make_minimal_pack_json())
|
|
571
|
+
assert pack.approval_state() == domainforge.ApprovalState.Candidate
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def test_semantic_pack_signature_state():
|
|
575
|
+
"""SemanticPack.signature_state() returns SignatureState.Unsigned."""
|
|
576
|
+
pack = domainforge.SemanticPack.from_json(make_minimal_pack_json())
|
|
577
|
+
assert pack.signature_state() == domainforge.SignatureState.Unsigned
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
def test_semantic_pack_concept_count():
|
|
581
|
+
"""SemanticPack.concept_count() returns 1 for the minimal pack."""
|
|
582
|
+
pack = domainforge.SemanticPack.from_json(make_minimal_pack_json())
|
|
583
|
+
assert pack.concept_count() == 1
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
def test_semantic_pack_alias_count():
|
|
587
|
+
"""SemanticPack.alias_count() returns 0 for the minimal pack with no aliases."""
|
|
588
|
+
pack = domainforge.SemanticPack.from_json(make_minimal_pack_json())
|
|
589
|
+
assert pack.alias_count() == 0
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
def test_semantic_pack_to_json_roundtrip():
|
|
593
|
+
"""SemanticPack.to_json() produces valid JSON that can be re-parsed."""
|
|
594
|
+
pack = domainforge.SemanticPack.from_json(make_minimal_pack_json())
|
|
595
|
+
json_out = pack.to_json()
|
|
596
|
+
reparsed = json.loads(json_out)
|
|
597
|
+
assert reparsed["pack_id"] == "test-org/test-domain/1.0.0"
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def test_semantic_pack_from_json_raises_on_invalid_json():
|
|
601
|
+
"""SemanticPack.from_json raises on invalid JSON."""
|
|
602
|
+
with pytest.raises((ValueError, Exception)):
|
|
603
|
+
domainforge.SemanticPack.from_json("not json")
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
def test_semantic_pack_pack_content_hash_starts_with_sha256():
|
|
607
|
+
"""SemanticPack.pack_content_hash() returns a sha256: prefixed string."""
|
|
608
|
+
pack = domainforge.SemanticPack.from_json(make_minimal_pack_json())
|
|
609
|
+
h = pack.pack_content_hash()
|
|
610
|
+
assert isinstance(h, str)
|
|
611
|
+
assert h.startswith("sha256:")
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
# ---------------------------------------------------------------------------
|
|
615
|
+
# sign_pack / verify_pack_signature
|
|
616
|
+
# ---------------------------------------------------------------------------
|
|
617
|
+
|
|
618
|
+
def test_sign_pack_is_callable():
|
|
619
|
+
"""sign_pack is a callable function in domainforge."""
|
|
620
|
+
assert callable(domainforge.sign_pack)
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
def test_verify_pack_signature_is_callable():
|
|
624
|
+
"""verify_pack_signature is a callable function in domainforge."""
|
|
625
|
+
assert callable(domainforge.verify_pack_signature)
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
def test_sign_pack_raises_on_invalid_pack_json():
|
|
629
|
+
"""sign_pack raises on invalid pack JSON."""
|
|
630
|
+
fake_pem = "-----BEGIN PRIVATE KEY-----\nnot-real\n-----END PRIVATE KEY-----"
|
|
631
|
+
with pytest.raises((ValueError, Exception)):
|
|
632
|
+
domainforge.sign_pack("bad json", fake_pem)
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
def test_verify_pack_signature_raises_on_invalid_pack_json():
|
|
636
|
+
"""verify_pack_signature raises on invalid pack JSON."""
|
|
637
|
+
fake_pem = "-----BEGIN PUBLIC KEY-----\nnot-real\n-----END PUBLIC KEY-----"
|
|
638
|
+
with pytest.raises((ValueError, Exception)):
|
|
639
|
+
domainforge.verify_pack_signature("bad json", fake_pem)
|