179 lines
28 KiB
YAML
179 lines
28 KiB
YAML
{
|
|
"apiVersion": "v1",
|
|
"kind": "List",
|
|
"items": [
|
|
{
|
|
"apiVersion": "v1",
|
|
"kind": "ConfigMap",
|
|
"metadata": {
|
|
"name": "hwlab-v03-postgres-init",
|
|
"namespace": "hwlab-v03",
|
|
"labels": {
|
|
"app.kubernetes.io/name": "hwlab-v03-postgres",
|
|
"app.kubernetes.io/part-of": "hwlab",
|
|
"hwlab.pikastech.local/environment": "v03",
|
|
"hwlab.pikastech.local/gitops-target": "v03",
|
|
"hwlab.pikastech.local/profile": "v03",
|
|
"hwlab.pikastech.local/source-commit": "66cdf0b8f7c0bae2e0b8c95783f38034ecb9a452"
|
|
}
|
|
},
|
|
"data": {
|
|
"0001_cloud_core_skeleton.sql": "-- SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-24-p0-aggregate-event-stream.\n-- HWLAB L1 Cloud Core schema skeleton.\n-- This file is source schema only; applying it to DEV/PROD is a separate\n-- operator action and is not performed by source tests or smokes.\n\nCREATE TABLE IF NOT EXISTS projects (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL DEFAULT '',\n status TEXT NOT NULL DEFAULT 'pending',\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS users (\n id TEXT PRIMARY KEY,\n username TEXT NOT NULL UNIQUE,\n display_name TEXT NOT NULL DEFAULT '',\n role TEXT NOT NULL CHECK (role IN ('admin', 'user')),\n status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'disabled')),\n password_hash TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS user_sessions (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id),\n session_token_hash TEXT NOT NULL UNIQUE,\n created_at TEXT NOT NULL,\n last_seen_at TEXT NOT NULL,\n expires_at TEXT NOT NULL,\n revoked_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS gateway_sessions (\n id TEXT PRIMARY KEY,\n project_id TEXT,\n gateway_service_id TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n started_at TEXT,\n ended_at TEXT,\n gateway_session_json TEXT NOT NULL DEFAULT '{}'\n);\n\nCREATE TABLE IF NOT EXISTS box_resources (\n id TEXT PRIMARY KEY,\n project_id TEXT,\n gateway_session_id TEXT,\n resource_state TEXT NOT NULL DEFAULT 'available',\n labels_json TEXT NOT NULL DEFAULT '{}',\n resource_json TEXT NOT NULL DEFAULT '{}',\n updated_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS box_capabilities (\n id TEXT PRIMARY KEY,\n box_resource_id TEXT NOT NULL,\n capability_type TEXT NOT NULL,\n capability_json TEXT NOT NULL DEFAULT '{}',\n updated_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS wiring_configs (\n id TEXT PRIMARY KEY,\n project_id TEXT,\n wiring_json TEXT NOT NULL DEFAULT '{}',\n status TEXT NOT NULL DEFAULT 'pending',\n updated_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS patch_panel_status (\n id TEXT PRIMARY KEY,\n gateway_session_id TEXT,\n wiring_config_id TEXT,\n status_json TEXT NOT NULL DEFAULT '{}',\n updated_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS hardware_operations (\n id TEXT PRIMARY KEY,\n project_id TEXT,\n requested_by TEXT,\n operation_type TEXT NOT NULL,\n operation_json TEXT NOT NULL DEFAULT '{}',\n status TEXT NOT NULL DEFAULT 'requested',\n requested_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS audit_events (\n id TEXT PRIMARY KEY,\n request_id TEXT NOT NULL,\n actor TEXT NOT NULL,\n source TEXT NOT NULL,\n operation TEXT NOT NULL,\n target TEXT NOT NULL,\n result TEXT NOT NULL,\n timestamp TEXT NOT NULL,\n event_json TEXT NOT NULL DEFAULT '{}'\n);\n\nCREATE TABLE IF NOT EXISTS agent_sessions (\n id TEXT PRIMARY KEY,\n project_id TEXT,\n agent_id TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n started_at TEXT,\n ended_at TEXT,\n owner_user_id TEXT REFERENCES users(id),\n conversation_id TEXT,\n thread_id TEXT,\n last_trace_id TEXT,\n session_json TEXT NOT NULL DEFAULT '{}',\n updated_at TEXT\n);\n\nALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS owner_user_id TEXT REFERENCES users(id);\nALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS conversation_id TEXT;\nALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS thread_id TEXT;\nALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS last_trace_id TEXT;\nALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS session_json TEXT NOT NULL DEFAULT '{}';\nALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS updated_at TEXT;\nCREATE INDEX IF NOT EXISTS idx_agent_sessions_owner ON agent_sessions(owner_user_id);\nCREATE INDEX IF NOT EXISTS idx_agent_sessions_conversation ON agent_sessions(conversation_id);\nCREATE INDEX IF NOT EXISTS idx_agent_sessions_active_updated ON agent_sessions(updated_at DESC, id DESC) WHERE status <> 'archived';\nCREATE INDEX IF NOT EXISTS idx_agent_sessions_owner_active_updated ON agent_sessions(owner_user_id, updated_at DESC, id DESC) WHERE status <> 'archived';\n\nCREATE TABLE IF NOT EXISTS account_workspaces (\n id TEXT PRIMARY KEY,\n owner_user_id TEXT NOT NULL REFERENCES users(id),\n project_id TEXT NOT NULL,\n name TEXT NOT NULL DEFAULT 'Default Workbench',\n status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'archived')),\n is_default BOOLEAN NOT NULL DEFAULT true,\n selected_conversation_id TEXT,\n selected_agent_session_id TEXT,\n active_trace_id TEXT,\n provider_profile TEXT,\n workspace_json TEXT NOT NULL DEFAULT '{}',\n revision INTEGER NOT NULL DEFAULT 1,\n updated_by_session_id TEXT,\n updated_by_client TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_account_workspaces_default ON account_workspaces(owner_user_id, project_id) WHERE is_default = TRUE AND status = 'active';\nCREATE INDEX IF NOT EXISTS idx_account_workspaces_owner ON account_workspaces(owner_user_id, project_id, updated_at DESC);\n\nCREATE TABLE IF NOT EXISTS worker_sessions (\n id TEXT PRIMARY KEY,\n agent_session_id TEXT,\n worker_id TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n started_at TEXT,\n ended_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS agent_trace_events (\n id TEXT PRIMARY KEY,\n trace_id TEXT NOT NULL,\n agent_session_id TEXT,\n worker_session_id TEXT,\n level TEXT NOT NULL DEFAULT 'info',\n message TEXT NOT NULL DEFAULT '',\n event_json TEXT NOT NULL DEFAULT '{}',\n occurred_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_agent_trace_events_trace_order ON agent_trace_events(trace_id, occurred_at, id);\nCREATE INDEX IF NOT EXISTS idx_agent_trace_events_session_order ON agent_trace_events(agent_session_id, occurred_at, id);\nCREATE INDEX IF NOT EXISTS idx_agent_trace_events_worker_order ON agent_trace_events(worker_session_id, occurred_at, id);\n\nCREATE TABLE IF NOT EXISTS workbench_projection_state (\n trace_id TEXT PRIMARY KEY,\n session_id TEXT,\n conversation_id TEXT,\n thread_id TEXT,\n run_id TEXT NOT NULL,\n command_id TEXT NOT NULL,\n last_agentrun_seq INTEGER NOT NULL DEFAULT 0,\n last_projected_seq INTEGER NOT NULL DEFAULT 0,\n upstream_latest_seq INTEGER,\n projection_status TEXT NOT NULL DEFAULT 'projecting',\n projection_health TEXT NOT NULL DEFAULT 'healthy',\n result_sync_state TEXT NOT NULL DEFAULT 'not_started',\n last_projected_at TEXT,\n last_result_sync_at TEXT,\n last_error_code TEXT,\n last_error_message TEXT,\n failure_count INTEGER NOT NULL DEFAULT 0,\n next_retry_at TEXT,\n projection_json TEXT NOT NULL DEFAULT '{}',\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_workbench_projection_state_status_retry_updated ON workbench_projection_state(projection_status, next_retry_at, updated_at);\nCREATE INDEX IF NOT EXISTS idx_workbench_projection_state_run_command ON workbench_projection_state(run_id, command_id);\nCREATE INDEX IF NOT EXISTS idx_workbench_projection_state_session_updated ON workbench_projection_state(session_id, updated_at DESC);\n\nCREATE TABLE IF NOT EXISTS workbench_sessions (\n session_id TEXT PRIMARY KEY,\n owner_user_id TEXT REFERENCES users(id),\n project_id TEXT,\n conversation_id TEXT,\n thread_id TEXT,\n status TEXT NOT NULL DEFAULT 'unknown',\n last_trace_id TEXT,\n projected_seq INTEGER NOT NULL DEFAULT 0,\n source_seq INTEGER NOT NULL DEFAULT 0,\n source_event_id TEXT,\n terminal BOOLEAN NOT NULL DEFAULT false,\n sealed BOOLEAN NOT NULL DEFAULT false,\n session_json TEXT NOT NULL DEFAULT '{}',\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_workbench_sessions_owner_updated ON workbench_sessions(owner_user_id, updated_at DESC, session_id);\nCREATE INDEX IF NOT EXISTS idx_workbench_sessions_status_updated ON workbench_sessions(status, updated_at DESC, session_id);\n\nCREATE TABLE IF NOT EXISTS workbench_messages (\n message_id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n turn_id TEXT,\n trace_id TEXT,\n role TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'unknown',\n projected_seq INTEGER NOT NULL DEFAULT 0,\n source_seq INTEGER NOT NULL DEFAULT 0,\n source_event_id TEXT,\n terminal BOOLEAN NOT NULL DEFAULT false,\n sealed BOOLEAN NOT NULL DEFAULT false,\n message_json TEXT NOT NULL DEFAULT '{}',\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_workbench_messages_session_updated ON workbench_messages(session_id, updated_at ASC, message_id);\nCREATE INDEX IF NOT EXISTS idx_workbench_messages_trace ON workbench_messages(trace_id, message_id);\nCREATE INDEX IF NOT EXISTS idx_workbench_messages_turn ON workbench_messages(turn_id, message_id);\n\nCREATE TABLE IF NOT EXISTS workbench_parts (\n part_id TEXT PRIMARY KEY,\n message_id TEXT NOT NULL,\n session_id TEXT NOT NULL,\n turn_id TEXT,\n trace_id TEXT,\n part_index INTEGER NOT NULL DEFAULT 0,\n part_type TEXT NOT NULL DEFAULT 'text',\n status TEXT NOT NULL DEFAULT 'unknown',\n projected_seq INTEGER NOT NULL DEFAULT 0,\n source_seq INTEGER NOT NULL DEFAULT 0,\n source_event_id TEXT,\n terminal BOOLEAN NOT NULL DEFAULT false,\n sealed BOOLEAN NOT NULL DEFAULT false,\n part_json TEXT NOT NULL DEFAULT '{}',\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_workbench_parts_message_index ON workbench_parts(message_id, part_index, part_id);\nCREATE INDEX IF NOT EXISTS idx_workbench_parts_session_trace ON workbench_parts(session_id, trace_id, part_index);\n\nCREATE TABLE IF NOT EXISTS workbench_turns (\n turn_id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n trace_id TEXT,\n message_id TEXT,\n status TEXT NOT NULL DEFAULT 'unknown',\n projected_seq INTEGER NOT NULL DEFAULT 0,\n source_seq INTEGER NOT NULL DEFAULT 0,\n source_event_id TEXT,\n terminal BOOLEAN NOT NULL DEFAULT false,\n sealed BOOLEAN NOT NULL DEFAULT false,\n final_response_json TEXT NOT NULL DEFAULT 'null',\n diagnostic_json TEXT NOT NULL DEFAULT '{}',\n turn_json TEXT NOT NULL DEFAULT '{}',\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_workbench_turns_session_updated ON workbench_turns(session_id, updated_at DESC, turn_id);\nCREATE INDEX IF NOT EXISTS idx_workbench_turns_trace ON workbench_turns(trace_id, turn_id);\n\nCREATE TABLE IF NOT EXISTS workbench_trace_events (\n id TEXT PRIMARY KEY,\n trace_id TEXT NOT NULL,\n session_id TEXT,\n turn_id TEXT,\n message_id TEXT,\n source_seq INTEGER NOT NULL DEFAULT 0,\n source_event_id TEXT,\n projected_seq INTEGER NOT NULL DEFAULT 0,\n event_type TEXT NOT NULL DEFAULT 'event',\n terminal BOOLEAN NOT NULL DEFAULT false,\n sealed BOOLEAN NOT NULL DEFAULT false,\n event_json TEXT NOT NULL DEFAULT '{}',\n occurred_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_workbench_trace_events_trace_seq ON workbench_trace_events(trace_id, source_seq, projected_seq, id);\nCREATE INDEX IF NOT EXISTS idx_workbench_trace_events_session_seq ON workbench_trace_events(session_id, source_seq, projected_seq, id);\n\nWITH duplicate_trace_source_events AS (\n SELECT\n id,\n ROW_NUMBER() OVER (\n PARTITION BY trace_id, source_event_id\n ORDER BY occurred_at, id\n ) AS duplicate_rank\n FROM workbench_trace_events\n WHERE trace_id IS NOT NULL AND source_event_id IS NOT NULL\n), trace_source_event_rewrites AS (\n SELECT\n id,\n 'workbench_trace_events:' || id AS stable_source_event_id\n FROM duplicate_trace_source_events\n WHERE duplicate_rank > 1\n)\nUPDATE workbench_trace_events AS target\nSET\n source_event_id = trace_source_event_rewrites.stable_source_event_id,\n updated_at = COALESCE(NULLIF(target.updated_at, ''), target.occurred_at, CURRENT_TIMESTAMP::text)\nFROM trace_source_event_rewrites\nWHERE target.id = trace_source_event_rewrites.id\n AND target.source_event_id IS DISTINCT FROM trace_source_event_rewrites.stable_source_event_id;\n\nWITH trace_event_projected_seq_conflicts AS (\n SELECT trace_id\n FROM workbench_trace_events\n WHERE trace_id IS NOT NULL\n GROUP BY trace_id\n HAVING COUNT(*) <> COUNT(DISTINCT projected_seq)\n), trace_event_resequence AS (\n SELECT\n workbench_trace_events.id,\n (ROW_NUMBER() OVER (\n PARTITION BY workbench_trace_events.trace_id\n ORDER BY\n CASE WHEN workbench_trace_events.projected_seq > 0 THEN 0 ELSE 1 END,\n workbench_trace_events.projected_seq,\n workbench_trace_events.occurred_at,\n workbench_trace_events.id\n ))::integer AS durable_projected_seq\n FROM workbench_trace_events\n INNER JOIN trace_event_projected_seq_conflicts\n ON trace_event_projected_seq_conflicts.trace_id = workbench_trace_events.trace_id\n)\nUPDATE workbench_trace_events AS target\nSET\n projected_seq = trace_event_resequence.durable_projected_seq,\n source_seq = CASE\n WHEN target.source_seq > 0 THEN target.source_seq\n ELSE trace_event_resequence.durable_projected_seq\n END,\n updated_at = COALESCE(NULLIF(target.updated_at, ''), target.occurred_at, CURRENT_TIMESTAMP::text)\nFROM trace_event_resequence\nWHERE target.id = trace_event_resequence.id\n AND (\n target.projected_seq IS DISTINCT FROM trace_event_resequence.durable_projected_seq\n OR target.source_seq <= 0\n );\n\nDROP INDEX IF EXISTS idx_workbench_trace_events_trace_source_event;\nCREATE UNIQUE INDEX idx_workbench_trace_events_trace_source_event ON workbench_trace_events(trace_id, source_event_id) WHERE source_event_id IS NOT NULL;\nDROP INDEX IF EXISTS idx_workbench_trace_events_trace_projected_seq;\nCREATE UNIQUE INDEX idx_workbench_trace_events_trace_projected_seq ON workbench_trace_events(trace_id, projected_seq);\n\nCREATE TABLE IF NOT EXISTS workbench_event_sequences (\n aggregate_id TEXT PRIMARY KEY,\n aggregate_type TEXT NOT NULL DEFAULT 'trace',\n session_id TEXT,\n turn_id TEXT,\n trace_id TEXT,\n last_seq INTEGER NOT NULL DEFAULT 0,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_workbench_event_sequences_session ON workbench_event_sequences(session_id, updated_at DESC, aggregate_id);\nCREATE INDEX IF NOT EXISTS idx_workbench_event_sequences_trace ON workbench_event_sequences(trace_id, updated_at DESC, aggregate_id);\n\nCREATE TABLE IF NOT EXISTS workbench_events (\n event_seq BIGSERIAL PRIMARY KEY,\n event_id TEXT NOT NULL UNIQUE,\n aggregate_id TEXT NOT NULL,\n aggregate_type TEXT NOT NULL DEFAULT 'trace',\n aggregate_seq INTEGER NOT NULL,\n session_id TEXT,\n turn_id TEXT,\n trace_id TEXT,\n message_id TEXT,\n source_run_id TEXT,\n source_command_id TEXT,\n source_seq INTEGER NOT NULL DEFAULT 0,\n source_event_id TEXT,\n event_type TEXT NOT NULL DEFAULT 'event',\n projection_revision INTEGER NOT NULL DEFAULT 0,\n terminal BOOLEAN NOT NULL DEFAULT false,\n sealed BOOLEAN NOT NULL DEFAULT false,\n payload_json TEXT NOT NULL DEFAULT '{}',\n occurred_at TEXT NOT NULL,\n committed_at TEXT NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_workbench_events_aggregate_seq ON workbench_events(aggregate_id, aggregate_seq);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_workbench_events_aggregate_source_event ON workbench_events(aggregate_id, source_event_id) WHERE source_event_id IS NOT NULL;\nCREATE INDEX IF NOT EXISTS idx_workbench_events_trace_seq ON workbench_events(trace_id, event_seq);\nCREATE INDEX IF NOT EXISTS idx_workbench_events_session_seq ON workbench_events(session_id, event_seq);\nCREATE INDEX IF NOT EXISTS idx_workbench_events_type_seq ON workbench_events(event_type, event_seq);\n\nCREATE TABLE IF NOT EXISTS workbench_projection_checkpoints (\n trace_id TEXT PRIMARY KEY,\n session_id TEXT,\n turn_id TEXT,\n run_id TEXT,\n command_id TEXT,\n projected_seq INTEGER NOT NULL DEFAULT 0,\n source_seq INTEGER NOT NULL DEFAULT 0,\n source_event_id TEXT,\n projection_status TEXT NOT NULL DEFAULT 'projecting',\n projection_health TEXT NOT NULL DEFAULT 'healthy',\n terminal BOOLEAN NOT NULL DEFAULT false,\n sealed BOOLEAN NOT NULL DEFAULT false,\n diagnostic_json TEXT NOT NULL DEFAULT '{}',\n checkpoint_json TEXT NOT NULL DEFAULT '{}',\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_workbench_projection_checkpoints_status_updated ON workbench_projection_checkpoints(projection_status, updated_at DESC, trace_id);\nCREATE INDEX IF NOT EXISTS idx_workbench_projection_checkpoints_session_updated ON workbench_projection_checkpoints(session_id, updated_at DESC, trace_id);\n\nCREATE TABLE IF NOT EXISTS workbench_projection_outbox (\n outbox_seq BIGSERIAL PRIMARY KEY,\n event_seq BIGINT,\n aggregate_id TEXT,\n aggregate_seq INTEGER NOT NULL DEFAULT 0,\n projection_revision INTEGER NOT NULL DEFAULT 0,\n trace_id TEXT NOT NULL,\n session_id TEXT,\n turn_id TEXT,\n message_id TEXT,\n projected_seq INTEGER NOT NULL DEFAULT 0,\n source_seq INTEGER NOT NULL DEFAULT 0,\n source_event_id TEXT,\n commit_type TEXT NOT NULL DEFAULT 'event',\n terminal BOOLEAN NOT NULL DEFAULT false,\n sealed BOOLEAN NOT NULL DEFAULT false,\n payload_json TEXT NOT NULL DEFAULT '{}',\n created_at TEXT NOT NULL\n);\nALTER TABLE workbench_projection_outbox ADD COLUMN IF NOT EXISTS event_seq BIGINT;\nALTER TABLE workbench_projection_outbox ADD COLUMN IF NOT EXISTS aggregate_id TEXT;\nALTER TABLE workbench_projection_outbox ADD COLUMN IF NOT EXISTS aggregate_seq INTEGER NOT NULL DEFAULT 0;\nALTER TABLE workbench_projection_outbox ADD COLUMN IF NOT EXISTS projection_revision INTEGER NOT NULL DEFAULT 0;\nCREATE INDEX IF NOT EXISTS idx_workbench_projection_outbox_trace_seq ON workbench_projection_outbox(trace_id, outbox_seq);\nCREATE INDEX IF NOT EXISTS idx_workbench_projection_outbox_session_seq ON workbench_projection_outbox(session_id, outbox_seq);\nCREATE INDEX IF NOT EXISTS idx_workbench_projection_outbox_after_seq ON workbench_projection_outbox(outbox_seq);\nCREATE INDEX IF NOT EXISTS idx_workbench_projection_outbox_event_seq ON workbench_projection_outbox(event_seq) WHERE event_seq IS NOT NULL;\n\nINSERT INTO workbench_sessions (\n session_id,\n owner_user_id,\n project_id,\n conversation_id,\n thread_id,\n status,\n last_trace_id,\n projected_seq,\n source_seq,\n source_event_id,\n terminal,\n sealed,\n session_json,\n created_at,\n updated_at\n)\nSELECT\n id,\n owner_user_id,\n project_id,\n conversation_id,\n thread_id,\n status,\n last_trace_id,\n 0,\n 0,\n id,\n status IN ('completed', 'failed', 'canceled', 'cancelled', 'archived'),\n status IN ('completed', 'failed', 'canceled', 'cancelled', 'archived') AND ended_at IS NOT NULL,\n COALESCE(NULLIF(session_json, ''), '{}'),\n COALESCE(started_at, updated_at, CURRENT_TIMESTAMP::text),\n COALESCE(updated_at, ended_at, started_at, CURRENT_TIMESTAMP::text)\nFROM agent_sessions\nWHERE id IS NOT NULL\nON CONFLICT (session_id) DO NOTHING;\n\nINSERT INTO workbench_trace_events (\n id,\n trace_id,\n session_id,\n turn_id,\n message_id,\n source_seq,\n source_event_id,\n projected_seq,\n event_type,\n terminal,\n sealed,\n event_json,\n occurred_at,\n updated_at\n)\nSELECT\n source_trace_events.id,\n source_trace_events.trace_id,\n source_trace_events.agent_session_id,\n source_trace_events.trace_id,\n NULL,\n source_trace_events.durable_projection_seq,\n source_trace_events.id,\n source_trace_events.durable_projection_seq,\n 'agent_trace_event',\n false,\n false,\n COALESCE(NULLIF(source_trace_events.event_json, ''), '{}'),\n source_trace_events.occurred_at,\n source_trace_events.occurred_at\nFROM (\n SELECT\n agent_trace_events.*,\n (ROW_NUMBER() OVER (PARTITION BY trace_id ORDER BY occurred_at, id))::integer AS durable_projection_seq\n FROM agent_trace_events\n WHERE id IS NOT NULL AND trace_id IS NOT NULL\n) AS source_trace_events\nON CONFLICT DO NOTHING;\n\nINSERT INTO workbench_turns (\n turn_id,\n session_id,\n trace_id,\n message_id,\n status,\n projected_seq,\n source_seq,\n source_event_id,\n terminal,\n sealed,\n final_response_json,\n diagnostic_json,\n turn_json,\n created_at,\n updated_at\n)\nSELECT\n trace_id,\n COALESCE(session_id, trace_id),\n trace_id,\n NULL,\n projection_status,\n last_projected_seq,\n last_agentrun_seq,\n trace_id || ':' || last_agentrun_seq::text,\n projection_status IN ('caught_up', 'terminal'),\n projection_status = 'terminal',\n 'null',\n COALESCE(NULLIF(projection_json, ''), '{}'),\n COALESCE(NULLIF(projection_json, ''), '{}'),\n COALESCE(created_at, updated_at, CURRENT_TIMESTAMP::text),\n COALESCE(updated_at, created_at, CURRENT_TIMESTAMP::text)\nFROM workbench_projection_state\nWHERE trace_id IS NOT NULL\nON CONFLICT (turn_id) DO NOTHING;\n\nINSERT INTO workbench_projection_checkpoints (\n trace_id,\n session_id,\n turn_id,\n run_id,\n command_id,\n projected_seq,\n source_seq,\n source_event_id,\n projection_status,\n projection_health,\n terminal,\n sealed,\n diagnostic_json,\n checkpoint_json,\n created_at,\n updated_at\n)\nSELECT\n trace_id,\n session_id,\n trace_id,\n run_id,\n command_id,\n last_projected_seq,\n last_agentrun_seq,\n trace_id || ':' || last_agentrun_seq::text,\n projection_status,\n projection_health,\n projection_status IN ('caught_up', 'terminal'),\n projection_status = 'terminal',\n COALESCE(NULLIF(projection_json, ''), '{}'),\n COALESCE(NULLIF(projection_json, ''), '{}'),\n COALESCE(created_at, updated_at, CURRENT_TIMESTAMP::text),\n COALESCE(updated_at, created_at, CURRENT_TIMESTAMP::text)\nFROM workbench_projection_state\nWHERE trace_id IS NOT NULL\nON CONFLICT (trace_id) DO NOTHING;\n\nCREATE TABLE IF NOT EXISTS evidence_records (\n id TEXT PRIMARY KEY,\n project_id TEXT,\n operation_id TEXT,\n evidence_type TEXT NOT NULL,\n uri TEXT NOT NULL DEFAULT '',\n metadata_json TEXT NOT NULL DEFAULT '{}',\n created_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS hwlab_schema_migrations (\n id TEXT PRIMARY KEY,\n schema_version TEXT NOT NULL,\n applied_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,\n migration_json TEXT NOT NULL DEFAULT '{}'\n);\n\nINSERT INTO hwlab_schema_migrations (id, schema_version, applied_at, migration_json)\nVALUES (\n '0001_cloud_core_skeleton',\n 'runtime-durable-postgres-v6',\n CURRENT_TIMESTAMP,\n '{\"path\":\"internal/db/migrations/0001_cloud_core_skeleton.sql\",\"runtime\":\"cloud-api\"}'\n)\nON CONFLICT (id) DO UPDATE SET\n schema_version = EXCLUDED.schema_version,\n migration_json = EXCLUDED.migration_json;\n"
|
|
}
|
|
},
|
|
{
|
|
"apiVersion": "v1",
|
|
"kind": "Service",
|
|
"metadata": {
|
|
"name": "hwlab-v03-postgres",
|
|
"namespace": "hwlab-v03",
|
|
"labels": {
|
|
"app.kubernetes.io/name": "hwlab-v03-postgres",
|
|
"app.kubernetes.io/part-of": "hwlab",
|
|
"hwlab.pikastech.local/environment": "v03",
|
|
"hwlab.pikastech.local/gitops-target": "v03",
|
|
"hwlab.pikastech.local/profile": "v03",
|
|
"hwlab.pikastech.local/source-commit": "66cdf0b8f7c0bae2e0b8c95783f38034ecb9a452"
|
|
}
|
|
},
|
|
"spec": {
|
|
"type": "ClusterIP",
|
|
"selector": {
|
|
"app.kubernetes.io/name": "hwlab-v03-postgres"
|
|
},
|
|
"ports": [
|
|
{
|
|
"name": "postgres",
|
|
"port": 5432,
|
|
"targetPort": "postgres"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"apiVersion": "apps/v1",
|
|
"kind": "StatefulSet",
|
|
"metadata": {
|
|
"name": "hwlab-v03-postgres",
|
|
"namespace": "hwlab-v03",
|
|
"labels": {
|
|
"app.kubernetes.io/name": "hwlab-v03-postgres",
|
|
"app.kubernetes.io/part-of": "hwlab",
|
|
"hwlab.pikastech.local/environment": "v03",
|
|
"hwlab.pikastech.local/gitops-target": "v03",
|
|
"hwlab.pikastech.local/profile": "v03",
|
|
"hwlab.pikastech.local/source-commit": "66cdf0b8f7c0bae2e0b8c95783f38034ecb9a452"
|
|
}
|
|
},
|
|
"spec": {
|
|
"serviceName": "hwlab-v03-postgres",
|
|
"replicas": 1,
|
|
"selector": {
|
|
"matchLabels": {
|
|
"app.kubernetes.io/name": "hwlab-v03-postgres"
|
|
}
|
|
},
|
|
"template": {
|
|
"metadata": {
|
|
"labels": {
|
|
"app.kubernetes.io/name": "hwlab-v03-postgres",
|
|
"app.kubernetes.io/part-of": "hwlab",
|
|
"hwlab.pikastech.local/environment": "v03",
|
|
"hwlab.pikastech.local/gitops-target": "v03",
|
|
"hwlab.pikastech.local/profile": "v03",
|
|
"hwlab.pikastech.local/migration-sha256": "76620977d7c018d8"
|
|
},
|
|
"annotations": {
|
|
"hwlab.pikastech.local/migration-sha256": "76620977d7c018d8de28f14dda27e86635da942faee8b927a849c023eaf46439"
|
|
}
|
|
},
|
|
"spec": {
|
|
"containers": [
|
|
{
|
|
"name": "postgres",
|
|
"image": "postgres:16-alpine",
|
|
"imagePullPolicy": "IfNotPresent",
|
|
"env": [
|
|
{
|
|
"name": "POSTGRES_DB",
|
|
"value": "hwlab_v03"
|
|
},
|
|
{
|
|
"name": "POSTGRES_USER",
|
|
"value": "hwlab_v03"
|
|
},
|
|
{
|
|
"name": "POSTGRES_PASSWORD",
|
|
"valueFrom": {
|
|
"secretKeyRef": {
|
|
"name": "hwlab-v03-postgres",
|
|
"key": "POSTGRES_PASSWORD"
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"ports": [
|
|
{
|
|
"name": "postgres",
|
|
"containerPort": 5432
|
|
}
|
|
],
|
|
"readinessProbe": {
|
|
"tcpSocket": {
|
|
"port": "postgres"
|
|
},
|
|
"initialDelaySeconds": 5,
|
|
"periodSeconds": 10
|
|
},
|
|
"livenessProbe": {
|
|
"tcpSocket": {
|
|
"port": "postgres"
|
|
},
|
|
"initialDelaySeconds": 30,
|
|
"periodSeconds": 20
|
|
},
|
|
"volumeMounts": [
|
|
{
|
|
"name": "data",
|
|
"mountPath": "/var/lib/postgresql/data"
|
|
},
|
|
{
|
|
"name": "init",
|
|
"mountPath": "/docker-entrypoint-initdb.d",
|
|
"readOnly": true
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"volumes": [
|
|
{
|
|
"name": "init",
|
|
"configMap": {
|
|
"name": "hwlab-v03-postgres-init"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"volumeClaimTemplates": [
|
|
{
|
|
"metadata": {
|
|
"name": "data"
|
|
},
|
|
"spec": {
|
|
"accessModes": [
|
|
"ReadWriteOnce"
|
|
],
|
|
"resources": {
|
|
"requests": {
|
|
"storage": "8Gi"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|