-- ADR-090: 監控盲區治理 + 資產盤點 × 7 項自動化覆蓋矩陣永久化 DB
-- 建立時間: 2026-04-18 下午 (台北時區)
-- 建立者: ogt + Claude Opus 4.7 (1M context)（亞太）
--
-- 上游:
--   - 主戰略: docs/superpowers/specs/2026-04-18-blindspot-governance-capacity-l4.md §5.2
--   - ADR: docs/adr/ADR-090-monitoring-blindspot-governance.md
--   - MEMORY: project_blindspot_governance.md
--
-- 設計說明:
--   本檔建立 11 張表作為 AWOOOI L4 AIOps 的資產盤點 + 自動化覆蓋 + AI 協作稽核地基。
--   目標: 把治理從 Markdown 搬進 PostgreSQL，讓 AI 四分工 (OpenClaw × NemoTron ×
--         Hermes × Claude LLM) 在結構化資料上做決策，且每次動作必留 trail。
--
--   對應七大自動化引擎:
--     E1 自動監控 / E2 自動告警 / E3 自動建規則 / E4 自動匹配
--     E5 自動 Playbook / E6 自動修復 / E7 自動 KM
--
-- 執行順序:
--   Step 0: pgcrypto extension (gen_random_uuid 需要)
--   Step 1:  asset_inventory         — 全景資產主表
--   Step 2:  asset_discovery_run     — 每次盤點 header
--   Step 3:  asset_coverage_snapshot — 資產 × 7 自動化覆蓋矩陣
--   Step 4:  asset_relationship      — 資產依賴圖 (爆炸半徑)
--   Step 5:  alert_rule_catalog      — 告警規則本身即資產
--   Step 6:  asset_change_event      — 資產變化追蹤
--   Step 7:  asset_compliance_snapshot — SSL/CVE/secret/backup 合規
--   Step 8:  host_capacity_snapshot  — 主機容量快照 (NemoTron 每日 02:00 寫)
--   Step 9:  capacity_violation_event — 配額違規
--   Step 10: automation_operation_log — 所有 AI 自動化動作稽核主表 🔴
--   Step 11: ai_collaboration_trace  — 多 Agent 協作逐步 (辯證歷程)
--   Step 12: 驗收查詢 (comment-only)
--
-- Idempotent 鐵律:
--   - CREATE TABLE IF NOT EXISTS
--   - CREATE INDEX IF NOT EXISTS
--   - CHECK constraint 寫在 CREATE TABLE 內,依賴 IF NOT EXISTS 保護
--   - 本檔可重複執行安全 (rerun 不會破壞既有資料)
--
-- 回滾:
--   DROP TABLE IF EXISTS ai_collaboration_trace, automation_operation_log,
--       capacity_violation_event, host_capacity_snapshot, asset_compliance_snapshot,
--       asset_change_event, alert_rule_catalog, asset_relationship,
--       asset_coverage_snapshot, asset_discovery_run, asset_inventory CASCADE;
--
-- ============================================================================
-- Step 0: pgcrypto extension (gen_random_uuid)
-- ============================================================================

CREATE EXTENSION IF NOT EXISTS pgcrypto;


-- ============================================================================
-- Step 1: asset_inventory — 全景資產主表
-- 用途: 主機 / 容器 / K8s workload / DB / 網站 / API / 套件 / 日誌 / KM / 前端 /
--       後端 / 容器 / Gitea / CI-CD 全部無例外
-- 主寫者: scanner (asset_discovery) + NemoTron (capacity 欄位)
-- ============================================================================

