feat(pipeline): implement Control Dependency Engine (Block 9)

Core engine (dependency_engine.py):
- 5 dependency types: prerequisite, supersedes, compensating_control,
  conditional_requirement, scope_exclusion
- Generic condition evaluator (JSONB rules with AND/OR/NOT/field ops)
- Priority-based conflict resolution
- Cycle detection (DFS) + topological sort
- Full evaluation with MCP-compatible dependency_resolution trace
- 39 tests all passing (incl. GHV scenario from user requirements)

Automatic generator (dependency_generator.py):
- Ontology-based: same normalized_object + phase sequence -> prerequisite
- Pattern-based: define->implement, implement->monitor, etc.
- Domain packs: YAML rules for GDPR, AI Act, CRA, Security, Labor Contracts
- 14 tests all passing

API routes (dependency_routes.py):
- CRUD for dependencies
- POST /evaluate with dependency resolution
- POST /generate (auto-generation with dry_run)
- POST /validate (cycle detection)
- GET /graph (nodes + edges for visualization)

Prompt enhancement (decomposition_pass.py):
- Added dependency_hints + lifecycle_phase_order to Pass 0b prompt
- Stored in generation_metadata for post-processing

DB migration: control_dependencies + control_evaluation_results tables

126 tests total, all passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-26 20:28:10 +02:00
parent 5aaa62dca7
commit 42ab5ead26
14 changed files with 2421 additions and 2 deletions

View File

@@ -351,3 +351,33 @@ def build_canonical_key(
if asset_scope:
parts.append(asset_scope)
return ":".join(parts)
# ============================================================================
# PHASE ORDERING (for dependency engine — lifecycle sequence)
# ============================================================================
PHASE_ORDER: dict[str, int] = {
"scope": 1,
"definition": 2,
"governance": 2,
"design": 3,
"implementation": 4,
"configuration": 5,
"operation": 6,
"training": 6,
"monitoring": 7,
"testing": 8,
"review": 9,
"assessment": 10,
"remediation": 10,
"validation": 11,
"reporting": 12,
"evidence": 13,
}
def get_phase_order(action_type: str) -> int:
"""Get the lifecycle phase order for an action_type (1-13)."""
phase = get_phase(action_type)
return PHASE_ORDER.get(phase, 6) # default: operation (middle)