-- 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);