CREATE TABLE IF NOT EXISTS asset_inventory (
    asset_id              BIGSERIAL       PRIMARY KEY,
    asset_key             TEXT            NOT NULL UNIQUE,
    asset_type            TEXT            NOT NULL,
    parent_asset_id       BIGINT          REFERENCES asset_inventory(asset_id),
    environment           TEXT            NOT NULL DEFAULT 'prod',
    host                  TEXT,
    namespace             TEXT,
    name                  TEXT            NOT NULL,
    metadata              JSONB           NOT NULL DEFAULT '{}'::jsonb,
    tags                  TEXT[]          NOT NULL DEFAULT '{}',
    owner_team            TEXT,
    criticality           TEXT,
    data_classification   TEXT,
    external              BOOLEAN         NOT NULL DEFAULT false,
    lifecycle_state       TEXT            NOT NULL DEFAULT 'active',
    source_repo           TEXT,
    source_commit_sha     TEXT,

    -- 容量欄位 (Layer 4 AI 巡檢用)
    cpu_avg_7d            NUMERIC(5,2),
    mem_avg_7d            NUMERIC(5,2),
    capacity_headroom     NUMERIC(5,2),
    resource_limits       JSONB,
    resource_requests     JSONB,
    quota_violation_count INT             NOT NULL DEFAULT 0,
    sla_target            JSONB,
    cost_monthly_usd      NUMERIC(10,2),

    -- 生命週期時間戳
    first_seen_at         TIMESTAMPTZ     NOT NULL DEFAULT NOW(),
    last_seen_at          TIMESTAMPTZ     NOT NULL DEFAULT NOW(),
    decommissioned_at     TIMESTAMPTZ,
    created_at            TIMESTAMPTZ     NOT NULL DEFAULT NOW(),
    updated_at            TIMESTAMPTZ     NOT NULL DEFAULT NOW(),

    CONSTRAINT asset_inventory_criticality_valid
        CHECK (criticality IS NULL OR criticality IN ('P0','P1','P2','P3')),
    CONSTRAINT asset_inventory_data_class_valid
        CHECK (data_classification IS NULL OR data_classification IN
            ('public','internal','sensitive','secret')),
    CONSTRAINT asset_inventory_lifecycle_valid
        CHECK (lifecycle_state IN
            ('planned','provisioning','active','degraded','deprecated','decommissioned')),
    CONSTRAINT asset_inventory_type_valid
        CHECK (asset_type IN (
            'host','container','k8s_workload','k8s_resource','database','table',
            'website','api_endpoint','package','log_stream','km_entry',
            'frontend','backend','ci_pipeline','gitea_repo','monitoring_target',
            'secret','volume','network','certificate','scheduled_job',
            'message_queue','cache','dashboard','ai_agent','llm_model',
            'third_party_service','backup_target'
        ))
);

COMMENT ON TABLE asset_inventory IS
    'ADR-090: 全景資產主表。每一個主機/容器/K8s workload/DB/網站/API/套件/...都有一筆,跨 run 沿用同 asset_id。';

CREATE INDEX IF NOT EXISTS idx_asset_inventory_type_host
    ON asset_inventory(asset_type, host);
CREATE INDEX IF NOT EXISTS idx_asset_inventory_env_lifecycle
    ON asset_inventory(environment, lifecycle_state);
CREATE INDEX IF NOT EXISTS idx_asset_inventory_metadata_gin
    ON asset_inventory USING GIN (metadata);
CREATE INDEX IF NOT EXISTS idx_asset_inventory_tags_gin
    ON asset_inventory USING GIN (tags);
CREATE INDEX IF NOT EXISTS idx_asset_inventory_active_last_seen
    ON asset_inventory(last_seen_at DESC)
    WHERE lifecycle_state = 'active';
-- 註: partial index 只索引 active 資產,按最近出現時間排序


-- ============================================================================
-- Step 2: asset_discovery_run — 每次盤點 header
-- 用途: 記錄每次全景掃描的起止時間、掃描範圍、掃到什麼、新增/消失多少
-- 觸發: cron (每日) / ai (proactive_inspector) / human (手動) / incident
-- ============================================================================

CREATE TABLE IF NOT EXISTS asset_discovery_run (
    run_id              UUID            PRIMARY KEY DEFAULT gen_random_uuid(),
    triggered_by        TEXT            NOT NULL,
    scope               TEXT[]          NOT NULL,
    scan_depth          TEXT            NOT NULL DEFAULT 'shallow',
    host_filter         TEXT[],
    started_at          TIMESTAMPTZ     NOT NULL DEFAULT NOW(),
    ended_at            TIMESTAMPTZ,
    status              TEXT            NOT NULL,
    total_assets        INT,
    new_assets          INT             NOT NULL DEFAULT 0,
    modified_assets     INT             NOT NULL DEFAULT 0,
    disappeared_assets  INT             NOT NULL DEFAULT 0,
    tools_used          JSONB,
    duration_ms         INT,
    error               TEXT,
    summary             JSONB,

    CONSTRAINT asset_discovery_run_status_valid
        CHECK (status IN ('running','success','partial','failed','aborted')),
    CONSTRAINT asset_discovery_run_scan_depth_valid
        CHECK (scan_depth IN ('shallow','deep','full'))
);

