SHACL validation infrastructure exists but has critical gaps preventing runtime enforcement: (1) fail-open error handling that silently passes invalid data, (2) TypeScript adapter bypassing validation entirely, (3) update events explicitly skipping validation, (4) IR-to-KGS pipeline never validating generated triples. This plan implements complete enforcement with feature-flag control, performance optimization achieving <20ms per write, per-context rollout, monitoring, alerting, shape versioning, cross-context validation, legacy data handling, automated impact analysis, and developer tooling.
Add feature flag configuration system — In main.py, add SHACL_ENFORCEMENT_ENABLED = os.getenv("SHACL_ENFORCEMENT_ENABLED", "true").lower() == "true", SHACL_ENFORCEMENT_CONTEXTS = set(os.getenv("SHACL_ENFORCEMENT_CONTEXTS", "").split(",")) (empty = all), SHACL_MAINTENANCE_MODE = os.getenv("SHACL_MAINTENANCE_MODE", "false").lower() == "true", and SHACL_SHAPES_VERSION = os.getenv("SHACL_SHAPES_VERSION", "v1") at module level, pass all to OxigraphAdapter.__init__().
Change fail-open to fail-closed with context-aware flag — In oxigraph_adapter.py, replace return True with: if self.maintenance_mode: logger.error(f"SHACL violation (maintenance mode): {e}"); return False, str(e), violations; elif self.enforcement_enabled and (not self.enforcement_contexts or bounded_context in self.enforcement_contexts): raise ShaclValidationError(...); else: logger.warning(...); return False, str(e), [].
Implement SHACL shape versioning — In ontologies, rename current file to sea-shapes.v1.shacl, create symlink sea-shapes.shacl -> sea-shapes.v1.shacl, update oxigraph_adapter.py _load_shapes_graph() to check SHACL_SHAPES_VERSION env var and load versioned file sea-shapes.{version}.shacl, document version compatibility matrix in docs/handbooks/shacl-shape-versioning.md.
Optimize validation with shapes caching — In oxigraph_adapter.py, extract shapes parsing to _load_shapes_graph(version: str) helper with @lru_cache(maxsize=3) decorator (cache 3 versions) so shapes are parsed once at startup instead of per-validation, reducing overhead from 50-100ms to <20ms.
Optimize validation with delta-only strategy — In oxigraph_adapter.py, validate only the data_graph parameter (temp graph delta) instead of entire self._graph to avoid re-validating existing triples, cutting validation time by ~70% for single-entity operations.
Add validation result caching — In oxigraph_adapter.py, create _validation_cache: Dict[str, Tuple[bool, datetime, str]] instance variable, cache results keyed by hashlib.sha256(sorted(graph.serialize())).hexdigest() with 5-minute TTL, return cached result for duplicate validation requests (idempotent operations).
Implement cross-context validation with caching — In oxigraph_adapter.py, add _check_cross_context_references(data_graph: Graph) -> List[str] helper that extracts referenced entity URIs, uses SPARQL EXISTS clauses for efficient checking, caches entity existence results per-session with 10-minute TTL in _entity_existence_cache: Dict[str, Tuple[bool, datetime]], batches reference checks when validating multiple triples.
Create shared shapes directory structure — Create ontologies/shared/ directory for cross-cutting shapes owned by architecture team, move universal constraints (e.g., identity patterns, temporal properties) to ontologies/shared/core.shacl, update bounded-context shapes in ontologies to import shared shapes using owl:imports, require ADR approval process (documented in docs/handbooks/shape-governance.md) for changes to shared shapes.
Add cross-context dependency annotations to shapes — In ontologies/sea-shapes.v1.shacl, add custom property sea:requiresContext to shapes that reference other contexts (e.g., sea-inc:SemanticIncidentShape sea:requiresContext "semantic-core" for debt references), parse these annotations in validation logic to enforce dependency checks.
Add TypeScript validated adapter — Create libs/skeleton/graph/adapters/src/lib/validated-triple-store.adapter.ts implementing TripleStorePort with constructor (inner: TripleStorePort, kgServiceUrl: string, enforcementEnabled = true, enforcementContexts: string[] = [], maintenanceMode = false), storeTriples() that calls POST ${kgServiceUrl}/graph/shacl/validate before delegating, throws ShaclValidationError with detailed constraint violation info unless maintenance mode active.
Enhance ShaclValidationError with actionable messages — In oxigraph_adapter.py, add get_fix_suggestions() method that parses violations and returns dict of {constraint_path: suggested_fix} (e.g., “severity must be one of: Low, Medium, High, Critical, Blocking”), include violated shape URI, focus node, example valid values, and cross-context dependency errors in error message.
Enable validation for update events — In oxigraph_adapter.py, remove validate = False lines for SemanticDebtUpdated and SemanticDebtSuperseded, refactor _project_debt_updated() to accept graph: Graph parameter and use temp-graph pattern like _project_debt_created_to_graph(), then validate the merged result state.
Add IR-to-KGS batch validation — In ir_to_kgs.py, add _validate_triples_batch(triples: List[str], shapes_version: str = "v1") -> None that parses all triples into single Graph (batch operation), loads shapes from ontologies/sea-shapes.{shapes_version}.shacl, calls pyshacl.validate() once for entire batch (~10x faster than per-triple), raises ValueError with full report if violations found, invoke before writing snapshot file.
Create kg-validate diagnostic command — Add to justfile: kg-validate: (python services/knowledge-graph/scripts/validate_existing_graph.py) that instantiates OxigraphAdapter, loads current graph from persistence, calls validate_with_shacl(), checks cross-context references, outputs JSON report with {"conforms": bool, "violation_count": int, "violations": [...], "fix_suggestions": {...}, "missing_references": [], "legacy_data_count": int}, exits with code 1 if violations found.
Create kg-validate-local pre-commit hook — Add to justfile: kg-validate-local: (python tools/validate_local_triples.py) that scans working directory for modified .sea files, generates triples via IR pipeline, validates against SHACL shapes, outputs violations with fix suggestions before allowing commit, integrate with pre-commit for automatic developer feedback.
Implement shape change impact analysis — Add to justfile: kg-impact-analysis: (python services/knowledge-graph/scripts/shape_impact_analysis.py --shape-version=${SHAPE_VERSION:-v2}) that loads entire graph, validates against new shapes version, generates JSON report with {"affected_entity_count": int, "violation_types": [...], "estimated_remediation_effort_hours": float, "auto_fix_available": bool, "sample_violations": [...]}, integrate with .github/workflows/shape-validation.yml to run automatically when files in ontologies are modified in PRs.
Create shape-lint validation tool — Add to justfile: shape-lint: (python tools/shape_lint.py) that scans all .shacl files in ontologies, detects conflicting constraints across contexts (e.g., same property with different cardinality), checks that bounded-context shapes extend (not override) shared shapes, validates import graph consistency, outputs violations with severity (error/warning), integrate with CI to block merges on errors.
Wire TypeScript validated adapter — In rag-orchestrator.service.ts, update DI config to inject ValidatedTripleStoreAdapter wrapping OxigraphAdapter with KG service URL from KNOWLEDGE_GRAPH_SERVICE_URL, enforcement flag from SHACL_ENFORCEMENT_ENABLED, contexts from SHACL_ENFORCEMENT_CONTEXTS, and maintenance mode from SHACL_MAINTENANCE_MODE.
Add OpenTelemetry monitoring — In oxigraph_adapter.py, wrap with @tracer.start_as_current_span("shacl.validate"), add span attributes shacl.conforms, shacl.violation_count, shacl.validation_duration_ms, shacl.cache_hit, shacl.bounded_context, shacl.shapes_version, shacl.maintenance_mode, shacl.legacy_data_exemption, emit counter metric shacl_validation_failures_total{enforcement_enabled, bounded_context, maintenance_mode}.
Configure Prometheus alerting — Add to infra/otel/alerts.yml: (1) ShaclValidationFailureRateHigh alert when rate(shacl_validation_failures_total{maintenance_mode="false"}[5m]) > 0.083 (>5/min warning), > 0.33 (>20/min critical), (2) ShaclValidationSlow when histogram_quantile(0.95, shacl_validation_duration_ms) > 100 sustained 5min, (3) ShaclCacheEfficiencyLow when cache hit rate < 0.8, (4) ShaclMaintenanceModeActive when maintenance mode enabled >4 hours, (5) ShapeVersionChanged when new shapes version deployed, (6) LegacyDataMigrationOverdue when migration deadline expires.
Implement legacy data exemption system with auto-expiration — In oxigraph_adapter.py, add _check_legacy_exemption(entity_uri: URIRef) -> Tuple[bool, datetime | None] that queries for entity_uri sea:legacyData true; sea:migrationDeadline "2026-04-15"^^xsd:date triple, if present check deadline: if expired escalate to error after 30-day grace period, if within deadline log warning and skip validation, add _mark_legacy_data(entity_uri: URIRef, migration_deadline: datetime) method, create services/knowledge-graph/scripts/legacy_data_migration.py with daily cron job that publishes LegacyDataMigrationOverdue events for expired deadlines, add migration progress dashboard to workbench showing {total_legacy_entities, migrated_count, overdue_count, remaining_days}.
Implement shape change notification system — In oxigraph_adapter.py, add _detect_shape_changes() method called on startup that compares current shapes version with last-deployed version (stored in graph metadata), if changed compute diff using rdflib.compare.graph_diff(), classify changes as {added_constraints, removed_constraints, modified_constraints, breaking_changes}, publish ShapeVersionChanged event to NATS with {version, changes, affected_contexts, migration_required, automatic_rollback_threshold}, subscribe bounded context services to receive notifications, include sample violations from impact analysis report.
Create migration runbook — Add docs/handbooks/shacl-enforcement-migration.md documenting: (1) Pre-deployment: Run just kg-validate and just kg-impact-analysis, (2) Phase 1: Enable for semantic-core via SHACL_ENFORCEMENT_CONTEXTS=semantic-core, monitor 24h, (3) Phase 2: Add case-management, (4) Phase 3: Enable globally, (5) Remediation: SPARQL UPDATE queries for each violation type, (6) Legacy data handling: Mark existing violations with sea:legacyData and 90-day migration deadline, track progress in Workbench dashboard, (7) Maintenance mode: Set SHACL_MAINTENANCE_MODE=true for max 4-hour refactoring windows, (8) Rollback: Set SHACL_ENFORCEMENT_ENABLED=false or automatic rollback if failure rate exceeds threshold.
Create shape versioning migration guide — Add docs/handbooks/shacl-shape-versioning.md documenting: (1) Version compatibility matrix (v1 supported until v3 released, 1-version backwards compat), (2) Creating new version: Copy sea-shapes.vN.shacl to sea-shapes.vN+1.shacl, modify, run just kg-impact-analysis --shape-version=vN+1 to assess impact, (3) Testing: Set SHACL_SHAPES_VERSION=vN+1 in staging, (4) Notification: ShapeVersionChanged event published automatically with breaking change flags, (5) Gradual rollout: Deploy new shapes version, run dual-validation for 1 week, (6) Migration scripts for breaking changes with examples, (7) Automatic rollback if failure rate exceeds 10% or >50 entities affected.
Create shape governance documentation — Add docs/handbooks/shape-governance.md documenting: (1) Ownership model: Shared shapes owned by architecture team require ADR approval, bounded-context shapes owned by domain teams require PR review, (2) Change approval process: Run just shape-lint and just kg-impact-analysis in PR, architecture team reviews shared shape changes, automated approval if impact <10 entities, (3) Conflict resolution: Bounded-context shapes must extend (not override) shared constraints, violations detected by just shape-lint, (4) Versioning policy: Major version for breaking changes, minor for backwards-compatible additions.
Add performance benchmarking — In tests, create test_shacl_performance.py with benchmarks measuring: single-entity validation (<20ms target), batch validation (100 entities <100ms target), cache hit rate (>80% for idempotent operations), cross-context validation overhead (<5ms additional), entity existence cache hit rate (>90%), validation with/without shapes caching, assert performance targets in CI to prevent regression.
Update test suite — In test_shacl_validation.py, add tests for: test_enforcement_flag_disabled_logs_warnings(), test_enforcement_contexts_filter(), test_maintenance_mode_logs_errors(), test_maintenance_mode_alert_triggers(), test_validation_cache_hit(), test_validation_cache_expiry(), test_update_event_validated(), test_cross_context_reference_validation(), test_cross_context_cache_efficiency(), test_missing_reference_error(), test_legacy_data_exemption(), test_legacy_data_migration_deadline(), test_legacy_data_auto_expiration(), test_shape_versioning(), test_shape_change_notification(), test_shape_conflict_detection(), test_impact_analysis_accuracy(), test_typescript_adapter_rejects_invalid(), test_error_messages_actionable(), test_fix_suggestions_present(), verify all pass with enforcement enabled.