All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 14m4s
## 之前c5b18101修錯地方 我加 db/base.py:init_db() ALTER 沒解問題。**CI 不跑 init_db()**。 ## 真實 CD 流程 `.gitea/workflows/cd.yaml` Integration Tests step: 1. 啟動臨時 `pg-test-b5` 容器(fresh PG) 2. `psql -f tests/integration/setup_test_schema.sql` 建表 3. 跑 pytest tests/integration/test_b5_core_flows.py setup_test_schema.sql 的 `knowledge_entries` 表沒有 `related_approval_id` + `path_type` 欄位 → INSERT 失敗。 ## 修法 setup_test_schema.sql:110 `CREATE TABLE knowledge_entries` 補: - related_approval_id VARCHAR(64) - path_type VARCHAR(50) - uix_knowledge_incident_path partial unique index - ix_knowledge_related_approval partial index ## 預期效果 CD #1119 (本 commit) 應該成功。 解鎖 4 個 stuck commit (1114-1118) 的部署 backlog。fb0c72db推翻 A2 DIAGNOSE Ollama primary 終於上 prod。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
167 lines
6.5 KiB
SQL
167 lines
6.5 KiB
SQL
-- Integration Test Schema Setup
|
||
-- ================================
|
||
-- 為 CI 環境的臨時 PostgreSQL 建立測試所需的 schema
|
||
-- 使用: psql $TEST_DATABASE_URL -f setup_test_schema.sql
|
||
-- 2026-04-10 Claude Sonnet 4.6 Asia/Taipei
|
||
|
||
CREATE EXTENSION IF NOT EXISTS vector;
|
||
|
||
DO $$ BEGIN
|
||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'incidentstatus') THEN
|
||
CREATE TYPE incidentstatus AS ENUM ('INVESTIGATING','MITIGATING','RESOLVED','CLOSED','ESCALATED');
|
||
END IF;
|
||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'severity') THEN
|
||
CREATE TYPE severity AS ENUM ('P0','P1','P2','P3');
|
||
END IF;
|
||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'approvalstatus') THEN
|
||
CREATE TYPE approvalstatus AS ENUM ('PENDING','APPROVED','REJECTED','EXPIRED','EXECUTION_SUCCESS','EXECUTION_FAILED');
|
||
END IF;
|
||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'risklevel') THEN
|
||
CREATE TYPE risklevel AS ENUM ('LOW','MEDIUM','HIGH','CRITICAL');
|
||
END IF;
|
||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entrysource') THEN
|
||
CREATE TYPE entrysource AS ENUM ('AI_EXTRACTED','HUMAN');
|
||
END IF;
|
||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entrystatus') THEN
|
||
CREATE TYPE entrystatus AS ENUM ('DRAFT','REVIEW','APPROVED','ARCHIVED','published');
|
||
END IF;
|
||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entrytype') THEN
|
||
CREATE TYPE entrytype AS ENUM ('INCIDENT_CASE','RUNBOOK','BEST_PRACTICE','POSTMORTEM','auto_runbook','anti_pattern');
|
||
END IF;
|
||
END $$;
|
||
|
||
CREATE TABLE IF NOT EXISTS incidents (
|
||
incident_id VARCHAR(30) PRIMARY KEY,
|
||
status incidentstatus NOT NULL DEFAULT 'INVESTIGATING',
|
||
severity severity NOT NULL DEFAULT 'P2',
|
||
signals JSON DEFAULT '[]',
|
||
affected_services JSON DEFAULT '[]',
|
||
decision_chain JSON DEFAULT '[]',
|
||
proposal_ids JSON DEFAULT '[]',
|
||
outcome JSON DEFAULT '{}',
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||
resolved_at TIMESTAMPTZ,
|
||
closed_at TIMESTAMPTZ,
|
||
ttl_days INTEGER DEFAULT 30,
|
||
vectorized BOOLEAN DEFAULT false
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS approval_records (
|
||
id VARCHAR(36) PRIMARY KEY,
|
||
action VARCHAR(500) NOT NULL,
|
||
description TEXT NOT NULL,
|
||
status approvalstatus NOT NULL DEFAULT 'PENDING',
|
||
risk_level risklevel NOT NULL,
|
||
required_signatures INTEGER DEFAULT 1,
|
||
current_signatures INTEGER DEFAULT 0,
|
||
signatures JSON DEFAULT '[]',
|
||
blast_radius JSON DEFAULT '{}',
|
||
dry_run_checks JSON DEFAULT '[]',
|
||
requested_by VARCHAR,
|
||
rejection_reason TEXT,
|
||
extra_metadata JSON DEFAULT '{}',
|
||
fingerprint VARCHAR,
|
||
hit_count INTEGER DEFAULT 1,
|
||
last_seen_at TIMESTAMPTZ,
|
||
approval_level VARCHAR DEFAULT 'standard',
|
||
approval_votes JSONB,
|
||
required_votes INTEGER DEFAULT 1,
|
||
incident_id VARCHAR,
|
||
telegram_message_id INTEGER,
|
||
telegram_chat_id BIGINT, -- ADR-093 2026-04-25: 支援群組負數 ID
|
||
matched_playbook_id VARCHAR(36),
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||
expires_at TIMESTAMPTZ,
|
||
resolved_at TIMESTAMPTZ
|
||
);
|
||
|
||
-- 2026-04-27 P2.1 DecisionFusion 欄位(對齊 p2_decision_fusion_columns.sql 已上 production)
|
||
-- IF NOT EXISTS 形式 idempotent,重跑安全
|
||
ALTER TABLE approval_records
|
||
ADD COLUMN IF NOT EXISTS composite_score REAL,
|
||
ADD COLUMN IF NOT EXISTS complexity_tier VARCHAR(16),
|
||
ADD COLUMN IF NOT EXISTS decision_fusion_details JSONB;
|
||
|
||
DO $$
|
||
BEGIN
|
||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'chk_complexity_tier') THEN
|
||
ALTER TABLE approval_records
|
||
ADD CONSTRAINT chk_complexity_tier CHECK (
|
||
complexity_tier IS NULL
|
||
OR complexity_tier IN ('low','medium','high','critical')
|
||
);
|
||
END IF;
|
||
END $$;
|
||
|
||
-- 2026-04-27 P3.2.2 — AI Provider 版本歷史表(對齊 p3_2_provider_version_history.sql)
|
||
CREATE TABLE IF NOT EXISTS ai_provider_version_history (
|
||
id SERIAL PRIMARY KEY,
|
||
provider VARCHAR(40) NOT NULL,
|
||
model VARCHAR(100) NOT NULL,
|
||
version VARCHAR(200),
|
||
digest VARCHAR(80),
|
||
captured_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
prev_version VARCHAR(200),
|
||
changed BOOLEAN NOT NULL DEFAULT FALSE
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS knowledge_entries (
|
||
id VARCHAR(36) PRIMARY KEY,
|
||
title VARCHAR NOT NULL,
|
||
content TEXT,
|
||
entry_type entrytype NOT NULL,
|
||
category VARCHAR,
|
||
tags JSON DEFAULT '[]',
|
||
source entrysource NOT NULL DEFAULT 'HUMAN',
|
||
status entrystatus NOT NULL DEFAULT 'DRAFT',
|
||
related_incident_id VARCHAR,
|
||
related_playbook_id VARCHAR,
|
||
symptoms_hash VARCHAR,
|
||
-- 2026-04-29 ogt + Claude Opus 4.7: M4 KMWriter 反查鏈 + 冪等補欄
|
||
-- 解 CD #1115-1118 全 failure:column "related_approval_id" does not exist
|
||
-- 對應 commit c22e5f33 KMWriter ORM 加的欄位
|
||
related_approval_id VARCHAR(64),
|
||
path_type VARCHAR(50),
|
||
view_count INTEGER DEFAULT 0,
|
||
created_by VARCHAR,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||
);
|
||
-- M3 冪等 unique index (incident_id + path_type)
|
||
CREATE UNIQUE INDEX IF NOT EXISTS uix_knowledge_incident_path
|
||
ON knowledge_entries(related_incident_id, path_type)
|
||
WHERE related_incident_id IS NOT NULL AND path_type IS NOT NULL;
|
||
-- M4 反查鏈 partial index
|
||
CREATE INDEX IF NOT EXISTS ix_knowledge_related_approval
|
||
ON knowledge_entries(related_approval_id)
|
||
WHERE related_approval_id IS NOT NULL;
|
||
|
||
CREATE TABLE IF NOT EXISTS rag_chunks (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
source TEXT NOT NULL,
|
||
source_id TEXT NOT NULL,
|
||
title TEXT,
|
||
chunk_text TEXT NOT NULL,
|
||
embedding vector(768),
|
||
metadata JSONB DEFAULT '{}',
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||
);
|
||
|
||
-- adr091: aider_events schema (2026-04-22 @ Asia/Taipei, 補入 integration test schema)
|
||
CREATE TABLE IF NOT EXISTS aider_events (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
session_id TEXT NOT NULL,
|
||
ts TIMESTAMPTZ NOT NULL,
|
||
type TEXT NOT NULL,
|
||
host TEXT DEFAULT 'ogt-mac',
|
||
payload JSONB NOT NULL,
|
||
incident_id TEXT,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
CREATE INDEX IF NOT EXISTS aider_events_session_idx ON aider_events(session_id);
|
||
CREATE INDEX IF NOT EXISTS aider_events_type_ts_idx ON aider_events(type, ts DESC);
|
||
CREATE INDEX IF NOT EXISTS aider_events_ts_idx ON aider_events(ts DESC);
|
||
CREATE INDEX IF NOT EXISTS aider_events_payload_gin ON aider_events USING GIN (payload);
|