COMMENT ON TABLE asset_discovery_run IS
    'ADR-090: 每次資產盤點的 header。run_id 作為下游 snapshot/event/change 的關聯主鍵。';

CREATE INDEX IF NOT EXISTS idx_asset_discovery_run_started
    ON asset_discovery_run(started_at DESC);
CREATE INDEX IF NOT EXISTS idx_asset_discovery_run_status
    ON asset_discovery_run(status) WHERE status IN ('running','failed','partial');


-- ============================================================================
-- Step 3: asset_coverage_snapshot — 資產 × 7 項自動化 覆蓋矩陣
-- 用途: 每個資產在 7 個自動化維度上的覆蓋狀態 (green/yellow/red)
-- 鐵律: 每次 discovery_run 為每個 asset 寫 7 筆 (7 dimensions)
-- ============================================================================

CREATE TABLE IF NOT EXISTS asset_coverage_snapshot (
    snapshot_id         BIGSERIAL       PRIMARY KEY,
    run_id              UUID            NOT NULL REFERENCES asset_discovery_run(run_id) ON DELETE CASCADE,
    asset_id            BIGINT          NOT NULL REFERENCES asset_inventory(asset_id),
    dimension           TEXT            NOT NULL,
    coverage_status     TEXT            NOT NULL,
    evidence            JSONB           NOT NULL DEFAULT '{}'::jsonb,
    gap_reason          TEXT,
    recommended_action  TEXT,
    confidence          NUMERIC(3,2),
    detected_by         TEXT            NOT NULL,
    created_at          TIMESTAMPTZ     NOT NULL DEFAULT NOW(),

    CONSTRAINT asset_coverage_snapshot_dimension_valid
        CHECK (dimension IN (
            'auto_monitoring','auto_alerting','auto_rule_creation',
            'auto_rule_matching','auto_playbook','auto_remediation','auto_km_creation'
        )),
    CONSTRAINT asset_coverage_snapshot_status_valid
        CHECK (coverage_status IN ('green','yellow','red','unknown')),
    CONSTRAINT asset_coverage_snapshot_unique
        UNIQUE (run_id, asset_id, dimension)
);

COMMENT ON TABLE asset_coverage_snapshot IS
    'ADR-090: 計分卡。查 red COUNT 即覆蓋率 SLO。evidence 欄位串 playbook_id/km_entry_id/rule_name。';

CREATE INDEX IF NOT EXISTS idx_asset_coverage_snapshot_asset_dim
    ON asset_coverage_snapshot(asset_id, dimension);
CREATE INDEX IF NOT EXISTS idx_asset_coverage_snapshot_red_yellow
    ON asset_coverage_snapshot(coverage_status)
    WHERE coverage_status IN ('red','yellow');
CREATE INDEX IF NOT EXISTS idx_asset_coverage_snapshot_run
    ON asset_coverage_snapshot(run_id);


-- ============================================================================
-- Step 4: asset_relationship — 資產依賴圖 (爆炸半徑必需)
-- 用途: 記錄資產之間的 depends_on / calls / stores_data_in / backs_up_to 關係
-- AI 用途: OpenClaw 計算 blast_radius 時查這張表
-- ============================================================================

CREATE TABLE IF NOT EXISTS asset_relationship (
    relationship_id     BIGSERIAL       PRIMARY KEY,
    from_asset_id       BIGINT          NOT NULL REFERENCES asset_inventory(asset_id),
    to_asset_id         BIGINT          NOT NULL REFERENCES asset_inventory(asset_id),
    relationship_type   TEXT            NOT NULL,
    strength            NUMERIC(3,2),
    metadata            JSONB,
    first_detected_at   TIMESTAMPTZ     NOT NULL DEFAULT NOW(),
    last_verified_at    TIMESTAMPTZ,
    is_active           BOOLEAN         NOT NULL DEFAULT true,

    CONSTRAINT asset_relationship_type_valid
        CHECK (relationship_type IN (
            'depends_on','calls','stores_data_in','backs_up_to',
            'routes_to','authenticates_via','monitors','alerts_to','logs_to'
        )),
    CONSTRAINT asset_relationship_strength_valid
        CHECK (strength IS NULL OR (strength >= 0 AND strength <= 1)),
    CONSTRAINT asset_relationship_unique
        UNIQUE (from_asset_id, to_asset_id, relationship_type),
    CONSTRAINT asset_relationship_no_self_loop
        CHECK (from_asset_id <> to_asset_id)
);

