-- IHF Phase 1 + Phase 2 Schema -- Hub, Widget, WidgetVersion, InteractionEvent, Annotation -- Phase 2: AnnotationThread, RequirementCandidate, TriageState, ReviewerAssignment -- See workplans/IHUB-WP-0001-ihf-phase1-minimal-interaction-core.md -- See workplans/IHUB-WP-0002-ihf-phase2-structured-feedback-and-triage.md CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- Users (T10 — authentication) CREATE TABLE users ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, email TEXT NOT NULL UNIQUE, password_hash TEXT NOT NULL, name TEXT NOT NULL, locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL, failed_login_attempts INT NOT NULL DEFAULT 0, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); -- Hubs — bounded domains of responsibility CREATE TABLE hubs ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, slug TEXT NOT NULL UNIQUE, name TEXT NOT NULL, domain TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, api_key TEXT, hub_kind TEXT NOT NULL DEFAULT 'domain' ); -- Widgets — smallest semantically governable interaction units CREATE TABLE widgets ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL, name TEXT NOT NULL, widget_type TEXT NOT NULL, capability_ref TEXT, view_context TEXT, policy_scope TEXT NOT NULL DEFAULT 'internal', status TEXT NOT NULL DEFAULT 'active', version INT NOT NULL DEFAULT 1, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, adapter_spec_id UUID, is_archived BOOLEAN NOT NULL DEFAULT FALSE ); -- Widget version history CREATE TABLE widget_versions ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, widget_id UUID NOT NULL, version INT NOT NULL, schema_snapshot JSONB NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, UNIQUE (widget_id, version) ); -- Interaction events — append-only capture CREATE TABLE interaction_events ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, widget_id UUID NOT NULL, event_type TEXT NOT NULL, actor_id UUID, actor_type TEXT NOT NULL DEFAULT 'user', view_context_ref TEXT, metadata JSONB DEFAULT '{}' NOT NULL, occurred_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX interaction_events_widget_id_idx ON interaction_events (widget_id); CREATE INDEX interaction_events_occurred_at_idx ON interaction_events (occurred_at DESC); -- Enforce append-only on interaction_events CREATE OR REPLACE FUNCTION prevent_interaction_event_mutation() RETURNS TRIGGER AS $$ BEGIN RAISE EXCEPTION 'interaction_events is append-only: UPDATE and DELETE are not permitted'; END; $$ LANGUAGE plpgsql; CREATE TRIGGER interaction_events_no_update BEFORE UPDATE ON interaction_events FOR EACH ROW EXECUTE FUNCTION prevent_interaction_event_mutation(); CREATE TRIGGER interaction_events_no_delete BEFORE DELETE ON interaction_events FOR EACH ROW EXECUTE FUNCTION prevent_interaction_event_mutation(); -- Annotation threads — groups related annotations for triage (Phase 2) CREATE TABLE annotation_threads ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, widget_id UUID NOT NULL, title TEXT NOT NULL, description TEXT, created_by UUID, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); -- Annotations — structured commentary, also append-only by convention -- Phase 2 additions: severity, thread_id CREATE TABLE annotations ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, widget_id UUID NOT NULL, parent_id UUID, body TEXT NOT NULL, category TEXT NOT NULL DEFAULT 'friction', severity TEXT NOT NULL DEFAULT 'medium', thread_id UUID, actor_id UUID, actor_type TEXT NOT NULL DEFAULT 'user', widget_state_ref TEXT, retracted_at TIMESTAMP WITH TIME ZONE DEFAULT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX annotations_widget_id_idx ON annotations (widget_id); -- Requirement candidates — escalated from annotations/threads (Phase 2) CREATE TABLE requirement_candidates ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, title TEXT NOT NULL, description TEXT NOT NULL, source_widget_id UUID NOT NULL, source_thread_id UUID, source_annotation_id UUID, category TEXT NOT NULL DEFAULT 'friction', status TEXT NOT NULL DEFAULT 'open', created_by UUID, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, requirement_id UUID, routed_to_hub_id UUID, outcome_summary JSONB ); CREATE INDEX requirement_candidates_widget_id_idx ON requirement_candidates (source_widget_id); CREATE INDEX requirement_candidates_status_idx ON requirement_candidates (status); -- Triage state history — append-only audit trail of status transitions (Phase 2) CREATE TABLE triage_states ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, candidate_id UUID NOT NULL, status TEXT NOT NULL, notes TEXT, changed_by UUID, changed_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX triage_states_candidate_id_idx ON triage_states (candidate_id); -- Reviewer assignments — one reviewer per candidate (Phase 2) CREATE TABLE reviewer_assignments ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, candidate_id UUID NOT NULL, user_id UUID NOT NULL, assigned_by UUID, assigned_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, UNIQUE (candidate_id) ); -- Requirements — promoted from accepted RequirementCandidates (Phase 3) CREATE TABLE requirements ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, title TEXT NOT NULL, description TEXT NOT NULL, source_candidate_id UUID NOT NULL, status TEXT NOT NULL DEFAULT 'active', created_by UUID, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX requirements_source_candidate_id_idx ON requirements (source_candidate_id); -- Decision records — governance decisions acting on requirements/candidates (Phase 3) CREATE TABLE decision_records ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, title TEXT NOT NULL, rationale TEXT NOT NULL, outcome TEXT NOT NULL, requirement_id UUID, candidate_id UUID, decided_by UUID, decided_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, notes TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, outcome_summary JSONB ); CREATE INDEX decision_records_outcome_idx ON decision_records (outcome); CREATE INDEX decision_records_requirement_id_idx ON decision_records (requirement_id); -- Policy references — editorial links from decisions to policy scope (Phase 3) CREATE TABLE policy_references ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, decision_id UUID NOT NULL, policy_scope TEXT NOT NULL, constraint_note TEXT, created_by UUID, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX policy_references_decision_id_idx ON policy_references (decision_id); -- Implementation change references — editorial links to work items (Phase 3) CREATE TABLE implementation_change_references ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, decision_id UUID NOT NULL, work_item_ref TEXT NOT NULL, system TEXT NOT NULL DEFAULT 'github', linked_by UUID, linked_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX impl_change_refs_decision_id_idx ON implementation_change_references (decision_id); -- Back-reference: which candidate was promoted to a requirement (Phase 3) -- MOVED TO CREATE TABLE: ALTER TABLE requirement_candidates ADD COLUMN requirement_id UUID; -- Deployment records — connect decisions to deployed versions (Phase 4) CREATE TABLE deployment_records ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, impl_ref_id UUID, decision_id UUID NOT NULL, version_ref TEXT NOT NULL, deployed_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, deployed_by UUID, notes TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX deployment_records_decision_id_idx ON deployment_records (decision_id); CREATE INDEX deployment_records_deployed_at_idx ON deployment_records (deployed_at DESC); -- Outcome signals — append-only observation of widget behaviour post-deployment (Phase 4) CREATE TABLE outcome_signals ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, widget_id UUID NOT NULL, deployment_id UUID NOT NULL, signal_type TEXT NOT NULL, value NUMERIC, observed_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX outcome_signals_widget_id_idx ON outcome_signals (widget_id); CREATE INDEX outcome_signals_deployment_id_idx ON outcome_signals (deployment_id); CREATE INDEX outcome_signals_observed_at_idx ON outcome_signals (observed_at DESC); CREATE OR REPLACE FUNCTION prevent_outcome_signal_mutation() RETURNS TRIGGER AS $$ BEGIN RAISE EXCEPTION 'outcome_signals is append-only: UPDATE and DELETE are not permitted'; END; $$ LANGUAGE plpgsql; CREATE TRIGGER outcome_signals_no_update BEFORE UPDATE ON outcome_signals FOR EACH ROW EXECUTE FUNCTION prevent_outcome_signal_mutation(); CREATE TRIGGER outcome_signals_no_delete BEFORE DELETE ON outcome_signals FOR EACH ROW EXECUTE FUNCTION prevent_outcome_signal_mutation(); -- Change evaluations — one score per deployment (Phase 4) CREATE TABLE change_evaluations ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, deployment_id UUID NOT NULL, decision_id UUID, score SMALLINT NOT NULL, rationale TEXT NOT NULL, evaluated_by UUID, evaluated_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, UNIQUE (deployment_id) ); CREATE INDEX change_evaluations_deployment_id_idx ON change_evaluations (deployment_id); -- Agent proposals — AI-generated outputs awaiting human review (Phase 5) CREATE TABLE agent_proposals ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, proposal_type TEXT NOT NULL, source_widget_id UUID, source_candidate_id UUID, source_thread_id UUID, source_decision_id UUID, content TEXT NOT NULL, model_ref TEXT NOT NULL, confidence NUMERIC, status TEXT NOT NULL DEFAULT 'pending', created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, agent_registration_id UUID, tokens_in INTEGER, tokens_out INTEGER ); CREATE INDEX agent_proposals_proposal_type_idx ON agent_proposals (proposal_type); CREATE INDEX agent_proposals_status_idx ON agent_proposals (status); CREATE INDEX agent_proposals_source_widget_id_idx ON agent_proposals (source_widget_id); CREATE INDEX agent_proposals_created_at_idx ON agent_proposals (created_at DESC); -- One review record per proposal (human decision on AI output) (Phase 5) CREATE TABLE agent_review_records ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, proposal_id UUID NOT NULL, reviewer_id UUID, decision TEXT NOT NULL, notes TEXT, reviewed_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, UNIQUE (proposal_id) ); CREATE INDEX agent_review_records_proposal_id_idx ON agent_review_records (proposal_id); -- Confidence annotations — per-dimension breakdown of AI confidence (Phase 5) CREATE TABLE confidence_annotations ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, proposal_id UUID NOT NULL, dimension TEXT NOT NULL, score NUMERIC NOT NULL, explanation TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX confidence_annotations_proposal_id_idx ON confidence_annotations (proposal_id); -- ============================================================ -- Phase 6 — Cross-Framework UI Adaptation Layer -- ============================================================ -- Formalises the rules for widget envelope emission: which data-* attributes -- are required, their format, and the contract version. CREATE TABLE envelope_emission_contracts ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, contract_version TEXT NOT NULL UNIQUE, required_attributes JSONB NOT NULL, optional_attributes JSONB NOT NULL DEFAULT '[]', validation_rules JSONB NOT NULL DEFAULT '{}', description TEXT, status TEXT NOT NULL DEFAULT 'active', created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, maturity TEXT NOT NULL DEFAULT 'stable' ); CREATE INDEX envelope_emission_contracts_status_idx ON envelope_emission_contracts (status); -- Standardised REST interface contract for external event and annotation -- submission — used by non-IHP adapters. CREATE TABLE interaction_reporting_contracts ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, contract_version TEXT NOT NULL UNIQUE, endpoint_path TEXT NOT NULL, accepted_event_types JSONB NOT NULL, required_fields JSONB NOT NULL, auth_scheme TEXT NOT NULL DEFAULT 'bearer', description TEXT, status TEXT NOT NULL DEFAULT 'active', created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, maturity TEXT NOT NULL DEFAULT 'stable' ); CREATE INDEX interaction_reporting_contracts_status_idx ON interaction_reporting_contracts (status); -- Describes how a specific UI technology maps to IHF widget protocol obligations. CREATE TABLE widget_adapter_specs ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, name TEXT NOT NULL UNIQUE, framework TEXT NOT NULL, version TEXT NOT NULL, envelope_contract_id UUID, reporting_contract_id UUID, status TEXT NOT NULL DEFAULT 'draft', notes TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, maturity TEXT NOT NULL DEFAULT 'beta' ); CREATE INDEX widget_adapter_specs_framework_idx ON widget_adapter_specs (framework); CREATE INDEX widget_adapter_specs_status_idx ON widget_adapter_specs (status); -- Link widgets to their adapter spec (null = native IHP widget). -- MOVED TO CREATE TABLE: ALTER TABLE widgets ADD COLUMN adapter_spec_id UUID; CREATE INDEX widgets_adapter_spec_id_idx ON widgets (adapter_spec_id); -- Per-hub API key for bearer-token auth on the interaction reporting endpoint. -- MOVED TO CREATE TABLE: ALTER TABLE hubs ADD COLUMN api_key TEXT; -- Phase 7: Advanced Observability and Operational Integration -- Aggregated pain score per widget, recomputed on demand or scheduled. CREATE TABLE friction_scores ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, widget_id UUID NOT NULL, score INTEGER NOT NULL DEFAULT 0, annotation_count INTEGER NOT NULL DEFAULT 0, error_event_count INTEGER NOT NULL DEFAULT 0, regression_flag BOOLEAN NOT NULL DEFAULT FALSE, stale_candidate_count INTEGER NOT NULL DEFAULT 0, last_computed_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, UNIQUE (widget_id) ); CREATE INDEX friction_scores_widget_id_idx ON friction_scores (widget_id); CREATE INDEX friction_scores_score_idx ON friction_scores (score DESC); -- Detected stalls at specific pipeline stages. CREATE TABLE bottleneck_records ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL, stage TEXT NOT NULL, subject_type TEXT NOT NULL, subject_id UUID NOT NULL, stalled_since TIMESTAMP WITH TIME ZONE NOT NULL, severity TEXT NOT NULL DEFAULT 'medium', resolved_at TIMESTAMP WITH TIME ZONE, notes TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX bottleneck_records_hub_id_idx ON bottleneck_records (hub_id); CREATE INDEX bottleneck_records_stage_idx ON bottleneck_records (stage); CREATE INDEX bottleneck_records_resolved_idx ON bottleneck_records (resolved_at) WHERE resolved_at IS NULL; -- Periodic health snapshots for trend tracking. CREATE TABLE hub_health_snapshots ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL, health_score INTEGER NOT NULL, open_candidates INTEGER NOT NULL DEFAULT 0, regressed_widgets INTEGER NOT NULL DEFAULT 0, stale_decisions INTEGER NOT NULL DEFAULT 0, active_bottlenecks INTEGER NOT NULL DEFAULT 0, computed_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX hub_health_snapshots_hub_id_idx ON hub_health_snapshots (hub_id); CREATE INDEX hub_health_snapshots_computed_at_idx ON hub_health_snapshots (hub_id, computed_at DESC); -- Patterns detected across multiple hubs. CREATE TABLE cross_hub_propagations ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, pattern_type TEXT NOT NULL, source_hub_id UUID, affected_hub_ids JSONB NOT NULL DEFAULT '[]', summary TEXT NOT NULL, detected_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, status TEXT NOT NULL DEFAULT 'open', notes TEXT ); CREATE INDEX cross_hub_propagations_status_idx ON cross_hub_propagations (status); CREATE INDEX cross_hub_propagations_pattern_idx ON cross_hub_propagations (pattern_type); -- Phase 8: Federated Hub Maturity -- Explicit ownership record for a widget. CREATE TABLE widget_ownerships ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, widget_id UUID NOT NULL, owner_hub_id UUID NOT NULL, steward_hub_id UUID, ownership_type TEXT NOT NULL DEFAULT 'local', effective_from TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), effective_until TIMESTAMP WITH TIME ZONE, notes TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX widget_ownerships_widget_id_idx ON widget_ownerships (widget_id); CREATE INDEX widget_ownerships_owner_hub_idx ON widget_ownerships (owner_hub_id); CREATE INDEX widget_ownerships_steward_hub_idx ON widget_ownerships (steward_hub_id); -- Routing rule: automatically routes a RequirementCandidate to another hub. CREATE TABLE hub_routing_rules ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, source_hub_id UUID NOT NULL, target_hub_id UUID NOT NULL, match_category TEXT, match_widget_type TEXT, priority INTEGER NOT NULL DEFAULT 0, status TEXT NOT NULL DEFAULT 'inactive', notes TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX hub_routing_rules_source_idx ON hub_routing_rules (source_hub_id); CREATE INDEX hub_routing_rules_status_idx ON hub_routing_rules (status); -- Routing destination on requirement candidates. -- MOVED TO CREATE TABLE: ALTER TABLE requirement_candidates ADD COLUMN routed_to_hub_id UUID; CREATE INDEX requirement_candidates_routed_hub_idx ON requirement_candidates (routed_to_hub_id) WHERE routed_to_hub_id IS NOT NULL; -- Org-wide policy overlay applied across selected hubs. CREATE TABLE federated_policy_overlays ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, title TEXT NOT NULL, policy_text TEXT NOT NULL, applies_to_hubs JSONB NOT NULL DEFAULT '[]', enforced_from TIMESTAMP WITH TIME ZONE, status TEXT NOT NULL DEFAULT 'draft', notes TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX federated_policy_overlays_status_idx ON federated_policy_overlays (status); -- Named governance role assigned to a hub. CREATE TABLE stewardship_roles ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL, role_name TEXT NOT NULL, assigned_to TEXT NOT NULL, granted_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, revoked_at TIMESTAMP WITH TIME ZONE, notes TEXT ); CREATE INDEX stewardship_roles_hub_id_idx ON stewardship_roles (hub_id); CREATE INDEX stewardship_roles_active_idx ON stewardship_roles (revoked_at) WHERE revoked_at IS NULL; -- Long-term archival entry for any IHF artifact. CREATE TABLE archive_records ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, subject_type TEXT NOT NULL, subject_id UUID NOT NULL, archived_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, reason TEXT NOT NULL, archived_by TEXT NOT NULL, lineage_ref TEXT ); CREATE INDEX archive_records_subject_type_idx ON archive_records (subject_type); CREATE INDEX archive_records_subject_id_idx ON archive_records (subject_id); -- Soft-archive flag on widgets. -- MOVED TO CREATE TABLE: ALTER TABLE widgets ADD COLUMN is_archived BOOLEAN NOT NULL DEFAULT FALSE; CREATE INDEX widgets_is_archived_idx ON widgets (is_archived) WHERE is_archived = TRUE; -- ============================================================ -- GAAF Compliance Foundation (IHUB-WP-0009) -- T02: hub_kind | T03: type registries + seed | T04: maturity columns | T05: manifests -- ============================================================ -- T02 — Hub kind classification -- MOVED TO CREATE TABLE: ALTER TABLE hubs ADD COLUMN hub_kind TEXT NOT NULL DEFAULT 'domain'; CREATE INDEX hubs_hub_kind_idx ON hubs (hub_kind); CREATE UNIQUE INDEX hubs_one_framework_idx ON hubs (hub_kind) WHERE hub_kind = 'framework'; -- T03 — Type registries CREATE TABLE widget_type_registry ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, name TEXT NOT NULL UNIQUE, label TEXT NOT NULL, description TEXT, owner_hub_id UUID, status TEXT NOT NULL DEFAULT 'active', deprecated_in_favour_of TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX widget_type_registry_status_idx ON widget_type_registry (status); CREATE INDEX widget_type_registry_owner_hub_idx ON widget_type_registry (owner_hub_id); CREATE TABLE event_type_registry ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, name TEXT NOT NULL UNIQUE, label TEXT NOT NULL, description TEXT, owner_hub_id UUID, status TEXT NOT NULL DEFAULT 'active', deprecated_in_favour_of TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX event_type_registry_status_idx ON event_type_registry (status); CREATE INDEX event_type_registry_owner_hub_idx ON event_type_registry (owner_hub_id); CREATE TABLE annotation_category_registry ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, name TEXT NOT NULL UNIQUE, label TEXT NOT NULL, description TEXT, owner_hub_id UUID, status TEXT NOT NULL DEFAULT 'active', deprecated_in_favour_of TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX annotation_category_registry_status_idx ON annotation_category_registry (status); CREATE INDEX annotation_category_registry_owner_hub_idx ON annotation_category_registry (owner_hub_id); CREATE TABLE policy_scope_registry ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, name TEXT NOT NULL UNIQUE, label TEXT NOT NULL, description TEXT, owner_hub_id UUID, status TEXT NOT NULL DEFAULT 'active', deprecated_in_favour_of TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX policy_scope_registry_status_idx ON policy_scope_registry (status); CREATE INDEX policy_scope_registry_owner_hub_idx ON policy_scope_registry (owner_hub_id); -- T03 — Type registry seed data moved to Migration/1744502400-seed-type-registries.sql -- T04 — Maturity columns on existing contract tables -- MOVED TO CREATE TABLE: ALTER TABLE envelope_emission_contracts ADD COLUMN maturity TEXT NOT NULL DEFAULT 'stable'; -- MOVED TO CREATE TABLE: ALTER TABLE interaction_reporting_contracts ADD COLUMN maturity TEXT NOT NULL DEFAULT 'stable'; -- MOVED TO CREATE TABLE: ALTER TABLE widget_adapter_specs ADD COLUMN maturity TEXT NOT NULL DEFAULT 'beta'; -- T05 — Hub Capability Manifest CREATE TABLE hub_capability_manifests ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL UNIQUE, manifest_version TEXT NOT NULL DEFAULT '1.0', declared_widget_types JSONB NOT NULL DEFAULT '[]', declared_event_types JSONB NOT NULL DEFAULT '[]', declared_annotation_categories JSONB NOT NULL DEFAULT '[]', declared_policy_scopes JSONB NOT NULL DEFAULT '[]', capability_description TEXT, contact TEXT, status TEXT NOT NULL DEFAULT 'draft', activated_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); CREATE INDEX hub_capability_manifests_hub_id_idx ON hub_capability_manifests (hub_id); CREATE INDEX hub_capability_manifests_status_idx ON hub_capability_manifests (status); -- GAAF: type registries enforced from here (IHUB-WP-0009) -- All new type discriminator columns (widget_type, event_type, category, -- policy_scope) must reference a registry table or carry a CHECK constraint. -- IHF Phase 9 — External API Surface and Consumer SDKs (IHUB-WP-0010) CREATE TABLE api_consumers ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, name TEXT NOT NULL, description TEXT, hub_capability_manifest_id UUID, rate_limit_per_minute INTEGER NOT NULL DEFAULT 60, quota_per_day INTEGER NOT NULL DEFAULT 10000, quota_resets_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE INDEX api_consumers_manifest_idx ON api_consumers (hub_capability_manifest_id); CREATE TABLE api_keys ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, api_consumer_id UUID NOT NULL, key_prefix TEXT NOT NULL, key_hash TEXT NOT NULL, scopes TEXT NOT NULL DEFAULT '', token_type TEXT NOT NULL DEFAULT 'static', expires_at TIMESTAMP WITH TIME ZONE, revoked_at TIMESTAMP WITH TIME ZONE, last_used_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE UNIQUE INDEX api_keys_prefix_idx ON api_keys (key_prefix); CREATE INDEX api_keys_consumer_idx ON api_keys (api_consumer_id); CREATE INDEX api_keys_hash_idx ON api_keys (key_hash); CREATE TABLE webhook_subscriptions ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, api_consumer_id UUID NOT NULL, event_type TEXT NOT NULL, target_url TEXT NOT NULL, secret TEXT NOT NULL, is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE INDEX webhook_subs_consumer_idx ON webhook_subscriptions (api_consumer_id); CREATE INDEX webhook_subs_event_type_idx ON webhook_subscriptions (event_type); CREATE TABLE webhook_deliveries ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, webhook_subscription_id UUID NOT NULL, payload JSONB NOT NULL, attempted_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, status TEXT NOT NULL, response_code INTEGER, latency_ms INTEGER, error_message TEXT ); CREATE INDEX webhook_deliveries_sub_idx ON webhook_deliveries (webhook_subscription_id, attempted_at DESC); CREATE TABLE api_request_log ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, api_consumer_id UUID, endpoint TEXT NOT NULL, method TEXT NOT NULL, status_code INTEGER NOT NULL, latency_ms INTEGER, requested_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE INDEX api_request_log_consumer_time_idx ON api_request_log (api_consumer_id, requested_at DESC); -- IHF Phase 10 — Hub Registry and Widget Marketplace (IHUB-WP-0011) -- No HubRegistry table — hub registry is a view over existing tables -- (hub_capability_manifests + hub_health_snapshots + hubs) -- widget_patterns: reusable widget definitions tied to registered types -- GAAF: widget_type FKs to widget_type_registry(name) — not TEXT CREATE TABLE widget_patterns ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL, name TEXT NOT NULL, description TEXT, widget_type TEXT NOT NULL, is_cross_hub BOOLEAN NOT NULL DEFAULT FALSE, is_published BOOLEAN NOT NULL DEFAULT FALSE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE INDEX widget_patterns_hub_id_idx ON widget_patterns (hub_id); CREATE INDEX widget_patterns_widget_type_idx ON widget_patterns (widget_type); CREATE INDEX widget_patterns_is_published_idx ON widget_patterns (is_published); -- widget_pattern_versions: explicit version history CREATE TABLE widget_pattern_versions ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, widget_pattern_id UUID NOT NULL, version_number INTEGER NOT NULL, definition JSONB NOT NULL, changelog TEXT, published_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, UNIQUE (widget_pattern_id, version_number) ); CREATE INDEX widget_pattern_versions_pattern_idx ON widget_pattern_versions (widget_pattern_id); -- pattern_adoptions: which hubs have adopted which patterns CREATE TABLE pattern_adoptions ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, widget_pattern_id UUID NOT NULL, adopting_hub_id UUID NOT NULL, pinned_version_id UUID, is_version_pinned BOOLEAN NOT NULL DEFAULT FALSE, is_anonymous BOOLEAN NOT NULL DEFAULT FALSE, adopted_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, UNIQUE (widget_pattern_id, adopting_hub_id) ); CREATE INDEX pattern_adoptions_pattern_idx ON pattern_adoptions (widget_pattern_id); CREATE INDEX pattern_adoptions_hub_idx ON pattern_adoptions (adopting_hub_id); -- governance_templates: requirement distillation and decision templates -- categories is JSONB array of annotation_category_registry names; -- each element validated against annotation_category_registry in controller CREATE TABLE governance_templates ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL, name TEXT NOT NULL, description TEXT, categories JSONB NOT NULL DEFAULT '[]', template_body JSONB NOT NULL, is_published BOOLEAN NOT NULL DEFAULT FALSE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE INDEX governance_templates_hub_id_idx ON governance_templates (hub_id); CREATE INDEX governance_templates_is_published_idx ON governance_templates (is_published); -- governance_template_clones: adoption record for governance templates CREATE TABLE governance_template_clones ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, governance_template_id UUID NOT NULL, cloning_hub_id UUID NOT NULL, cloned_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, UNIQUE (governance_template_id, cloning_hub_id) ); CREATE INDEX governance_template_clones_template_idx ON governance_template_clones (governance_template_id); CREATE INDEX governance_template_clones_hub_idx ON governance_template_clones (cloning_hub_id); -- IHF Phase 11 — Advanced AI Federation (IHUB-WP-0012) -- agent_registrations: named, versioned AI agents backed by llm-connect providers -- GAAF: trust_level CHECK constraint — no bare TEXT discriminator CREATE TABLE agent_registrations ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL, name TEXT NOT NULL, slug TEXT NOT NULL UNIQUE, description TEXT, provider TEXT NOT NULL, model_name TEXT NOT NULL, trust_level TEXT NOT NULL DEFAULT 'advisory', capabilities JSONB NOT NULL DEFAULT '[]', system_prompt TEXT, is_active BOOLEAN NOT NULL DEFAULT TRUE, version INTEGER NOT NULL DEFAULT 1, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE INDEX agent_registrations_hub_id_idx ON agent_registrations (hub_id); CREATE INDEX agent_registrations_slug_idx ON agent_registrations (slug); CREATE INDEX agent_registrations_is_active_idx ON agent_registrations (is_active); -- model_routing_policies: task_type → agent selection rules per hub CREATE TABLE model_routing_policies ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL, task_type TEXT NOT NULL, agent_registration_id UUID NOT NULL, priority INTEGER NOT NULL DEFAULT 0, is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, UNIQUE (hub_id, task_type, priority) ); CREATE INDEX model_routing_policies_hub_task_idx ON model_routing_policies (hub_id, task_type); -- agent_delegations: auditable inter-agent subtask delegation records -- GAAF: status CHECK constraint CREATE TABLE agent_delegations ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, delegating_agent_id UUID NOT NULL, receiving_agent_id UUID NOT NULL, parent_proposal_id UUID, scope TEXT NOT NULL, token_budget INTEGER NOT NULL DEFAULT 1000, tokens_used INTEGER, status TEXT NOT NULL DEFAULT 'pending', result JSONB, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, completed_at TIMESTAMP WITH TIME ZONE ); CREATE INDEX agent_delegations_delegating_idx ON agent_delegations (delegating_agent_id); CREATE INDEX agent_delegations_receiving_idx ON agent_delegations (receiving_agent_id); CREATE INDEX agent_delegations_parent_proposal_idx ON agent_delegations (parent_proposal_id); -- collective_proposals: multi-agent proposals with attribution -- GAAF: consensus_status CHECK constraint CREATE TABLE collective_proposals ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, title TEXT NOT NULL, summary TEXT, task_type TEXT NOT NULL, consensus_status TEXT NOT NULL DEFAULT 'pending', final_content JSONB, source_widget_id UUID, source_candidate_id UUID, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE INDEX collective_proposals_task_type_idx ON collective_proposals (task_type); CREATE INDEX collective_proposals_consensus_status_idx ON collective_proposals (consensus_status); -- collective_proposal_contributions: per-agent contribution records CREATE TABLE collective_proposal_contributions ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, collective_proposal_id UUID NOT NULL, agent_registration_id UUID NOT NULL, content JSONB NOT NULL, tokens_in INTEGER, tokens_out INTEGER, model_used TEXT, contributed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE INDEX collective_proposal_contributions_proposal_idx ON collective_proposal_contributions (collective_proposal_id); CREATE INDEX collective_proposal_contributions_agent_idx ON collective_proposal_contributions (agent_registration_id); -- ai_governance_policies: per-hub rules controlling agent scope -- allowed_actions is JSONB array; elements validated at controller layer -- (each element: read | propose | delegate | auto_apply) CREATE TABLE ai_governance_policies ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL, agent_registration_id UUID NOT NULL, artifact_type TEXT NOT NULL, allowed_actions JSONB NOT NULL DEFAULT '["read"]', is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE INDEX ai_governance_policies_hub_agent_idx ON ai_governance_policies (hub_id, agent_registration_id); CREATE INDEX ai_governance_policies_is_active_idx ON ai_governance_policies (is_active); -- agent_performance_records: periodic snapshots of per-agent metrics CREATE TABLE agent_performance_records ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, agent_registration_id UUID NOT NULL, hub_id UUID NOT NULL, period_start TIMESTAMP WITH TIME ZONE NOT NULL, period_end TIMESTAMP WITH TIME ZONE NOT NULL, proposals_generated INTEGER NOT NULL DEFAULT 0, proposals_accepted INTEGER NOT NULL DEFAULT 0, proposals_rejected INTEGER NOT NULL DEFAULT 0, proposals_revised INTEGER NOT NULL DEFAULT 0, mean_confidence DOUBLE PRECISION, calibration_score DOUBLE PRECISION, computed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE INDEX agent_performance_records_agent_idx ON agent_performance_records (agent_registration_id); CREATE INDEX agent_performance_records_period_idx ON agent_performance_records (period_start, period_end); -- Extend agent_proposals with agent_registration_id and token tracking (Phase 11) -- MOVED TO CREATE TABLE: ALTER TABLE agent_proposals ADD COLUMN agent_registration_id UUID; -- MOVED TO CREATE TABLE: ALTER TABLE agent_proposals ADD COLUMN tokens_in INTEGER; -- MOVED TO CREATE TABLE: ALTER TABLE agent_proposals ADD COLUMN tokens_out INTEGER; CREATE INDEX agent_proposals_agent_registration_idx ON agent_proposals (agent_registration_id); -- ============================================================ -- Phase 12 — Platform Memory and Continuous Learning -- ============================================================ -- outcome_correlations: links annotation signals to downstream outcome quality -- GAAF: correlation_type CHECK constraint CREATE TABLE outcome_correlations ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL, annotation_category TEXT NOT NULL, correlation_type TEXT NOT NULL DEFAULT 'annotation_predictor', correlation_score DOUBLE PRECISION NOT NULL, sample_count INTEGER NOT NULL DEFAULT 0, computed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE INDEX outcome_correlations_hub_idx ON outcome_correlations (hub_id); CREATE INDEX outcome_correlations_score_idx ON outcome_correlations (correlation_score DESC); -- pattern_performance_records: per-pattern historical outcome quality CREATE TABLE pattern_performance_records ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, widget_pattern_id UUID NOT NULL, hub_id UUID NOT NULL, adoption_count INTEGER NOT NULL DEFAULT 0, positive_outcome_count INTEGER NOT NULL DEFAULT 0, total_outcome_count INTEGER NOT NULL DEFAULT 0, mean_outcome_value DOUBLE PRECISION, outcome_rank INTEGER, calibrated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, UNIQUE (widget_pattern_id, hub_id) ); CREATE INDEX pattern_performance_pattern_idx ON pattern_performance_records (widget_pattern_id); CREATE INDEX pattern_performance_rank_idx ON pattern_performance_records (hub_id, outcome_rank); -- adaptive_threshold_configs: per-hub friction weight overrides CREATE TABLE adaptive_threshold_configs ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL UNIQUE, weight_overrides JSONB NOT NULL DEFAULT '{}', bottleneck_threshold_override DOUBLE PRECISION, calibration_date TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, notes TEXT ); CREATE INDEX adaptive_threshold_hub_idx ON adaptive_threshold_configs (hub_id); -- institutional_knowledge_entries: distilled decision summaries -- GIN index for full-text search (PostgreSQL tsvector, no extension needed) CREATE TABLE institutional_knowledge_entries ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL, decision_record_id UUID, summary TEXT NOT NULL, summary_tsv TSVECTOR, tags JSONB NOT NULL DEFAULT '[]', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE INDEX institutional_knowledge_hub_idx ON institutional_knowledge_entries (hub_id); CREATE INDEX institutional_knowledge_fts_idx ON institutional_knowledge_entries USING GIN (summary_tsv); -- learning_insights: platform-level insights with evidence links -- GAAF: insight_type CHECK constraint CREATE TABLE learning_insights ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, hub_id UUID NOT NULL, insight_type TEXT NOT NULL, title TEXT NOT NULL, body TEXT NOT NULL, evidence_links JSONB NOT NULL DEFAULT '[]', is_actioned BOOLEAN NOT NULL DEFAULT FALSE, computed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE INDEX learning_insights_hub_idx ON learning_insights (hub_id); CREATE INDEX learning_insights_type_idx ON learning_insights (insight_type); -- Extend core tables with outcome_summary (retroactive lineage enrichment) -- GAAF rule 3: /contracts/core/ updated in T01/T06 -- MOVED TO CREATE TABLE: ALTER TABLE decision_records ADD COLUMN outcome_summary JSONB; -- MOVED TO CREATE TABLE: ALTER TABLE requirement_candidates ADD COLUMN outcome_summary JSONB; -- Foreign Key Constraints (for IHP type generation — IHP generates Id types from these) ALTER TABLE widgets ADD FOREIGN KEY (hub_id) REFERENCES hubs(id); ALTER TABLE widget_versions ADD FOREIGN KEY (widget_id) REFERENCES widgets(id); ALTER TABLE interaction_events ADD FOREIGN KEY (widget_id) REFERENCES widgets(id); ALTER TABLE outcome_signals ADD FOREIGN KEY (widget_id) REFERENCES widgets(id); ALTER TABLE outcome_signals ADD FOREIGN KEY (deployment_id) REFERENCES deployment_records(id); ALTER TABLE deployment_records ADD FOREIGN KEY (impl_ref_id) REFERENCES implementation_change_references(id); ALTER TABLE deployment_records ADD FOREIGN KEY (decision_id) REFERENCES decision_records(id); ALTER TABLE api_keys ADD FOREIGN KEY (api_consumer_id) REFERENCES api_consumers(id); ALTER TABLE webhook_subscriptions ADD FOREIGN KEY (api_consumer_id) REFERENCES api_consumers(id); ALTER TABLE pattern_adoptions ADD FOREIGN KEY (widget_pattern_id) REFERENCES widget_patterns(id); ALTER TABLE annotation_threads ADD FOREIGN KEY (widget_id) REFERENCES widgets(id); ALTER TABLE annotations ADD FOREIGN KEY (widget_id) REFERENCES widgets(id); ALTER TABLE annotations ADD FOREIGN KEY (thread_id) REFERENCES annotation_threads(id); ALTER TABLE requirement_candidates ADD FOREIGN KEY (source_widget_id) REFERENCES widgets(id); ALTER TABLE requirement_candidates ADD FOREIGN KEY (source_thread_id) REFERENCES annotation_threads(id); ALTER TABLE requirement_candidates ADD FOREIGN KEY (source_annotation_id) REFERENCES annotations(id); ALTER TABLE requirement_candidates ADD FOREIGN KEY (requirement_id) REFERENCES requirements(id); ALTER TABLE triage_states ADD FOREIGN KEY (candidate_id) REFERENCES requirement_candidates(id); ALTER TABLE reviewer_assignments ADD FOREIGN KEY (candidate_id) REFERENCES requirement_candidates(id); ALTER TABLE reviewer_assignments ADD FOREIGN KEY (user_id) REFERENCES users(id); ALTER TABLE reviewer_assignments ADD FOREIGN KEY (assigned_by) REFERENCES users(id); ALTER TABLE requirements ADD FOREIGN KEY (source_candidate_id) REFERENCES requirement_candidates(id); ALTER TABLE decision_records ADD FOREIGN KEY (requirement_id) REFERENCES requirements(id); ALTER TABLE decision_records ADD FOREIGN KEY (candidate_id) REFERENCES requirement_candidates(id); ALTER TABLE implementation_change_references ADD FOREIGN KEY (decision_id) REFERENCES decision_records(id); ALTER TABLE policy_references ADD FOREIGN KEY (decision_id) REFERENCES decision_records(id); ALTER TABLE agent_review_records ADD FOREIGN KEY (proposal_id) REFERENCES agent_proposals(id); ALTER TABLE confidence_annotations ADD FOREIGN KEY (proposal_id) REFERENCES agent_proposals(id); ALTER TABLE institutional_knowledge_entries ADD FOREIGN KEY (hub_id) REFERENCES hubs(id); ALTER TABLE institutional_knowledge_entries ADD FOREIGN KEY (decision_record_id) REFERENCES decision_records(id);