{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "schema-drift-alert-board",
  "title": "Schema Drift Alert Board",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/schema-drift-alert-board/schema-drift-alert-board.component.ts",
      "content": "// Data warehouse schema drift and anomaly alert board: header with acknowledge-all,\n// 4 telemetry metric cards, a filterable incidents table, and a blast-radius lineage\n// tree with contract-YAML / remediation-DDL tabs. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core'\nimport {\n  Activity,\n  AlertCircle,\n  AlertTriangle,\n  ArrowUpRight,\n  BellOff,\n  BellRing,\n  Check,\n  CheckCircle2,\n  Clock,\n  Copy,\n  Database,\n  Eye,\n  FileCode2,\n  Filter,\n  Layers,\n  LucideAngularModule,\n  Network,\n  RefreshCw,\n  Search,\n  ShieldAlert,\n  ShieldCheck,\n  Table2,\n  Terminal,\n  Workflow,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiProgressComponent } from '@/ui/progress/progress.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\nimport {\n  UiTableBodyComponent,\n  UiTableCellComponent,\n  UiTableComponent,\n  UiTableHeadComponent,\n  UiTableHeaderComponent,\n  UiTableRowComponent,\n} from '@/ui/table/table.component'\n\nexport interface BlastRadiusNode {\n  id: string\n  name: string\n  layer: 'origin' | 'transform' | 'mart' | 'consumer'\n  layerLabel: string\n  status: 'mutation' | 'impacted' | 'healthy' | 'warning'\n  statusLabel: string\n  type: string\n  description: string\n  owner: string\n  runtime?: string\n}\n\nexport interface SchemaDriftIncident {\n  id: string\n  targetTable: string\n  environment: 'Snowflake Prod' | 'Postgres OLTP' | 'Kafka Topics'\n  changeType: 'Unexpected Column Added' | 'Data Type Alteration' | 'Nullability Relaxation' | 'Enum Definition Extended'\n  driftDiff: string\n  diffMode: 'added' | 'altered' | 'relaxed'\n  severity: 'low' | 'medium' | 'high'\n  severityLabel: string\n  blastRadiusSummary: string\n  brokenModelsCount: number\n  impactedPipelinesCount: number\n  detectedAt: string\n  actionLabel: string\n  isAcknowledged: boolean\n  isContractSynced: boolean\n  contractYaml: string\n  remediationDdl: string\n  lineageNodes: BlastRadiusNode[]\n}\n\nconst defaultIncidents: SchemaDriftIncident[] = [\n  {\n    id: 'drift-inc-1',\n    targetTable: 'public.users',\n    environment: 'Postgres OLTP',\n    changeType: 'Unexpected Column Added',\n    driftDiff: '+ phone_country_code VARCHAR(8)',\n    diffMode: 'added',\n    severity: 'low',\n    severityLabel: 'Low Non-Breaking',\n    blastRadiusSummary: '0 models broken',\n    brokenModelsCount: 0,\n    impactedPipelinesCount: 0,\n    detectedAt: '14m ago',\n    actionLabel: 'Add to Data Contract',\n    isAcknowledged: false,\n    isContractSynced: false,\n    contractYaml: `version: 2\nmodels:\n  - name: dim_users\n    config:\n      contract:\n        enforced: true\n    columns:\n      - name: user_id\n        data_type: varchar\n        constraints:\n          - type: not_null\n      # Newly detected column added upstream in Postgres OLTP\n      - name: phone_country_code\n        data_type: varchar(8)\n        description: \"ISO-3166-1 alpha-2 / E.164 dial prefix added by auth service\"`,\n    remediationDdl: `-- Automated dbt / Snowflake staging sync\nALTER TABLE raw_postgres.users\n  ADD COLUMN IF NOT EXISTS phone_country_code VARCHAR(8);`,\n    lineageNodes: [\n      {\n        id: 'node-users-origin',\n        name: 'public.users',\n        layer: 'origin',\n        layerLabel: 'Postgres Source Table',\n        status: 'mutation',\n        statusLabel: 'Column Added (+1 col)',\n        type: 'Postgres Table',\n        description: 'OLTP user management table with new phone_country_code attribute.',\n        owner: '#team-auth',\n      },\n      {\n        id: 'node-users-ingest',\n        name: 'fivetran.raw_postgres_users',\n        layer: 'transform',\n        layerLabel: 'CDC Connector Stream',\n        status: 'healthy',\n        statusLabel: 'CDC Auto-Synced',\n        type: 'Fivetran Log-Based CDC',\n        description: 'Automated column replication synced to Snowflake bronze raw zone.',\n        owner: '#data-platform',\n        runtime: '<2m latency',\n      },\n      {\n        id: 'node-users-stg',\n        name: 'dbt.stg_users',\n        layer: 'transform',\n        layerLabel: 'dbt Staging View',\n        status: 'healthy',\n        statusLabel: '0 Breaking (Explicit Select)',\n        type: 'dbt View Model',\n        description: 'Explicit column projection prevents unmapped column propagation.',\n        owner: '#data-eng',\n        runtime: '12s run',\n      },\n      {\n        id: 'node-users-dim',\n        name: 'marts.dim_customers',\n        layer: 'mart',\n        layerLabel: 'Core Dimension Mart',\n        status: 'healthy',\n        statusLabel: 'Contract Compliant',\n        type: 'Snowflake Dynamic Table',\n        description: 'Certified dimension table feeding marketing cohorts and customer 360.',\n        owner: '#data-eng',\n      },\n      {\n        id: 'node-users-crm',\n        name: 'HubSpot Reverse ETL Sync',\n        layer: 'consumer',\n        layerLabel: 'Operational Reverse ETL',\n        status: 'healthy',\n        statusLabel: 'Active · 0 Failures',\n        type: 'Census Sync Pipeline',\n        description: 'Outbound sync to HubSpot Marketing Hub CRM contacts.',\n        owner: '#rev-ops',\n      },\n    ],\n  },\n  {\n    id: 'drift-inc-2',\n    targetTable: 'analytics.fct_orders',\n    environment: 'Snowflake Prod',\n    changeType: 'Data Type Alteration',\n    driftDiff: 'discount_amount FLOAT -> DECIMAL(18,2)',\n    diffMode: 'altered',\n    severity: 'medium',\n    severityLabel: 'Medium Warning',\n    blastRadiusSummary: '2 dbt models affected',\n    brokenModelsCount: 0,\n    impactedPipelinesCount: 2,\n    detectedAt: '32m ago',\n    actionLabel: 'Inspect Model Lineage',\n    isAcknowledged: false,\n    isContractSynced: false,\n    contractYaml: `version: 2\nmodels:\n  - name: fct_orders\n    config:\n      contract:\n        enforced: true\n    columns:\n      - name: order_id\n        data_type: varchar\n      - name: gross_amount\n        data_type: decimal(18,2)\n      # Altered type: FLOAT replaced with exact high-precision DECIMAL(18,2)\n      - name: discount_amount\n        data_type: decimal(18,2) # Previously float64`,\n    remediationDdl: `-- Model Migration Patch for dbt Intermediate Layers:\nALTER TABLE production_dw.analytics.fct_orders\n  ALTER COLUMN discount_amount SET DATA TYPE DECIMAL(18,2);`,\n    lineageNodes: [\n      {\n        id: 'node-orders-origin',\n        name: 'analytics.fct_orders',\n        layer: 'origin',\n        layerLabel: 'Warehouse Fact Table',\n        status: 'mutation',\n        statusLabel: 'Type Alteration (FLOAT -> DECIMAL)',\n        type: 'Snowflake Incremental',\n        description: 'Core financial transactions mart table receiving monetary precision fix.',\n        owner: '#finance-data',\n      },\n      {\n        id: 'node-orders-int-rev',\n        name: 'dbt.int_daily_revenue',\n        layer: 'transform',\n        layerLabel: 'dbt Intermediate Model',\n        status: 'impacted',\n        statusLabel: 'Impacted (Sum Float Warning)',\n        type: 'dbt Incremental Model',\n        description: 'Aggregates daily gross/net sales; needs explicit decimal cast in SUM expression.',\n        owner: '#data-eng',\n        runtime: '1m 18s',\n      },\n      {\n        id: 'node-orders-int-disc',\n        name: 'dbt.int_order_discounts',\n        layer: 'transform',\n        layerLabel: 'dbt Intermediate Model',\n        status: 'impacted',\n        statusLabel: 'Impacted (Join Key Precision)',\n        type: 'dbt View Model',\n        description: 'Promotional discount matrix model joined on discount_amount thresholds.',\n        owner: '#data-eng',\n        runtime: '45s',\n      },\n      {\n        id: 'node-orders-mart',\n        name: 'marts.fct_monthly_financials',\n        layer: 'mart',\n        layerLabel: 'Gold Financial Mart',\n        status: 'healthy',\n        statusLabel: 'Sanitized Output (Safe)',\n        type: 'Snowflake Mart Table',\n        description: 'GAAP revenue mart used for board reporting and audit ledger.',\n        owner: '#finance-ops',\n      },\n      {\n        id: 'node-orders-looker',\n        name: 'Looker ARR & Margin Dashboard',\n        layer: 'consumer',\n        layerLabel: 'Executive BI Dashboard',\n        status: 'warning',\n        statusLabel: '1 Tile Check Advised',\n        type: 'Looker Explore Tile',\n        description: 'C-Suite executive dashboard tracking daily net margin & discount rates.',\n        owner: '#bi-analytics',\n      },\n      {\n        id: 'node-orders-netsuite',\n        name: 'Finance NetSuite Journal Sync',\n        layer: 'consumer',\n        layerLabel: 'Accounting ERP Pipeline',\n        status: 'healthy',\n        statusLabel: 'Decimal Compatible (Safe)',\n        type: 'Census Batch Sync',\n        description: 'Hourly journal entry creation into Oracle NetSuite ERP general ledger.',\n        owner: '#accounting',\n      },\n    ],\n  },\n  {\n    id: 'drift-inc-3',\n    targetTable: 'kafka.events.checkout',\n    environment: 'Kafka Topics',\n    changeType: 'Nullability Relaxation',\n    driftDiff: 'zip_code became nullable',\n    diffMode: 'relaxed',\n    severity: 'low',\n    severityLabel: 'Low',\n    blastRadiusSummary: '0 broken',\n    brokenModelsCount: 0,\n    impactedPipelinesCount: 0,\n    detectedAt: '2h ago',\n    actionLabel: 'Add to Data Contract',\n    isAcknowledged: false,\n    isContractSynced: false,\n    contractYaml: `version: 2\nsources:\n  - name: kafka_stream\n    tables:\n      - name: events_checkout\n        columns:\n          - name: session_id\n            data_type: varchar\n          # Nullability relaxed for international orders lacking postal codes\n          - name: zip_code\n            data_type: varchar(16)`,\n    remediationDdl: `-- Event Stream Deserialization Schema Update (Avro/JSON Schema Registry):\n{\n  \"name\": \"zip_code\",\n  \"type\": [\"null\", \"string\"],\n  \"default\": null\n}`,\n    lineageNodes: [\n      {\n        id: 'node-kafka-origin',\n        name: 'kafka.events.checkout',\n        layer: 'origin',\n        layerLabel: 'Event Stream Topic',\n        status: 'mutation',\n        statusLabel: 'Nullability Relaxed',\n        type: 'Kafka Partition Stream',\n        description: 'Real-time e-commerce checkout session payload stream.',\n        owner: '#checkout-squad',\n      },\n      {\n        id: 'node-kafka-flink',\n        name: 'flink.checkout_stream_enrichment',\n        layer: 'transform',\n        layerLabel: 'Flink Stream Processing',\n        status: 'healthy',\n        statusLabel: 'COALESCE Handler Active',\n        type: 'Apache Flink Job',\n        description: 'Streaming enrichment with geo-IP fallback when zip_code is null.',\n        owner: '#stream-eng',\n        runtime: '<500ms streaming',\n      },\n      {\n        id: 'node-kafka-mart',\n        name: 'analytics.fct_checkout_events',\n        layer: 'mart',\n        layerLabel: 'Realtime Bronze Table',\n        status: 'healthy',\n        statusLabel: 'Schema Compatible',\n        type: 'Snowflake Raw Event Table',\n        description: 'Append-only event log capturing checkout telemetry.',\n        owner: '#analytics-eng',\n      },\n      {\n        id: 'node-kafka-bi',\n        name: 'Realtime Checkout Conversion Board',\n        layer: 'consumer',\n        layerLabel: 'Operations Monitor',\n        status: 'healthy',\n        statusLabel: 'Active · 0 Failures',\n        type: 'Grafana Live Dashboard',\n        description: 'Ops NOC wallboard monitoring conversion rates per minute.',\n        owner: '#growth-team',\n      },\n    ],\n  },\n]\n\nconst ENVIRONMENTS = ['all', 'Snowflake Prod', 'Postgres OLTP', 'Kafka Topics']\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-schema-drift-alert-board, [ui-schema-drift-alert-board]',\n  standalone: true,\n  // React renders the root <div> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiCardDescriptionComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiProgressComponent,\n    UiSeparatorComponent,\n    UiTableBodyComponent,\n    UiTableCellComponent,\n    UiTableComponent,\n    UiTableHeadComponent,\n    UiTableHeaderComponent,\n    UiTableRowComponent,\n  ],\n  template: `\n    <div data-slot=\"schema-drift-alert-board\" [class]=\"rootClass\">\n      <!-- Header Section -->\n      <div ui-card class=\"border-border bg-card shadow-xs\">\n        <div ui-card-content class=\"p-5 sm:p-6\">\n          <div class=\"flex flex-col gap-5 lg:flex-row lg:items-center lg:justify-between\">\n            <div class=\"space-y-2\">\n              <div class=\"flex flex-wrap items-center gap-2\">\n                <div\n                  class=\"border-warning/30 bg-warning/10 text-warning flex size-9 shrink-0 items-center justify-center rounded-lg border shadow-xs\"\n                >\n                  <lucide-icon [img]=\"ShieldAlert\" class=\"size-4.5\" />\n                </div>\n                <div>\n                  <div class=\"flex flex-wrap items-center gap-2.5\">\n                    <h1 class=\"text-foreground font-mono text-lg font-bold tracking-tight break-all sm:text-xl\">\n                      {{ title() }}\n                    </h1>\n                    <span\n                      ui-badge\n                      [variant]=\"allAcknowledged() ? 'success' : 'warning'\"\n                      class=\"gap-1.5 px-2.5 py-0.5 font-mono text-xs font-semibold\"\n                    >\n                      @if (!allAcknowledged()) {\n                        <span class=\"relative flex size-2\">\n                          <span class=\"bg-warning absolute inline-flex size-full rounded-full opacity-75\"></span>\n                          <span class=\"bg-warning relative inline-flex size-2 rounded-full\"></span>\n                        </span>\n                      } @else {\n                        <lucide-icon [img]=\"CheckCircle2\" class=\"text-success size-3\" />\n                      }\n                      <span>{{ allAcknowledged() ? 'All Contracts Synced' : activeMutationsSummary() }}</span>\n                    </span>\n                  </div>\n                  <div class=\"text-muted-foreground flex flex-wrap items-center gap-2 pt-1 text-xs\">\n                    <span class=\"text-muted-foreground font-medium\">Monitored Environments:</span>\n                    <div class=\"flex flex-wrap items-center gap-1.5\">\n                      @for (env of monitoredEnvironments(); track env) {\n                        <span\n                          class=\"border-border bg-muted/60 text-foreground inline-flex items-center gap-1 rounded-md border px-2 py-0.5 font-mono text-xs\"\n                        >\n                          @if (env.includes('Snowflake')) {\n                            <lucide-icon [img]=\"Database\" class=\"text-info size-3\" />\n                          } @else if (env.includes('Postgres')) {\n                            <lucide-icon [img]=\"Layers\" class=\"text-chart-1 size-3\" />\n                          } @else {\n                            <lucide-icon [img]=\"Activity\" class=\"text-warning size-3\" />\n                          }\n                          {{ env }}\n                        </span>\n                      }\n                    </div>\n                  </div>\n                </div>\n              </div>\n            </div>\n\n            <div class=\"flex flex-wrap items-center gap-2.5\">\n              <button ui-button variant=\"outline\" size=\"sm\" [class]=\"muteClass\" (click)=\"handleToggleMute()\">\n                @if (isMutedNonBreaking()) {\n                  <lucide-icon [img]=\"BellOff\" class=\"size-3.5\" />\n                } @else {\n                  <lucide-icon [img]=\"BellRing\" class=\"size-3.5\" />\n                }\n                <span>{{ isMutedNonBreaking() ? 'Muted (Non-Breaking Hidden)' : 'Mute Non-Breaking Alerts' }}</span>\n              </button>\n\n              <button\n                ui-button\n                variant=\"default\"\n                size=\"sm\"\n                class=\"h-9 gap-1.5 text-xs font-semibold shadow-xs\"\n                [disabled]=\"isSyncingAll()\"\n                (click)=\"handleAcknowledgeAndSync()\"\n              >\n                <lucide-icon [img]=\"RefreshCw\" [class]=\"syncIconClass\" />\n                @if (allAcknowledged()) {\n                  <lucide-icon [img]=\"Check\" class=\"text-success size-3.5\" />\n                }\n                <span>{{ syncLabel() }}</span>\n              </button>\n            </div>\n          </div>\n        </div>\n\n        <div\n          class=\"border-border/80 bg-muted/30 text-muted-foreground flex flex-col gap-2 border-t px-5 py-2.5 text-xs sm:flex-row sm:items-center sm:justify-between\"\n        >\n          <div class=\"flex items-center gap-2 font-mono\">\n            <span class=\"bg-success size-2 rounded-full\"></span>\n            <span>Realtime Schema Contract Gate: Active (CDC Triggers & dbt Artifact Audits)</span>\n          </div>\n          <div class=\"flex items-center gap-3\">\n            <span\n              >Detection Engine:\n              <strong class=\"text-foreground font-mono font-medium\">UIPKGE Drift Sentinel v2.4</strong></span\n            >\n            <ui-separator orientation=\"vertical\" class=\"hidden h-3 sm:block\" />\n            <span class=\"font-mono\">Checked 14s ago</span>\n          </div>\n        </div>\n      </div>\n\n      <!-- 4 Drift Telemetry Metric Cards -->\n      <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n        <div ui-card class=\"border-border bg-card hover:border-border shadow-xs transition-colors\">\n          <div ui-card-header class=\"p-4 pb-2\">\n            <div class=\"flex flex-wrap items-start justify-between gap-2\">\n              <p class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Active Drift Incidents</p>\n              <div\n                class=\"border-warning/20 bg-warning/10 text-warning flex size-7 items-center justify-center rounded-md border\"\n              >\n                <lucide-icon [img]=\"AlertTriangle\" class=\"size-4\" />\n              </div>\n            </div>\n            <div class=\"flex items-baseline gap-2 pt-1\">\n              <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\"\n                >2 Anomalies Active</span\n              >\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-2 p-4 pt-1\">\n            <div class=\"bg-muted/40 flex items-center justify-between rounded-md px-2 py-1 text-xs\">\n              <span class=\"text-muted-foreground\">Severity Split</span>\n              <span class=\"text-foreground font-mono font-medium\">1 Warning · 1 Low</span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">2 Active Schema Mutations Detected</p>\n          </div>\n        </div>\n\n        <div ui-card class=\"border-border bg-card hover:border-border shadow-xs transition-colors\">\n          <div ui-card-header class=\"p-4 pb-2\">\n            <div class=\"flex flex-wrap items-start justify-between gap-2\">\n              <p class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Broken Downstream Models</p>\n              <div\n                class=\"border-success/20 bg-success/10 text-success flex size-7 items-center justify-center rounded-md border\"\n              >\n                <lucide-icon [img]=\"ShieldCheck\" class=\"size-4\" />\n              </div>\n            </div>\n            <div class=\"flex items-baseline gap-2 pt-1\">\n              <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\"\n                >0 Broken Models</span\n              >\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-2 p-4 pt-1\">\n            <div class=\"bg-muted/40 flex items-center justify-between rounded-md px-2 py-1 text-xs\">\n              <span class=\"text-muted-foreground\">Impacted Pipelines</span>\n              <span class=\"text-warning font-mono font-medium\">2 Impacted Pipelines</span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">Zero outages · 100% DAG pipeline uptime maintained</p>\n          </div>\n        </div>\n\n        <div ui-card class=\"border-border bg-card hover:border-border shadow-xs transition-colors\">\n          <div ui-card-header class=\"p-4 pb-2\">\n            <div class=\"flex flex-wrap items-start justify-between gap-2\">\n              <p class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Schema Audits in 24h</p>\n              <div\n                class=\"border-border bg-muted text-foreground flex size-7 items-center justify-center rounded-md border\"\n              >\n                <lucide-icon [img]=\"Activity\" class=\"text-info size-4\" />\n              </div>\n            </div>\n            <div class=\"flex items-baseline gap-2 pt-1\">\n              <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">1,840</span>\n              <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">100% evaluated</span>\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-2 p-4 pt-1\">\n            <ui-progress [value]=\"100\" class=\"h-1.5 w-full\" />\n            <p class=\"text-muted-foreground text-xs\">Continuous CDC & dbt schema contract verification</p>\n          </div>\n        </div>\n\n        <div ui-card class=\"border-border bg-card hover:border-border shadow-xs transition-colors\">\n          <div ui-card-header class=\"p-4 pb-2\">\n            <div class=\"flex flex-wrap items-start justify-between gap-2\">\n              <p class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Mean Time to Acknowledge</p>\n              <div\n                class=\"border-chart-2/20 bg-chart-2/10 text-chart-2 flex size-7 items-center justify-center rounded-md border\"\n              >\n                <lucide-icon [img]=\"Clock\" class=\"size-4\" />\n              </div>\n            </div>\n            <div class=\"flex items-baseline gap-2 pt-1\">\n              <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">12m</span>\n              <span ui-badge variant=\"success\" class=\"text-xs font-medium\">-4.2m vs 30d</span>\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-2 p-4 pt-1\">\n            <div class=\"bg-muted/40 flex items-center justify-between rounded-md px-2 py-1 text-xs\">\n              <span class=\"text-muted-foreground\">SLA Compliance</span>\n              <span class=\"text-success font-mono font-medium\">98.4% within SLA</span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">Target &lt; 30m response for Tier-1 Gold Marts</p>\n          </div>\n        </div>\n      </div>\n\n      <!-- Schema Drift Incidents Table Card -->\n      <div ui-card class=\"border-border bg-card shadow-xs\">\n        <div ui-card-header class=\"flex flex-col gap-4 pb-3 sm:flex-row sm:items-center sm:justify-between\">\n          <div>\n            <div class=\"flex items-center gap-2\">\n              <h3 ui-card-title class=\"text-base font-semibold\">Schema Drift & Mutation Incidents</h3>\n              <span ui-badge variant=\"secondary\" class=\"font-mono text-xs\">\n                {{ filteredIncidents().length }} of {{ incidentsList().length }} Tracked\n              </span>\n            </div>\n            <p ui-card-description class=\"text-xs\">\n              Detected structural schema variances, missing or unmapped columns, type widening, and nullability\n              relaxations.\n            </p>\n          </div>\n\n          <div class=\"flex flex-wrap items-center gap-1.5\">\n            <button\n              ui-button\n              variant=\"outline\"\n              size=\"xs\"\n              [class]=\"sevPillClass('all')\"\n              (click)=\"selectedSeverity.set('all')\"\n            >\n              All Severities ({{ incidentsList().length }})\n            </button>\n            <button\n              ui-button\n              variant=\"outline\"\n              size=\"xs\"\n              [class]=\"sevPillClass('medium')\"\n              (click)=\"selectedSeverity.set('medium')\"\n            >\n              Medium Warning (1)\n            </button>\n            <button\n              ui-button\n              variant=\"outline\"\n              size=\"xs\"\n              [class]=\"sevPillClass('low')\"\n              (click)=\"selectedSeverity.set('low')\"\n            >\n              Low / Non-Breaking (2)\n            </button>\n          </div>\n        </div>\n\n        <div class=\"border-border/60 border-t p-4 pt-3 pb-3\">\n          <div class=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n            <div class=\"relative flex-1\">\n              <lucide-icon\n                [img]=\"Search\"\n                class=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-3.5 -translate-y-1/2\"\n              />\n              <input\n                [value]=\"searchQuery()\"\n                (input)=\"searchQuery.set($any($event.target).value)\"\n                type=\"text\"\n                placeholder=\"Search table, column, environment, or mutation diff...\"\n                class=\"border-border bg-background placeholder:text-muted-foreground focus-visible:ring-ring h-8.5 w-full rounded-md border px-3 pl-8 text-xs focus-visible:ring-2 focus-visible:outline-none\"\n              />\n            </div>\n\n            <div class=\"flex flex-wrap items-center gap-1.5\">\n              <span class=\"text-muted-foreground mr-1 flex items-center gap-1 text-xs font-medium\">\n                <lucide-icon [img]=\"Filter\" class=\"size-3\" />\n                <span>Environment:</span>\n              </span>\n              @for (env of envOptions; track env) {\n                <button\n                  ui-button\n                  variant=\"outline\"\n                  size=\"xs\"\n                  [class]=\"envPillClass(env)\"\n                  (click)=\"selectedEnvironment.set(env)\"\n                >\n                  {{ env === 'all' ? 'All Environments' : env }}\n                </button>\n              }\n            </div>\n          </div>\n        </div>\n\n        <div ui-card-content class=\"p-0\">\n          <div class=\"border-border/60 overflow-x-auto border-t\">\n            <table ui-table>\n              <thead ui-table-header class=\"bg-muted/40\">\n                <tr ui-table-row>\n                  <th ui-table-head class=\"min-w-[200px] text-xs font-semibold\">Target Entity & Env</th>\n                  <th ui-table-head class=\"min-w-[170px] text-xs font-semibold\">Mutation Type</th>\n                  <th ui-table-head class=\"min-w-[260px] text-xs font-semibold\">Schema Drift Diff</th>\n                  <th ui-table-head class=\"min-w-[130px] text-xs font-semibold\">Severity</th>\n                  <th ui-table-head class=\"min-w-[140px] text-xs font-semibold\">Blast Radius</th>\n                  <th ui-table-head class=\"min-w-[90px] text-xs font-semibold\">Detected</th>\n                  <th ui-table-head class=\"min-w-[160px] text-right text-xs font-semibold\">Action</th>\n                </tr>\n              </thead>\n              <tbody ui-table-body>\n                @for (incident of filteredIncidents(); track incident.id) {\n                  <tr ui-table-row [class]=\"rowClass(incident.id)\" (click)=\"selectedIncidentId.set(incident.id)\">\n                    <td ui-table-cell class=\"py-3\">\n                      <div class=\"space-y-1\">\n                        <div class=\"text-foreground flex items-center gap-1.5 font-mono text-xs font-bold\">\n                          @if (incident.environment.includes('Snowflake')) {\n                            <lucide-icon [img]=\"Database\" class=\"text-info size-3.5 shrink-0\" />\n                          } @else if (incident.environment.includes('Postgres')) {\n                            <lucide-icon [img]=\"Layers\" class=\"text-chart-1 size-3.5 shrink-0\" />\n                          } @else {\n                            <lucide-icon [img]=\"Activity\" class=\"text-warning size-3.5 shrink-0\" />\n                          }\n                          <span>{{ incident.targetTable }}</span>\n                        </div>\n                        <span\n                          ui-badge\n                          variant=\"outline\"\n                          class=\"border-border/80 text-muted-foreground font-mono text-xs font-normal\"\n                        >\n                          {{ incident.environment }}\n                        </span>\n                      </div>\n                    </td>\n                    <td ui-table-cell class=\"py-3\">\n                      <span class=\"text-foreground text-xs font-medium\">{{ incident.changeType }}</span>\n                    </td>\n                    <td ui-table-cell class=\"py-3\">\n                      <div [class]=\"diffClass(incident.diffMode)\">\n                        <code>{{ incident.driftDiff }}</code>\n                      </div>\n                    </td>\n                    <td ui-table-cell class=\"py-3\">\n                      <span\n                        ui-badge\n                        [variant]=\"incident.severity === 'medium' ? 'warning' : 'secondary'\"\n                        class=\"gap-1 text-xs font-medium\"\n                      >\n                        @if (incident.severity === 'medium') {\n                          <lucide-icon [img]=\"AlertTriangle\" class=\"text-warning size-3\" />\n                        } @else {\n                          <lucide-icon [img]=\"AlertCircle\" class=\"text-info size-3\" />\n                        }\n                        <span>{{ incident.severityLabel }}</span>\n                      </span>\n                    </td>\n                    <td ui-table-cell class=\"py-3\">\n                      <div class=\"space-y-0.5\">\n                        <span [class]=\"blastClass(incident.impactedPipelinesCount)\">\n                          {{ incident.blastRadiusSummary }}\n                        </span>\n                        <span class=\"text-muted-foreground text-xs\">\n                          {{ incident.brokenModelsCount }} broken · {{ incident.impactedPipelinesCount }} impacted\n                        </span>\n                      </div>\n                    </td>\n                    <td ui-table-cell class=\"text-muted-foreground py-3 font-mono text-xs\">\n                      {{ incident.detectedAt }}\n                    </td>\n                    <td ui-table-cell class=\"py-3 text-right\">\n                      <button\n                        ui-button\n                        variant=\"outline\"\n                        size=\"xs\"\n                        [class]=\"actionClass(incident.isContractSynced)\"\n                        (click)=\"handleRowAction(incident, $event)\"\n                      >\n                        @if (incident.isContractSynced) {\n                          <lucide-icon [img]=\"Check\" class=\"size-3\" />\n                        } @else if (incident.changeType === 'Data Type Alteration') {\n                          <lucide-icon [img]=\"Eye\" class=\"text-primary size-3\" />\n                        } @else {\n                          <lucide-icon [img]=\"Workflow\" class=\"size-3\" />\n                        }\n                        <span>{{ incident.isContractSynced ? 'Contract Synced' : incident.actionLabel }}</span>\n                      </button>\n                    </td>\n                  </tr>\n                }\n                @if (filteredIncidents().length === 0) {\n                  <tr ui-table-row>\n                    <td ui-table-cell [attr.colspan]=\"7\" class=\"py-8 text-center\">\n                      <div class=\"flex flex-col items-center justify-center gap-1.5\">\n                        <lucide-icon [img]=\"CheckCircle2\" class=\"text-success size-7\" />\n                        <p class=\"text-foreground text-sm font-medium\">\n                          No schema drift incidents match active filters\n                        </p>\n                        <p class=\"text-muted-foreground text-xs\">\n                          All active monitored entities adhere strictly to baseline contracts.\n                        </p>\n                      </div>\n                    </td>\n                  </tr>\n                }\n              </tbody>\n            </table>\n          </div>\n\n          <div\n            class=\"border-border/60 bg-muted/20 text-muted-foreground flex flex-col gap-2 border-t px-4 py-2.5 text-xs sm:flex-row sm:items-center sm:justify-between\"\n          >\n            <div class=\"flex items-center gap-2\">\n              <span class=\"bg-success size-2 rounded-full\"></span>\n              <span>Click any incident row to trace downstream blast radius lineage and contract YAML.</span>\n            </div>\n            <span class=\"font-mono text-xs\">\n              Active Incident Focus:\n              <strong class=\"text-foreground font-bold\">{{ selectedIncident().targetTable }}</strong>\n            </span>\n          </div>\n        </div>\n      </div>\n\n      <!-- Blast Radius Lineage Tree Card -->\n      <div ui-card class=\"border-border bg-card shadow-xs\">\n        <div ui-card-header class=\"border-border/80 border-b p-4 sm:p-5\">\n          <div class=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n            <div class=\"space-y-1\">\n              <div class=\"flex flex-wrap items-center gap-2\">\n                <lucide-icon [img]=\"Workflow\" class=\"text-primary size-5\" />\n                <h3 ui-card-title class=\"text-base font-semibold\">Downstream Blast Radius & Lineage Impact Tree</h3>\n                <span ui-badge variant=\"outline\" class=\"font-mono text-xs font-semibold\">\n                  {{ selectedIncident().targetTable }}\n                </span>\n                <span\n                  ui-badge\n                  [variant]=\"selectedIncident().severity === 'medium' ? 'warning' : 'secondary'\"\n                  class=\"font-mono text-xs\"\n                >\n                  {{ selectedIncident().changeType }}\n                </span>\n              </div>\n              <p ui-card-description class=\"text-xs\">\n                Automated topological DAG trace evaluating impacted dbt models, Snowflake views, Looker semantic tiles,\n                and operational syncs.\n              </p>\n            </div>\n\n            <div class=\"flex flex-wrap items-center gap-1.5\">\n              <button\n                ui-button\n                variant=\"outline\"\n                size=\"sm\"\n                [class]=\"tabClass('lineage')\"\n                (click)=\"activeTab.set('lineage')\"\n              >\n                <lucide-icon [img]=\"Network\" class=\"size-3.5\" />\n                <span>Lineage Tree</span>\n              </button>\n              <button ui-button variant=\"outline\" size=\"sm\" [class]=\"tabClass('yaml')\" (click)=\"activeTab.set('yaml')\">\n                <lucide-icon [img]=\"FileCode2\" class=\"size-3.5\" />\n                <span>Contract YAML Diff</span>\n              </button>\n              <button ui-button variant=\"outline\" size=\"sm\" [class]=\"tabClass('sql')\" (click)=\"activeTab.set('sql')\">\n                <lucide-icon [img]=\"Terminal\" class=\"size-3.5\" />\n                <span>Remediation DDL</span>\n              </button>\n            </div>\n          </div>\n        </div>\n\n        <div ui-card-content class=\"p-4 sm:p-5\">\n          @if (activeTab() === 'lineage') {\n            <div class=\"space-y-4\">\n              <div class=\"grid grid-cols-2 gap-2.5 sm:grid-cols-4\">\n                <div class=\"border-border/80 bg-muted/30 space-y-1 rounded-lg border p-3 text-xs\">\n                  <span class=\"text-muted-foreground block\">Mutation Origin</span>\n                  <span class=\"text-foreground block truncate font-mono font-bold\">{{\n                    selectedIncident().targetTable\n                  }}</span>\n                  <span class=\"text-muted-foreground text-xs\">{{ selectedIncident().environment }}</span>\n                </div>\n                <div class=\"border-border/80 bg-muted/30 space-y-1 rounded-lg border p-3 text-xs\">\n                  <span class=\"text-muted-foreground block\">Total Nodes in DAG</span>\n                  <span class=\"text-foreground block font-mono text-base font-bold\"\n                    >{{ selectedIncident().lineageNodes.length }} Tiers</span\n                  >\n                  <span class=\"text-muted-foreground text-xs\">Topologically ordered</span>\n                </div>\n                <div class=\"border-border/80 bg-muted/30 space-y-1 rounded-lg border p-3 text-xs\">\n                  <span class=\"text-muted-foreground block\">Impacted Pipelines</span>\n                  <span [class]=\"impactedClass(selectedIncident().impactedPipelinesCount)\">\n                    {{ selectedIncident().impactedPipelinesCount }} Models Impacted\n                  </span>\n                  <span class=\"text-muted-foreground text-xs\">Requires cast adjustment</span>\n                </div>\n                <div class=\"border-border/80 bg-muted/30 space-y-1 rounded-lg border p-3 text-xs\">\n                  <span class=\"text-muted-foreground block\">Broken Models</span>\n                  <span class=\"text-success block font-mono text-base font-bold\">0 Outages</span>\n                  <span class=\"text-muted-foreground text-xs\">Zero pipeline failures</span>\n                </div>\n              </div>\n\n              <div class=\"border-border bg-muted/10 space-y-3 rounded-xl border p-4\">\n                <div class=\"border-border/60 flex items-center justify-between border-b pb-2 text-xs\">\n                  <span class=\"text-muted-foreground font-semibold tracking-wider uppercase\">\n                    Downstream Dependency DAG Flow (Left to Right)\n                  </span>\n                  <span class=\"text-muted-foreground font-mono text-xs\">\n                    Active Drift: <code class=\"text-foreground font-bold\">{{ selectedIncident().driftDiff }}</code>\n                  </span>\n                </div>\n\n                <div class=\"grid grid-cols-1 gap-3 md:grid-cols-2 xl:grid-cols-3\">\n                  @for (node of selectedIncident().lineageNodes; track node.id; let i = $index) {\n                    <div [class]=\"nodeCardClass(node.status)\">\n                      <div class=\"flex flex-wrap items-start justify-between gap-2\">\n                        <div class=\"flex min-w-0 items-center gap-2\">\n                          <div [class]=\"nodeIconClass(node.status)\">\n                            @if (node.layer === 'origin') {\n                              <lucide-icon [img]=\"Database\" class=\"size-3.5\" />\n                            } @else if (node.layer === 'transform') {\n                              <lucide-icon [img]=\"Layers\" class=\"size-3.5\" />\n                            } @else if (node.layer === 'mart') {\n                              <lucide-icon [img]=\"Table2\" class=\"size-3.5\" />\n                            } @else {\n                              <lucide-icon [img]=\"ArrowUpRight\" class=\"size-3.5\" />\n                            }\n                          </div>\n                          <div class=\"min-w-0\">\n                            <div class=\"flex items-center gap-1.5\">\n                              <span class=\"text-muted-foreground font-mono text-xs\">#{{ i + 1 }}</span>\n                              <span class=\"text-foreground block min-w-0 truncate font-mono font-bold\">{{\n                                node.name\n                              }}</span>\n                            </div>\n                            <span class=\"text-muted-foreground block truncate text-xs\">{{ node.layerLabel }}</span>\n                          </div>\n                        </div>\n                        <span\n                          ui-badge\n                          [variant]=\"nodeBadgeVariant(node.status)\"\n                          class=\"shrink-0 font-mono text-xs font-medium\"\n                        >\n                          @if (node.status === 'healthy') {\n                            <lucide-icon [img]=\"CheckCircle2\" class=\"text-success size-3\" />\n                          } @else {\n                            <lucide-icon [img]=\"AlertTriangle\" class=\"size-3\" />\n                          }\n                          <span>{{ node.statusLabel }}</span>\n                        </span>\n                      </div>\n                      <p class=\"text-muted-foreground text-xs leading-relaxed\">{{ node.description }}</p>\n                      <div\n                        class=\"border-border/60 text-muted-foreground flex items-center justify-between border-t pt-2 font-mono text-xs\"\n                      >\n                        <span>{{ node.type }}</span>\n                        <span>{{ node.owner }}</span>\n                      </div>\n                    </div>\n                  }\n                </div>\n              </div>\n            </div>\n          } @else if (activeTab() === 'yaml') {\n            <div class=\"space-y-3\">\n              <div class=\"flex items-center justify-between\">\n                <div class=\"flex items-center gap-2\">\n                  <lucide-icon [img]=\"FileCode2\" class=\"text-primary size-4\" />\n                  <span class=\"text-foreground font-mono text-xs font-semibold\">\n                    models/contracts/{{ selectedIncident().targetTable.replace('.', '_') }}_contract.yml\n                  </span>\n                  <span ui-badge variant=\"secondary\" class=\"font-mono text-xs\">dbt v1.8 Contract Definition</span>\n                </div>\n                <button\n                  ui-button\n                  variant=\"ghost\"\n                  size=\"xs\"\n                  class=\"h-7 gap-1 text-xs\"\n                  (click)=\"copyCode('yaml', selectedIncident().contractYaml)\"\n                >\n                  @if (copiedKey() === 'yaml') {\n                    <lucide-icon [img]=\"Check\" class=\"text-success size-3\" />\n                  } @else {\n                    <lucide-icon [img]=\"Copy\" class=\"size-3\" />\n                  }\n                  <span>{{ copiedKey() === 'yaml' ? 'Copied YAML!' : 'Copy YAML Contract' }}</span>\n                </button>\n              </div>\n              <div\n                class=\"border-border overflow-x-auto rounded-lg border bg-neutral-950 p-4 font-mono text-xs leading-relaxed text-neutral-100 dark:bg-neutral-950\"\n              >\n                <pre class=\"whitespace-pre\"><code>{{ selectedIncident().contractYaml }}</code></pre>\n              </div>\n            </div>\n          } @else {\n            <div class=\"space-y-3\">\n              <div class=\"flex items-center justify-between\">\n                <div class=\"flex items-center gap-2\">\n                  <lucide-icon [img]=\"Terminal\" class=\"text-primary size-4\" />\n                  <span class=\"text-foreground font-mono text-xs font-semibold\">\n                    remediation_migration_{{ selectedIncident().targetTable.replace('.', '_') }}.sql\n                  </span>\n                  <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">Warehouse DDL Patch</span>\n                </div>\n                <button\n                  ui-button\n                  variant=\"ghost\"\n                  size=\"xs\"\n                  class=\"h-7 gap-1 text-xs\"\n                  (click)=\"copyCode('sql', selectedIncident().remediationDdl)\"\n                >\n                  @if (copiedKey() === 'sql') {\n                    <lucide-icon [img]=\"Check\" class=\"text-success size-3\" />\n                  } @else {\n                    <lucide-icon [img]=\"Copy\" class=\"size-3\" />\n                  }\n                  <span>{{ copiedKey() === 'sql' ? 'Copied SQL!' : 'Copy Migration SQL' }}</span>\n                </button>\n              </div>\n              <div\n                class=\"border-border overflow-x-auto rounded-lg border bg-neutral-950 p-4 font-mono text-xs leading-relaxed text-neutral-100 dark:bg-neutral-950\"\n              >\n                <pre class=\"whitespace-pre\"><code>{{ selectedIncident().remediationDdl }}</code></pre>\n              </div>\n            </div>\n          }\n        </div>\n      </div>\n    </div>\n  `,\n})\nexport class UiSchemaDriftAlertBoardComponent {\n  protected readonly Activity = Activity\n  protected readonly AlertCircle = AlertCircle\n  protected readonly AlertTriangle = AlertTriangle\n  protected readonly ArrowUpRight = ArrowUpRight\n  protected readonly BellOff = BellOff\n  protected readonly BellRing = BellRing\n  protected readonly Check = Check\n  protected readonly CheckCircle2 = CheckCircle2\n  protected readonly Clock = Clock\n  protected readonly Copy = Copy\n  protected readonly Database = Database\n  protected readonly Eye = Eye\n  protected readonly FileCode2 = FileCode2\n  protected readonly Filter = Filter\n  protected readonly Layers = Layers\n  protected readonly Network = Network\n  protected readonly RefreshCw = RefreshCw\n  protected readonly Search = Search\n  protected readonly ShieldAlert = ShieldAlert\n  protected readonly ShieldCheck = ShieldCheck\n  protected readonly Table2 = Table2\n  protected readonly Terminal = Terminal\n  protected readonly Workflow = Workflow\n\n  protected readonly envOptions = ENVIRONMENTS\n\n  @Input('title') set titleInput(v: string | undefined) {\n    this.title.set(v ?? 'Data Warehouse Schema Drift & Anomaly Alerts')\n  }\n  @Input('monitoredEnvironments') set monitoredEnvironmentsInput(v: string[] | undefined) {\n    this.monitoredEnvironments.set(v ?? ['Snowflake Prod', 'Postgres OLTP', 'Kafka Topics'])\n  }\n  @Input() set incidents(v: SchemaDriftIncident[] | undefined) {\n    this.incidentsList.set(\n      (v ?? defaultIncidents).map((i) => ({ ...i, lineageNodes: i.lineageNodes.map((n) => ({ ...n })) })),\n    )\n  }\n  @Input() set initialSelectedIncident(v: string | undefined) {\n    if (v) this.selectedIncidentId.set(v)\n  }\n  @Input('class') className?: string\n\n  readonly title = signal('Data Warehouse Schema Drift & Anomaly Alerts')\n  readonly monitoredEnvironments = signal<string[]>(['Snowflake Prod', 'Postgres OLTP', 'Kafka Topics'])\n  readonly incidentsList = signal<SchemaDriftIncident[]>(\n    defaultIncidents.map((i) => ({ ...i, lineageNodes: i.lineageNodes.map((n) => ({ ...n })) })),\n  )\n\n  readonly selectedIncidentId = signal('drift-inc-2')\n  readonly searchQuery = signal('')\n  readonly selectedEnvironment = signal('all')\n  readonly selectedSeverity = signal('all')\n  readonly isMutedNonBreaking = signal(false)\n  readonly isSyncingAll = signal(false)\n  readonly allAcknowledged = signal(false)\n  readonly copiedKey = signal<string | null>(null)\n  readonly activeTab = signal<'lineage' | 'yaml' | 'sql'>('lineage')\n\n  readonly selectedIncident = computed(() => {\n    const list = this.incidentsList()\n    return list.find((inc) => inc.id === this.selectedIncidentId()) ?? list[0]!\n  })\n\n  readonly filteredIncidents = computed(() => {\n    const query = this.searchQuery().trim().toLowerCase()\n    const env = this.selectedEnvironment()\n    const sev = this.selectedSeverity()\n    const muted = this.isMutedNonBreaking()\n    return this.incidentsList().filter((item) => {\n      if (muted && item.severity === 'low') return false\n      if (env !== 'all' && item.environment !== env) return false\n      if (sev !== 'all' && item.severity !== sev) return false\n      if (\n        query &&\n        !item.targetTable.toLowerCase().includes(query) &&\n        !item.changeType.toLowerCase().includes(query) &&\n        !item.driftDiff.toLowerCase().includes(query) &&\n        !item.environment.toLowerCase().includes(query)\n      )\n        return false\n      return true\n    })\n  })\n\n  readonly activeMutationsSummary = computed(() => {\n    const unacknowledged = this.incidentsList().filter((i) => !i.isAcknowledged)\n    return `${unacknowledged.length} Active Schema Mutations Detected`\n  })\n\n  get rootClass(): string {\n    return cn('text-foreground w-full space-y-6', this.className)\n  }\n\n  get muteClass(): string {\n    return cn(\n      'h-9 gap-1.5 text-xs shadow-xs',\n      this.isMutedNonBreaking() && 'border-warning/40 bg-warning/10 text-warning font-medium',\n    )\n  }\n\n  get syncIconClass(): string {\n    return cn('size-3.5', this.isSyncingAll() && 'animate-spin')\n  }\n\n  syncLabel(): string {\n    if (this.isSyncingAll()) return 'Syncing Schema Contracts...'\n    if (this.allAcknowledged()) return 'Contracts Synced & Locked'\n    return 'Acknowledge & Sync Contracts'\n  }\n\n  sevPillClass(sev: string): string {\n    if (this.selectedSeverity() !== sev) return 'h-7 rounded-full text-xs'\n    if (sev === 'medium') return cn('h-7 rounded-full text-xs', 'border-warning bg-warning font-medium text-white')\n    if (sev === 'low') return cn('h-7 rounded-full text-xs', 'border-info bg-info font-medium text-white')\n    return cn('h-7 rounded-full text-xs', 'border-primary bg-primary text-primary-foreground font-medium')\n  }\n\n  envPillClass(env: string): string {\n    return cn(\n      'h-7 font-mono text-xs',\n      this.selectedEnvironment() === env && 'border-foreground bg-foreground text-background font-semibold',\n    )\n  }\n\n  rowClass(id: string): string {\n    return cn(\n      'hover:bg-muted/30 cursor-pointer transition-colors',\n      this.selectedIncidentId() === id && 'bg-primary/5 ring-primary/20 ring-1',\n    )\n  }\n\n  diffClass(mode: SchemaDriftIncident['diffMode']): string {\n    return cn(\n      'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 font-mono text-xs font-medium',\n      mode === 'added' && 'border-success/30 bg-success/10 text-success',\n      mode === 'altered' && 'border-warning/30 bg-warning/10 text-warning',\n      mode === 'relaxed' && 'border-info/30 bg-info/10 text-info',\n    )\n  }\n\n  blastClass(impacted: number): string {\n    return cn('block font-mono text-xs font-medium', impacted > 0 ? 'text-warning font-semibold' : 'text-success')\n  }\n\n  impactedClass(impacted: number): string {\n    return cn('block font-mono text-base font-bold', impacted > 0 ? 'text-warning' : 'text-success')\n  }\n\n  actionClass(synced: boolean): string {\n    return cn('h-7 gap-1 text-xs font-medium shadow-xs', synced && 'border-success/40 bg-success/10 text-success')\n  }\n\n  tabClass(tab: 'lineage' | 'yaml' | 'sql'): string {\n    return cn(\n      'h-8 gap-1.5 text-xs',\n      this.activeTab() === tab && 'border-primary bg-primary/10 text-primary font-semibold',\n    )\n  }\n\n  nodeCardClass(status: BlastRadiusNode['status']): string {\n    return cn(\n      'space-y-2 rounded-lg border p-3 text-xs shadow-xs transition-colors',\n      status === 'mutation' && 'border-warning/40 bg-warning/5',\n      status === 'impacted' && 'border-warning/50 bg-warning/10 ring-warning/30 ring-1',\n      status === 'warning' && 'border-yellow-500/40 bg-yellow-500/5',\n      status === 'healthy' && 'border-border bg-card',\n    )\n  }\n\n  nodeIconClass(status: BlastRadiusNode['status']): string {\n    return cn(\n      'flex size-7 shrink-0 items-center justify-center rounded-md border text-xs',\n      status === 'mutation' && 'border-warning/30 bg-warning/20 text-warning',\n      status === 'impacted' && 'border-warning/40 bg-warning/20 text-warning',\n      status === 'warning' && 'border-yellow-500/30 bg-yellow-500/20 text-yellow-600 dark:text-yellow-400',\n      status === 'healthy' && 'border-border bg-muted text-foreground',\n    )\n  }\n\n  nodeBadgeVariant(status: BlastRadiusNode['status']): 'outline' | 'secondary' | 'warning' {\n    if (status === 'healthy') return 'outline'\n    if (status === 'warning') return 'secondary'\n    return 'warning'\n  }\n\n  handleAcknowledgeAndSync(): void {\n    if (this.isSyncingAll()) return\n    this.isSyncingAll.set(true)\n    setTimeout(() => {\n      this.incidentsList.update((prev) =>\n        prev.map((item) => ({ ...item, isAcknowledged: true, isContractSynced: true })),\n      )\n      this.isSyncingAll.set(false)\n      this.allAcknowledged.set(true)\n    }, 900)\n  }\n\n  handleToggleMute(): void {\n    this.isMutedNonBreaking.update((v) => !v)\n  }\n\n  handleRowAction(incident: SchemaDriftIncident, event: MouseEvent): void {\n    event.stopPropagation()\n    this.selectedIncidentId.set(incident.id)\n    if (incident.changeType === 'Data Type Alteration') {\n      this.activeTab.set('lineage')\n    } else {\n      this.incidentsList.update((prev) =>\n        prev.map((item) =>\n          item.id === incident.id ? { ...item, isContractSynced: !item.isContractSynced, isAcknowledged: true } : item,\n        ),\n      )\n    }\n  }\n\n  copyCode(key: string, code: string): void {\n    try {\n      navigator.clipboard.writeText(code)\n      this.copiedKey.set(key)\n      setTimeout(() => {\n        if (this.copiedKey() === key) this.copiedKey.set(null)\n      }, 2000)\n    } catch {\n      // Clipboard unavailable in this context.\n    }\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/schema-drift-alert-board/schema-drift-alert-board.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/schema-drift-alert-board/index.ts",
      "content": "export {\n  UiSchemaDriftAlertBoardComponent,\n  type BlastRadiusNode,\n  type SchemaDriftIncident,\n} from './schema-drift-alert-board.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/schema-drift-alert-board/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/progress.json",
    "https://uipkge.dev/r/angular/separator.json",
    "https://uipkge.dev/r/angular/table.json"
  ],
  "description": "Automated data warehouse schema drift and structural anomaly detector with downstream blast radius impact analysis, interactive multi-tier lineage graph, schema mutation contract diffs, and remediation workflows.",
  "categories": [
    "devops",
    "dashboard",
    "app",
    "analytics",
    "data"
  ]
}