COMMENT ON TABLE asset_relationship IS
    'ADR-090: 資產依賴圖。AI 計算爆炸半徑必讀。edge 而非 tree,支援多重關係。';

CREATE INDEX IF NOT EXISTS idx_asset_relationship_from
    ON asset_relationship(from_asset_id) WHERE is_active;
CREATE INDEX IF NOT EXISTS idx_asset_relationship_to
    ON asset_relationship(to_asset_id) WHERE is_active;
CREATE INDEX IF NOT EXISTS idx_asset_relationship_type
    ON asset_relationship(relationship_type);


-- ============================================================================
-- Step 5: alert_rule_catalog — 告警規則本身即資產
-- 用途: 把 alert_rules.yaml 升級為 DB-driven;記錄誰創的 / 何時 / 效能 / 生死
-- AI 用途: Hermes 做 noise_rate 分析 / 提建議 retire 低品質規則
-- ============================================================================

CREATE TABLE IF NOT EXISTS alert_rule_catalog (
    rule_id                 BIGSERIAL       PRIMARY KEY,
    rule_name               TEXT            NOT NULL UNIQUE,
    source                  TEXT            NOT NULL,
    expr                    TEXT            NOT NULL,
    duration_seconds        INT,
    severity                TEXT,
    labels                  JSONB,
    annotations             JSONB,
    linked_asset_ids        BIGINT[],
    created_by_agent        TEXT,

    -- 規則品質追蹤
    true_positive_count     INT             NOT NULL DEFAULT 0,
    false_positive_count    INT             NOT NULL DEFAULT 0,
    noise_rate              NUMERIC(5,2),
    last_fired_at           TIMESTAMPTZ,

    -- 信心與演化
    confidence              NUMERIC(3,2),
    review_status           TEXT,
    superseded_by_rule_id   BIGINT          REFERENCES alert_rule_catalog(rule_id),

    created_at              TIMESTAMPTZ     NOT NULL DEFAULT NOW(),
    updated_at              TIMESTAMPTZ     NOT NULL DEFAULT NOW(),

    CONSTRAINT alert_rule_catalog_source_valid
        CHECK (source IN ('yaml_hardcoded','ai_generated','human_written','playbook_derived')),
    CONSTRAINT alert_rule_catalog_review_valid
        CHECK (review_status IS NULL OR review_status IN
            ('draft','approved','deprecated','retired'))
);

COMMENT ON TABLE alert_rule_catalog IS
    'ADR-090: 告警規則即一等資產。支援規則演化 (ai_generated) 與替代鏈 (superseded_by)。';

CREATE INDEX IF NOT EXISTS idx_alert_rule_catalog_source
    ON alert_rule_catalog(source);
CREATE INDEX IF NOT EXISTS idx_alert_rule_catalog_assets_gin
    ON alert_rule_catalog USING GIN (linked_asset_ids);
CREATE INDEX IF NOT EXISTS idx_alert_rule_catalog_review
    ON alert_rule_catalog(review_status) WHERE review_status IS NOT NULL;


-- ============================================================================
-- Step 6: asset_change_event — 資產變化追蹤 (diff between runs)
-- 用途: 兩次 discovery_run 之間的 delta。新增/消失/修改/覆蓋率變化
-- ============================================================================

CREATE TABLE IF NOT EXISTS asset_change_event (
    event_id        BIGSERIAL       PRIMARY KEY,
    run_id          UUID            NOT NULL REFERENCES asset_discovery_run(run_id),
    asset_id        BIGINT          REFERENCES asset_inventory(asset_id),
    change_type     TEXT            NOT NULL,
    before_state    JSONB,
    after_state     JSONB,
    diff            JSONB,
    detected_at     TIMESTAMPTZ     NOT NULL DEFAULT NOW(),
    ai_analysis     TEXT,

    CONSTRAINT asset_change_event_type_valid
        CHECK (change_type IN (
            'asset_added','asset_removed','asset_modified',
            'coverage_improved','coverage_degraded',
            'criticality_changed','owner_changed','lifecycle_changed'
        ))
);

