diff --git a/Makefile b/Makefile index 71bb240..a984487 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -.PHONY: validate validate-json validate-schemas validate-control-plane validate-eventctl validate-event-store validate-events validate-identity validate-process-provenance validate-policy-normalizer validate-service-graph install-dev +.PHONY: validate validate-json validate-schemas validate-control-plane validate-eventctl validate-event-store validate-events validate-identity validate-process-provenance validate-policy-normalizer validate-service-graph validate-semantic-enterprise-state-integrity install-dev -validate: validate-json validate-schemas validate-control-plane validate-eventctl validate-event-store validate-events validate-identity validate-process-provenance validate-policy-normalizer validate-service-graph +validate: validate-json validate-schemas validate-control-plane validate-eventctl validate-event-store validate-events validate-identity validate-process-provenance validate-policy-normalizer validate-service-graph validate-semantic-enterprise-state-integrity install-dev: python3 -m pip install -r requirements-dev.txt @@ -57,3 +57,6 @@ validate-policy-normalizer: validate-service-graph: python3 tools/sourceos_service_graph.py validate examples/services/*.json python3 tools/sourceos_service_graph.py graph examples/services/*.json --json >/dev/null + +validate-semantic-enterprise-state-integrity: + python3 tools/validate_semantic_enterprise_state_integrity.py diff --git a/docs/semantic-enterprise-state-integrity.md b/docs/semantic-enterprise-state-integrity.md new file mode 100644 index 0000000..3e6f410 --- /dev/null +++ b/docs/semantic-enterprise-state-integrity.md @@ -0,0 +1,68 @@ +# Semantic Enterprise State Integrity Mapping v0.1 + +`sourceos-syncd` consumes `semantic-enterprise-v0.1.0` from `SocioProphet/ontogenesis` as a state-integrity mapping surface. + +The local fixture is: + +- `examples/semantic-enterprise/v0.1/state-integrity-mapping.example.json` + +The validator is: + +- `tools/validate_semantic_enterprise_state_integrity.py` + +## Source release + +- Repository: `SocioProphet/ontogenesis` +- Release/tag: `semantic-enterprise-v0.1.0` +- Manifest: `manifests/semantic_enterprise_v0_1_manifest.json` +- Rollup registry: `catalog/semantic_enterprise_v0_1_registry.ttl` +- Supply-chain module: `Domains/supply-chain.ttl` +- Named graph fixture: `examples/named-graphs/semantic_sector_named_graphs.ttl` + +## State integrity surfaces + +The v0.1 mapping covers: + +- artifact lineage +- release provenance +- repair lineage +- rollback evidence +- local-first state context +- named graph governance + +## Semantic bindings + +The fixture maps SourceOS state surfaces to Semantic Enterprise concepts: + +- `release_artifact` -> `supply-chain:Component` +- `state_integrity_report` -> `named-graph-governance:CuratedGraph` +- `repair_plan` -> `supply-chain:MitigationAction` +- `rollback_evidence` -> `supply-chain:AlternateSource` + +## Closure boundary + +The mapping distinguishes: + +- `inside_source`: Ontogenesis authors semantic source modules and supply-chain scenarios. +- `outside_state_runtime`: SourceOS syncd maps semantic provenance into local-first state integrity evidence. +- `boundary_membrane`: release tag, source path, graph URI, trust level, access class, retention policy, and lifecycle phase survive translation. +- `feedback_surface`: SourceOS repair, rollback, and state reports remain downstream evidence. + +## Validation + +Run: + +```bash +make validate +``` + +or: + +```bash +python3 tools/validate_semantic_enterprise_state_integrity.py +``` + +## Parent work + +- `SourceOS-Linux/sourceos-syncd#22` +- `SocioProphet/delivery-excellence#21` diff --git a/examples/semantic-enterprise/v0.1/state-integrity-mapping.example.json b/examples/semantic-enterprise/v0.1/state-integrity-mapping.example.json new file mode 100644 index 0000000..c1fb912 --- /dev/null +++ b/examples/semantic-enterprise/v0.1/state-integrity-mapping.example.json @@ -0,0 +1,83 @@ +{ + "contract": "sourceos-syncd.semantic-enterprise.state-integrity", + "version": "0.1.0", + "source": { + "repository": "SocioProphet/ontogenesis", + "release": "semantic-enterprise-v0.1.0", + "manifest_path": "manifests/semantic_enterprise_v0_1_manifest.json", + "rollup_registry_path": "catalog/semantic_enterprise_v0_1_registry.ttl", + "supply_chain_module_path": "Domains/supply-chain.ttl", + "named_graph_fixture_path": "examples/named-graphs/semantic_sector_named_graphs.ttl" + }, + "state_integrity_surfaces": [ + "artifact_lineage", + "release_provenance", + "repair_lineage", + "rollback_evidence", + "local_first_state_context", + "named_graph_governance" + ], + "provenance_requirements": [ + "source_path", + "graph_uri", + "source_system", + "trust_level", + "access_class", + "retention_policy", + "lifecycle_phase", + "release_tag" + ], + "semantic_bindings": [ + { + "sourceos_surface": "release_artifact", + "semantic_enterprise_class": "supply-chain:Component", + "evidence_role": "software-artifact-component", + "required_fields": ["artifact_id", "source_path", "release_tag", "trust_level"] + }, + { + "sourceos_surface": "state_integrity_report", + "semantic_enterprise_class": "named-graph-governance:CuratedGraph", + "evidence_role": "curated-state-perspective", + "required_fields": ["graph_uri", "source_system", "access_class", "retention_policy"] + }, + { + "sourceos_surface": "repair_plan", + "semantic_enterprise_class": "supply-chain:MitigationAction", + "evidence_role": "non-destructive-repair-mitigation", + "required_fields": ["plan_id", "source_path", "affected_component", "approval_state"] + }, + { + "sourceos_surface": "rollback_evidence", + "semantic_enterprise_class": "supply-chain:AlternateSource", + "evidence_role": "alternate-source-or-rollback-reference", + "required_fields": ["rollback_id", "source_path", "previous_state_ref", "trust_level"] + } + ], + "named_graph_contexts": [ + { + "sector": "supply-chain", + "source_path": "examples/scenarios/supply_chain_resilience_demo.ttl", + "graph_uri_fragment": "graphs/scenarios/supply-chain-resilience", + "source_system": "Ontogenesis semantic-enterprise scenario fixture", + "access_class": "internal", + "trust_level": "curated-demo", + "retention_policy": "retain-current-plus-audit-history", + "lifecycle_phase": "KnowledgeCuration" + } + ], + "sourceos_fixture": { + "artifact_id": "sourceos-demo-release-component", + "release_tag": "semantic-enterprise-v0.1.0", + "state_context": "local-first-state-integrity-demo", + "graph_uri_fragment": "graphs/scenarios/supply-chain-resilience", + "trust_level": "curated-demo", + "access_class": "internal", + "operator_narrative": "Semantic Enterprise supply-chain provenance is mapped into SourceOS state integrity evidence without mutating Ontogenesis source semantics." + }, + "closure_model": { + "inside_source": "Ontogenesis authors the semantic source modules and supply-chain scenario.", + "outside_state_runtime": "SourceOS syncd maps semantic provenance into local-first state integrity evidence.", + "boundary_membrane": "Release tag, source path, graph URI, trust level, access class, retention policy, and lifecycle phase must survive translation.", + "feedback_surface": "SourceOS repair, rollback, and state reports remain downstream evidence and do not mutate Ontogenesis source semantics." + } +} diff --git a/tools/validate_semantic_enterprise_state_integrity.py b/tools/validate_semantic_enterprise_state_integrity.py new file mode 100644 index 0000000..f1c809d --- /dev/null +++ b/tools/validate_semantic_enterprise_state_integrity.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +"""Validate SourceOS syncd's Semantic Enterprise v0.1 state-integrity mapping fixture.""" +from __future__ import annotations + +import json +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +FIXTURE = ROOT / "examples/semantic-enterprise/v0.1/state-integrity-mapping.example.json" + +REQUIRED_SURFACES = { + "artifact_lineage", + "release_provenance", + "repair_lineage", + "rollback_evidence", + "local_first_state_context", + "named_graph_governance", +} +REQUIRED_PROVENANCE = { + "source_path", + "graph_uri", + "source_system", + "trust_level", + "access_class", + "retention_policy", + "lifecycle_phase", + "release_tag", +} +REQUIRED_BINDINGS = { + "release_artifact", + "state_integrity_report", + "repair_plan", + "rollback_evidence", +} +REQUIRED_CLOSURE_KEYS = { + "inside_source", + "outside_state_runtime", + "boundary_membrane", + "feedback_surface", +} + + +def main() -> int: + errors: list[str] = [] + if not FIXTURE.is_file(): + print(f"missing fixture: {FIXTURE}") + return 1 + + try: + data = json.loads(FIXTURE.read_text(encoding="utf-8")) + except json.JSONDecodeError as exc: + print(f"invalid JSON: {exc}") + return 1 + + if data.get("contract") != "sourceos-syncd.semantic-enterprise.state-integrity": + errors.append("unexpected contract identifier") + if data.get("version") != "0.1.0": + errors.append("unexpected contract version") + + source = data.get("source") + if not isinstance(source, dict): + errors.append("source must be an object") + else: + expected = { + "repository": "SocioProphet/ontogenesis", + "release": "semantic-enterprise-v0.1.0", + "manifest_path": "manifests/semantic_enterprise_v0_1_manifest.json", + "rollup_registry_path": "catalog/semantic_enterprise_v0_1_registry.ttl", + "supply_chain_module_path": "Domains/supply-chain.ttl", + "named_graph_fixture_path": "examples/named-graphs/semantic_sector_named_graphs.ttl", + } + for key, value in expected.items(): + if source.get(key) != value: + errors.append(f"source.{key} expected {value!r}, got {source.get(key)!r}") + + surfaces = set(data.get("state_integrity_surfaces") or []) + if not REQUIRED_SURFACES.issubset(surfaces): + errors.append(f"state_integrity_surfaces missing: {sorted(REQUIRED_SURFACES.difference(surfaces))}") + + provenance = set(data.get("provenance_requirements") or []) + if not REQUIRED_PROVENANCE.issubset(provenance): + errors.append(f"provenance_requirements missing: {sorted(REQUIRED_PROVENANCE.difference(provenance))}") + + bindings = data.get("semantic_bindings") + if not isinstance(bindings, list): + errors.append("semantic_bindings must be a list") + else: + binding_surfaces = {binding.get("sourceos_surface") for binding in bindings if isinstance(binding, dict)} + if binding_surfaces != REQUIRED_BINDINGS: + errors.append(f"expected sourceos surfaces {sorted(REQUIRED_BINDINGS)}, got {sorted(binding_surfaces)}") + for binding in bindings: + if not isinstance(binding, dict): + errors.append("semantic binding must be an object") + continue + surface = binding.get("sourceos_surface") + if not binding.get("semantic_enterprise_class"): + errors.append(f"{surface} missing semantic_enterprise_class") + if not binding.get("evidence_role"): + errors.append(f"{surface} missing evidence_role") + required_fields = binding.get("required_fields") + if not isinstance(required_fields, list) or not required_fields: + errors.append(f"{surface} must include required_fields") + + contexts = data.get("named_graph_contexts") + if not isinstance(contexts, list) or not contexts: + errors.append("named_graph_contexts must be a non-empty list") + else: + for context in contexts: + if not isinstance(context, dict): + errors.append("named graph context must be an object") + continue + if context.get("sector") != "supply-chain": + errors.append("SourceOS v0.1 mapping should bind the supply-chain sector first") + if not str(context.get("source_path", "")).startswith("examples/scenarios/"): + errors.append("named graph context source_path must point to examples/scenarios") + if not str(context.get("graph_uri_fragment", "")).startswith("graphs/scenarios/"): + errors.append("named graph context graph_uri_fragment must point to graphs/scenarios") + for key in ["source_system", "access_class", "trust_level", "retention_policy", "lifecycle_phase"]: + if not context.get(key): + errors.append(f"named graph context missing {key}") + + fixture = data.get("sourceos_fixture") + if not isinstance(fixture, dict): + errors.append("sourceos_fixture must be an object") + else: + for key in ["artifact_id", "release_tag", "state_context", "graph_uri_fragment", "trust_level", "access_class", "operator_narrative"]: + if not fixture.get(key): + errors.append(f"sourceos_fixture missing {key}") + if fixture.get("release_tag") != "semantic-enterprise-v0.1.0": + errors.append("sourceos_fixture release_tag mismatch") + + closure = data.get("closure_model") + if not isinstance(closure, dict): + errors.append("closure_model must be an object") + else: + missing = REQUIRED_CLOSURE_KEYS.difference(closure) + if missing: + errors.append(f"closure_model missing keys: {sorted(missing)}") + for key in REQUIRED_CLOSURE_KEYS.intersection(closure): + if not isinstance(closure.get(key), str) or not closure[key].strip(): + errors.append(f"closure_model.{key} must be a non-empty string") + + if errors: + print("Semantic Enterprise state-integrity validation failed:") + for error in errors: + print(f"- {error}") + return 1 + + print("Semantic Enterprise state-integrity validation passed.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())