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>
80 lines
2.9 KiB
SQL
80 lines
2.9 KiB
SQL
-- Migration 001: Control Dependency Engine (Block 9)
|
|
-- Schema: compliance (search_path already set)
|
|
-- Run: psql -U breakpilot -d breakpilot_db -f 001_dependency_engine.sql
|
|
|
|
SET search_path TO compliance, public;
|
|
|
|
-- ========================================
|
|
-- control_dependencies
|
|
-- ========================================
|
|
|
|
CREATE TABLE IF NOT EXISTS control_dependencies (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
source_control_id UUID NOT NULL REFERENCES canonical_controls(id) ON DELETE CASCADE,
|
|
target_control_id UUID NOT NULL REFERENCES canonical_controls(id) ON DELETE CASCADE,
|
|
|
|
dependency_type VARCHAR(30) NOT NULL
|
|
CHECK (dependency_type IN (
|
|
'prerequisite',
|
|
'conditional_requirement',
|
|
'supersedes',
|
|
'compensating_control',
|
|
'scope_exclusion'
|
|
)),
|
|
|
|
condition JSONB DEFAULT '{}',
|
|
effect JSONB NOT NULL DEFAULT '{}',
|
|
|
|
priority INTEGER NOT NULL DEFAULT 100,
|
|
|
|
generation_method VARCHAR(30) NOT NULL DEFAULT 'manual'
|
|
CHECK (generation_method IN (
|
|
'manual', 'ontology', 'pattern', 'domain_pack', 'llm_hint'
|
|
)),
|
|
generation_metadata JSONB DEFAULT '{}',
|
|
|
|
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
|
|
CONSTRAINT uq_dependency_edge UNIQUE (source_control_id, target_control_id, dependency_type),
|
|
CONSTRAINT no_self_dependency CHECK (source_control_id != target_control_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_dep_target ON control_dependencies(target_control_id) WHERE is_active = TRUE;
|
|
CREATE INDEX IF NOT EXISTS idx_dep_source ON control_dependencies(source_control_id) WHERE is_active = TRUE;
|
|
CREATE INDEX IF NOT EXISTS idx_dep_type ON control_dependencies(dependency_type);
|
|
|
|
-- ========================================
|
|
-- control_evaluation_results
|
|
-- ========================================
|
|
|
|
CREATE TABLE IF NOT EXISTS control_evaluation_results (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
control_id UUID NOT NULL REFERENCES canonical_controls(id) ON DELETE CASCADE,
|
|
evaluation_run_id UUID NOT NULL,
|
|
company_profile JSONB DEFAULT '{}',
|
|
|
|
raw_status VARCHAR(30) NOT NULL,
|
|
resolved_status VARCHAR(30) NOT NULL
|
|
CHECK (resolved_status IN (
|
|
'pass', 'fail', 'not_applicable',
|
|
'partially_satisfied', 'compensated_fail',
|
|
'review_required'
|
|
)),
|
|
|
|
dependency_resolution JSONB DEFAULT '[]',
|
|
confidence FLOAT DEFAULT 1.0,
|
|
reasoning TEXT DEFAULT '',
|
|
|
|
evaluated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
|
|
CONSTRAINT uq_eval_per_run UNIQUE (control_id, evaluation_run_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_eval_run ON control_evaluation_results(evaluation_run_id);
|
|
CREATE INDEX IF NOT EXISTS idx_eval_control ON control_evaluation_results(control_id);
|
|
CREATE INDEX IF NOT EXISTS idx_eval_status ON control_evaluation_results(resolved_status);
|