COMMENT ON TABLE asset_change_event IS
    'ADR-090: 資產變化追蹤。兩次掃描的 diff 明確落地,LLM 可加 ai_analysis 解讀。';

CREATE INDEX IF NOT EXISTS idx_asset_change_event_run
    ON asset_change_event(run_id);
CREATE INDEX IF NOT EXISTS idx_asset_change_event_asset_time
    ON asset_change_event(asset_id, detected_at DESC);


-- ============================================================================
-- Step 7: asset_compliance_snapshot — 合規狀態 (SSL/CVE/secret/backup)
-- 用途: 與 coverage 不同軸的合規追蹤。SSL cert 到期 / CVE 掃描 / secret 輪替
-- ============================================================================

CREATE TABLE IF NOT EXISTS asset_compliance_snapshot (
    snapshot_id             BIGSERIAL       PRIMARY KEY,
    run_id                  UUID            REFERENCES asset_discovery_run(run_id),
    asset_id                BIGINT          NOT NULL REFERENCES asset_inventory(asset_id),
    dimension               TEXT            NOT NULL,
    status                  TEXT            NOT NULL,
    expires_at              TIMESTAMPTZ,
    detail                  JSONB,
    remediation_deadline    TIMESTAMPTZ,
    detected_at             TIMESTAMPTZ     NOT NULL DEFAULT NOW(),

    CONSTRAINT asset_compliance_snapshot_dimension_valid
        CHECK (dimension IN (
            'ssl_cert_valid','cve_scan','secret_rotated','backup_tested',
            'audit_log_enabled','access_reviewed','encryption_at_rest'
        )),
    CONSTRAINT asset_compliance_snapshot_status_valid
        CHECK (status IN ('compliant','warning','violation','unknown'))
);

COMMENT ON TABLE asset_compliance_snapshot IS
    'ADR-090: 合規狀態快照。與 coverage 不同軸,SSL/CVE/secret/backup 專用。';

CREATE INDEX IF NOT EXISTS idx_asset_compliance_snapshot_asset_dim
    ON asset_compliance_snapshot(asset_id, dimension);
CREATE INDEX IF NOT EXISTS idx_asset_compliance_snapshot_expiring
    ON asset_compliance_snapshot(expires_at)
    WHERE expires_at IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_asset_compliance_snapshot_violations
    ON asset_compliance_snapshot(status)
    WHERE status IN ('warning','violation');


-- ============================================================================
-- Step 8: host_capacity_snapshot — 主機容量快照
-- 用途: NemoTron 每日 02:00 台北 自主容量巡檢寫入
-- Layer 4 核心表。hermes 做預測,openclaw 產建議,全寫這張
-- ============================================================================

CREATE TABLE IF NOT EXISTS host_capacity_snapshot (
    snapshot_id             BIGSERIAL       PRIMARY KEY,
    host                    TEXT            NOT NULL,
    captured_at             TIMESTAMPTZ     NOT NULL DEFAULT NOW(),
    load1                   NUMERIC(6,2),
    load5                   NUMERIC(6,2),
    load15                  NUMERIC(6,2),
    cpu_used_pct            NUMERIC(5,2),
    cpu_iowait_pct          NUMERIC(5,2),
    mem_used_pct            NUMERIC(5,2),
    swap_used_pct           NUMERIC(5,2),
    disk_used_pct           JSONB,
    container_count         INT,
    k8s_pod_count           INT,
    top_cpu_offenders       JSONB,
    top_mem_offenders       JSONB,
    headroom_pct            NUMERIC(5,2),
    ai_verdict              TEXT,
    ai_reasoning            TEXT,
    recommended_actions     JSONB,
    written_by_agent        TEXT            NOT NULL,

    CONSTRAINT host_capacity_snapshot_verdict_valid
        CHECK (ai_verdict IS NULL OR ai_verdict IN ('safe','warning','critical','unknown'))
);

COMMENT ON TABLE host_capacity_snapshot IS
    'ADR-090: NemoTron 每日主機容量巡檢結果。Layer 4 AI 自主治理核心表。';

CREATE INDEX IF NOT EXISTS idx_host_capacity_snapshot_host_time
    ON host_capacity_snapshot(host, captured_at DESC);
CREATE INDEX IF NOT EXISTS idx_host_capacity_snapshot_critical
    ON host_capacity_snapshot(ai_verdict)
    WHERE ai_verdict IN ('warning','critical');


-- ============================================================================
-- Step 9: capacity_violation_event — 配額違規事件
-- 用途: 記錄任何「缺 limit」「超 request」「主機飽和」的違規
-- ============================================================================

CREATE TABLE IF NOT EXISTS capacity_violation_event (
    event_id            BIGSERIAL       PRIMARY KEY,
    asset_id            BIGINT          REFERENCES asset_inventory(asset_id),
    host                TEXT,
    violation_type      TEXT            NOT NULL,
    threshold           NUMERIC(10,2),
    actual_value        NUMERIC(10,2),
    detected_at         TIMESTAMPTZ     NOT NULL DEFAULT NOW(),
    auto_action         TEXT,
    auto_action_op_id   UUID,
    human_override      TEXT,
    resolved_at         TIMESTAMPTZ,

    CONSTRAINT capacity_violation_event_type_valid
        CHECK (violation_type IN (
            'no_limit_set','over_request','over_limit','host_saturation',
            'over_sla_budget','unauthorized_new_deploy'
        ))
);

COMMENT ON TABLE capacity_violation_event IS
    'ADR-090: 配額違規稽核。每次 AI 偵測到資產無 limit/主機飽和/未授權部署 都寫一筆。';

CREATE INDEX IF NOT EXISTS idx_capacity_violation_event_asset_time
    ON capacity_violation_event(asset_id, detected_at DESC);
CREATE INDEX IF NOT EXISTS idx_capacity_violation_event_unresolved
    ON capacity_violation_event(detected_at DESC)
    WHERE resolved_at IS NULL;


-- ============================================================================
-- Step 10: automation_operation_log — 所有 AI 自動化動作稽核主表 🔴
-- 鐵律: 每一個 AI 自動化動作都必須寫一筆。缺筆 = 治理失效
-- ============================================================================

CREATE TABLE IF NOT EXISTS automation_operation_log (
    op_id               UUID            PRIMARY KEY DEFAULT gen_random_uuid(),
    operation_type      TEXT            NOT NULL,
    asset_id            BIGINT          REFERENCES asset_inventory(asset_id),
    incident_id         BIGINT,
    run_id              UUID            REFERENCES asset_discovery_run(run_id),
    actor               TEXT            NOT NULL,
    input               JSONB           NOT NULL DEFAULT '{}'::jsonb,
    output              JSONB           NOT NULL DEFAULT '{}'::jsonb,
    dry_run_result      JSONB,
    status              TEXT            NOT NULL,
    error               TEXT,
    duration_ms         INT,
    tokens_in           INT,
    tokens_out          INT,
    cost_usd            NUMERIC(10,6),
    budget_bucket       TEXT,
    parent_op_id        UUID            REFERENCES automation_operation_log(op_id),
    retry_count         INT             NOT NULL DEFAULT 0,
    retry_of_op_id      UUID            REFERENCES automation_operation_log(op_id),
    stderr_feed_back    TEXT,
    tags                TEXT[],
    created_at          TIMESTAMPTZ     NOT NULL DEFAULT NOW(),

    CONSTRAINT automation_operation_log_type_valid
        CHECK (operation_type IN (
            'monitor_configured','monitor_removed',
            'alert_fired','alert_suppressed','alert_routed',
            'rule_created','rule_updated','rule_matched','rule_rejected','rule_deprecated',
            'playbook_generated','playbook_updated','playbook_executed',
            'remediation_executed','remediation_verified','remediation_rolled_back',
            'self_correction_attempted',
            'km_created','km_updated','km_linked',
            'asset_discovered','coverage_recalculated',
            'capacity_recommendation','quota_enforced'
        )),
    CONSTRAINT automation_operation_log_status_valid
        CHECK (status IN ('pending','success','failed','dry_run','rolled_back'))
);

COMMENT ON TABLE automation_operation_log IS
    'ADR-090: 所有 AI 自動化動作稽核主表。retry_of_op_id + stderr_feed_back 支援引擎 4 閉環。';

CREATE INDEX IF NOT EXISTS idx_automation_operation_log_type_time
    ON automation_operation_log(operation_type, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_automation_operation_log_asset_time
    ON automation_operation_log(asset_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_automation_operation_log_incident
    ON automation_operation_log(incident_id)
    WHERE incident_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_automation_operation_log_actor_time
    ON automation_operation_log(actor, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_automation_operation_log_retry
    ON automation_operation_log(retry_of_op_id)
    WHERE retry_of_op_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_automation_operation_log_tags_gin
    ON automation_operation_log USING GIN (tags);


-- ============================================================================
-- Step 11: ai_collaboration_trace — 多 Agent 協作逐步 (LLM × OpenClaw × NemoTron × Hermes)
-- 用途: 每個 automation_operation_log 背後的 N 步 AI 決策過程
-- 最寶貴的語料: challenged_by + accepted 支援 RLHF fine-tune
-- ============================================================================

CREATE TABLE IF NOT EXISTS ai_collaboration_trace (
    trace_id                BIGSERIAL       PRIMARY KEY,
    op_id                   UUID            NOT NULL REFERENCES automation_operation_log(op_id) ON DELETE CASCADE,
    step_order              INT             NOT NULL,
    agent                   TEXT            NOT NULL,
    model                   TEXT,
    system_prompt_version   TEXT,
    prompt                  TEXT,
    response                JSONB,
    confidence              NUMERIC(3,2),
    challenged_by           TEXT[],
    accepted                BOOLEAN,
    tokens_in               INT,
    tokens_out              INT,
    duration_ms             INT,
    created_at              TIMESTAMPTZ     NOT NULL DEFAULT NOW(),

    CONSTRAINT ai_collaboration_trace_unique_step
        UNIQUE (op_id, step_order)
);

COMMENT ON TABLE ai_collaboration_trace IS
    'ADR-090: AI 多 Agent 協作逐步紀錄。challenged_by + accepted = RLHF 訓練語料金礦。';

CREATE INDEX IF NOT EXISTS idx_ai_collaboration_trace_op
    ON ai_collaboration_trace(op_id, step_order);
CREATE INDEX IF NOT EXISTS idx_ai_collaboration_trace_agent_time
    ON ai_collaboration_trace(agent, created_at DESC);


-- ============================================================================
-- Step 12: 驗收查詢 (執行後手動跑,驗證 11 張表都到位)
-- ============================================================================

-- SELECT table_name
-- FROM information_schema.tables
-- WHERE table_schema = 'public'
--   AND table_name IN (
--       'asset_inventory',
--       'asset_discovery_run',
--       'asset_coverage_snapshot',
--       'asset_relationship',
--       'alert_rule_catalog',
--       'asset_change_event',
--       'asset_compliance_snapshot',
--       'host_capacity_snapshot',
--       'capacity_violation_event',
--       'automation_operation_log',
--       'ai_collaboration_trace'
--   )
-- ORDER BY table_name;
-- -- 預期: 11 筆

-- SELECT table_name, COUNT(*) AS column_count
-- FROM information_schema.columns
-- WHERE table_schema = 'public'
--   AND table_name LIKE 'asset_%' OR table_name IN
--       ('alert_rule_catalog','host_capacity_snapshot','capacity_violation_event',
--        'automation_operation_log','ai_collaboration_trace')
-- GROUP BY table_name
-- ORDER BY table_name;

-- SELECT conname, conrelid::regclass AS table_name
-- FROM pg_constraint
-- WHERE conrelid IN (
--     'asset_inventory'::regclass,
--     'asset_discovery_run'::regclass,
--     'asset_coverage_snapshot'::regclass,
--     'asset_relationship'::regclass,
--     'alert_rule_catalog'::regclass,
--     'asset_change_event'::regclass,
--     'asset_compliance_snapshot'::regclass,
--     'host_capacity_snapshot'::regclass,
--     'capacity_violation_event'::regclass,
--     'automation_operation_log'::regclass,
--     'ai_collaboration_trace'::regclass
-- ) AND contype = 'c'  -- CHECK constraints only
-- ORDER BY table_name, conname;

-- ============================================================================
-- END OF MIGRATION adr090_asset_inventory_foundation.sql
-- 預計新增物件: 11 tables + 33 indexes + 20 CHECK constraints + 3 UNIQUE + 16 FK references
-- 依賴: pgcrypto extension (for gen_random_uuid)
-- 影響資料: 無 (純 DDL, 不動現有表)
-- 回滾: 見檔案頭部
-- ============================================================================
