444 lines
9.9 KiB
TypeScript
444 lines
9.9 KiB
TypeScript
/*
|
|
* SPEC: PJ2026-010403 API契约 draft-2026-06-17-r0; PJ2026-0102 Agent编排 draft-2026-06-17-r0; PJ2026-0104010803 Workbench唯一投影 draft-2026-06-24-p0-aggregate-event-stream; PJ2026-010205 HWLAB接入 draft-2026-06-25-p0-session-warm-runner-contract.
|
|
* 职责: Cloud runtime durable schema contract。Workbench/Code Agent 投影表必须纳入启动 readiness 和迁移一致性检查。
|
|
*/
|
|
import { TABLES } from "../protocol/index.mjs";
|
|
|
|
export const CLOUD_CORE_MIGRATION_ID = "0001_cloud_core_skeleton";
|
|
export const CLOUD_RUNTIME_DURABLE_ADAPTER_SCHEMA_VERSION = "runtime-durable-postgres-v7";
|
|
export const CLOUD_TRANSACTIONAL_REALTIME_MIGRATION_ID = "0008_workbench_kafka_realtime";
|
|
export const CLOUD_TRANSACTIONAL_REALTIME_SCHEMA_VERSION = "runtime-durable-postgres-v8";
|
|
export const CLOUD_RUNTIME_DURABLE_MIGRATION_TABLE = "hwlab_schema_migrations";
|
|
|
|
export const FROZEN_CLOUD_CORE_TABLES = Object.freeze([...TABLES]);
|
|
|
|
export const CLOUD_RUNTIME_DURABLE_MIGRATION_TABLE_COLUMNS = Object.freeze([
|
|
"id",
|
|
"schema_version",
|
|
"applied_at",
|
|
"migration_json"
|
|
]);
|
|
|
|
export const CLOUD_RUNTIME_DURABLE_TABLE_COLUMNS = Object.freeze({
|
|
users: Object.freeze([
|
|
"id",
|
|
"username",
|
|
"display_name",
|
|
"role",
|
|
"status",
|
|
"password_hash",
|
|
"created_at",
|
|
"updated_at"
|
|
]),
|
|
user_sessions: Object.freeze([
|
|
"id",
|
|
"user_id",
|
|
"session_token_hash",
|
|
"created_at",
|
|
"last_seen_at",
|
|
"expires_at",
|
|
"revoked_at"
|
|
]),
|
|
gateway_sessions: Object.freeze([
|
|
"id",
|
|
"project_id",
|
|
"gateway_service_id",
|
|
"status",
|
|
"started_at",
|
|
"ended_at",
|
|
"gateway_session_json"
|
|
]),
|
|
box_resources: Object.freeze([
|
|
"id",
|
|
"project_id",
|
|
"gateway_session_id",
|
|
"resource_state",
|
|
"labels_json",
|
|
"resource_json",
|
|
"updated_at"
|
|
]),
|
|
box_capabilities: Object.freeze([
|
|
"id",
|
|
"box_resource_id",
|
|
"capability_type",
|
|
"capability_json",
|
|
"updated_at"
|
|
]),
|
|
hardware_operations: Object.freeze([
|
|
"id",
|
|
"project_id",
|
|
"requested_by",
|
|
"operation_type",
|
|
"operation_json",
|
|
"status",
|
|
"requested_at",
|
|
"updated_at"
|
|
]),
|
|
audit_events: Object.freeze([
|
|
"id",
|
|
"request_id",
|
|
"actor",
|
|
"source",
|
|
"operation",
|
|
"target",
|
|
"result",
|
|
"timestamp",
|
|
"event_json"
|
|
]),
|
|
evidence_records: Object.freeze([
|
|
"id",
|
|
"project_id",
|
|
"operation_id",
|
|
"evidence_type",
|
|
"uri",
|
|
"metadata_json",
|
|
"created_at"
|
|
]),
|
|
agent_sessions: Object.freeze([
|
|
"id",
|
|
"project_id",
|
|
"agent_id",
|
|
"status",
|
|
"started_at",
|
|
"ended_at",
|
|
"owner_user_id",
|
|
"conversation_id",
|
|
"thread_id",
|
|
"last_trace_id",
|
|
"session_json",
|
|
"updated_at"
|
|
]),
|
|
account_workspaces: Object.freeze([
|
|
"id",
|
|
"owner_user_id",
|
|
"project_id",
|
|
"name",
|
|
"status",
|
|
"is_default",
|
|
"selected_conversation_id",
|
|
"selected_agent_session_id",
|
|
"active_trace_id",
|
|
"provider_profile",
|
|
"workspace_json",
|
|
"revision",
|
|
"updated_by_session_id",
|
|
"updated_by_client",
|
|
"created_at",
|
|
"updated_at"
|
|
]),
|
|
worker_sessions: Object.freeze([
|
|
"id",
|
|
"agent_session_id",
|
|
"worker_id",
|
|
"status",
|
|
"started_at",
|
|
"ended_at"
|
|
]),
|
|
agent_trace_events: Object.freeze([
|
|
"id",
|
|
"trace_id",
|
|
"agent_session_id",
|
|
"worker_session_id",
|
|
"level",
|
|
"message",
|
|
"event_json",
|
|
"occurred_at"
|
|
]),
|
|
workbench_projection_state: Object.freeze([
|
|
"trace_id",
|
|
"session_id",
|
|
"conversation_id",
|
|
"thread_id",
|
|
"run_id",
|
|
"command_id",
|
|
"last_agentrun_seq",
|
|
"last_projected_seq",
|
|
"upstream_latest_seq",
|
|
"projection_status",
|
|
"projection_health",
|
|
"result_sync_state",
|
|
"last_projected_at",
|
|
"last_result_sync_at",
|
|
"last_error_code",
|
|
"last_error_message",
|
|
"failure_count",
|
|
"next_retry_at",
|
|
"projection_json",
|
|
"created_at",
|
|
"updated_at"
|
|
]),
|
|
workbench_sessions: Object.freeze([
|
|
"session_id",
|
|
"owner_user_id",
|
|
"project_id",
|
|
"conversation_id",
|
|
"thread_id",
|
|
"status",
|
|
"last_trace_id",
|
|
"projected_seq",
|
|
"source_seq",
|
|
"source_event_id",
|
|
"terminal",
|
|
"sealed",
|
|
"session_json",
|
|
"created_at",
|
|
"updated_at"
|
|
]),
|
|
workbench_messages: Object.freeze([
|
|
"message_id",
|
|
"session_id",
|
|
"turn_id",
|
|
"trace_id",
|
|
"role",
|
|
"status",
|
|
"projected_seq",
|
|
"source_seq",
|
|
"source_event_id",
|
|
"terminal",
|
|
"sealed",
|
|
"message_json",
|
|
"created_at",
|
|
"updated_at"
|
|
]),
|
|
workbench_parts: Object.freeze([
|
|
"part_id",
|
|
"message_id",
|
|
"session_id",
|
|
"turn_id",
|
|
"trace_id",
|
|
"part_index",
|
|
"part_type",
|
|
"status",
|
|
"projected_seq",
|
|
"source_seq",
|
|
"source_event_id",
|
|
"terminal",
|
|
"sealed",
|
|
"part_json",
|
|
"created_at",
|
|
"updated_at"
|
|
]),
|
|
workbench_turns: Object.freeze([
|
|
"turn_id",
|
|
"session_id",
|
|
"trace_id",
|
|
"message_id",
|
|
"status",
|
|
"projected_seq",
|
|
"source_seq",
|
|
"source_event_id",
|
|
"terminal",
|
|
"sealed",
|
|
"final_response_json",
|
|
"diagnostic_json",
|
|
"turn_json",
|
|
"created_at",
|
|
"updated_at"
|
|
]),
|
|
workbench_trace_events: Object.freeze([
|
|
"id",
|
|
"trace_id",
|
|
"session_id",
|
|
"turn_id",
|
|
"message_id",
|
|
"source_seq",
|
|
"source_event_id",
|
|
"projected_seq",
|
|
"event_type",
|
|
"terminal",
|
|
"sealed",
|
|
"event_json",
|
|
"occurred_at",
|
|
"updated_at"
|
|
]),
|
|
workbench_event_sequences: Object.freeze([
|
|
"aggregate_id",
|
|
"aggregate_type",
|
|
"session_id",
|
|
"turn_id",
|
|
"trace_id",
|
|
"last_seq",
|
|
"created_at",
|
|
"updated_at"
|
|
]),
|
|
workbench_events: Object.freeze([
|
|
"event_seq",
|
|
"event_id",
|
|
"aggregate_id",
|
|
"aggregate_type",
|
|
"aggregate_seq",
|
|
"session_id",
|
|
"turn_id",
|
|
"trace_id",
|
|
"message_id",
|
|
"source_run_id",
|
|
"source_command_id",
|
|
"source_seq",
|
|
"source_event_id",
|
|
"event_type",
|
|
"projection_revision",
|
|
"terminal",
|
|
"sealed",
|
|
"payload_json",
|
|
"occurred_at",
|
|
"committed_at"
|
|
]),
|
|
workbench_session_inputs: Object.freeze([
|
|
"input_id",
|
|
"session_id",
|
|
"turn_id",
|
|
"trace_id",
|
|
"message_id",
|
|
"command_id",
|
|
"delivery",
|
|
"admitted_seq",
|
|
"promoted_seq",
|
|
"status",
|
|
"error_code",
|
|
"source_event_id",
|
|
"input_json",
|
|
"created_at",
|
|
"updated_at"
|
|
]),
|
|
workbench_projection_checkpoints: Object.freeze([
|
|
"trace_id",
|
|
"session_id",
|
|
"turn_id",
|
|
"run_id",
|
|
"command_id",
|
|
"projected_seq",
|
|
"source_seq",
|
|
"source_event_id",
|
|
"projection_status",
|
|
"projection_health",
|
|
"terminal",
|
|
"sealed",
|
|
"diagnostic_json",
|
|
"checkpoint_json",
|
|
"created_at",
|
|
"updated_at"
|
|
]),
|
|
workbench_projection_outbox: Object.freeze([
|
|
"outbox_seq",
|
|
"event_seq",
|
|
"aggregate_id",
|
|
"aggregate_seq",
|
|
"projection_revision",
|
|
"trace_id",
|
|
"session_id",
|
|
"turn_id",
|
|
"message_id",
|
|
"projected_seq",
|
|
"source_seq",
|
|
"source_event_id",
|
|
"commit_type",
|
|
"terminal",
|
|
"sealed",
|
|
"payload_json",
|
|
"created_at"
|
|
])
|
|
});
|
|
|
|
export const CLOUD_TRANSACTIONAL_REALTIME_TABLE_COLUMNS = Object.freeze({
|
|
workbench_projection_outbox: Object.freeze([
|
|
"outbox_event_id",
|
|
"entity_family",
|
|
"entity_id"
|
|
]),
|
|
workbench_kafka_inbox: Object.freeze([
|
|
"source_topic",
|
|
"source_partition",
|
|
"source_offset",
|
|
"source_key",
|
|
"source_event_id",
|
|
"input_sha256",
|
|
"trace_id",
|
|
"session_id",
|
|
"run_id",
|
|
"command_id",
|
|
"source_seq",
|
|
"status",
|
|
"projected_seq",
|
|
"envelope_json",
|
|
"error_json",
|
|
"created_at",
|
|
"updated_at",
|
|
"projected_at"
|
|
]),
|
|
workbench_kafka_dlq: Object.freeze([
|
|
"dlq_seq",
|
|
"source_topic",
|
|
"source_partition",
|
|
"source_offset",
|
|
"source_event_id",
|
|
"input_sha256",
|
|
"error_code",
|
|
"error_message",
|
|
"envelope_json",
|
|
"created_at"
|
|
]),
|
|
hwlab_kafka_outbox: Object.freeze([
|
|
"outbox_seq",
|
|
"event_id",
|
|
"topic",
|
|
"partition_key",
|
|
"payload_json",
|
|
"headers_json",
|
|
"attempt_count",
|
|
"next_attempt_at",
|
|
"lease_owner",
|
|
"lease_expires_at",
|
|
"published_at",
|
|
"last_error",
|
|
"created_at",
|
|
"updated_at"
|
|
])
|
|
});
|
|
|
|
export const CLOUD_TRANSACTIONAL_REALTIME_REQUIRED_TABLE_COLUMNS = Object.freeze({
|
|
...CLOUD_RUNTIME_DURABLE_TABLE_COLUMNS,
|
|
...CLOUD_TRANSACTIONAL_REALTIME_TABLE_COLUMNS,
|
|
workbench_projection_outbox: Object.freeze([
|
|
...CLOUD_RUNTIME_DURABLE_TABLE_COLUMNS.workbench_projection_outbox,
|
|
...CLOUD_TRANSACTIONAL_REALTIME_TABLE_COLUMNS.workbench_projection_outbox
|
|
])
|
|
});
|
|
|
|
export const CLOUD_CORE_MIGRATIONS = Object.freeze([
|
|
{
|
|
id: CLOUD_CORE_MIGRATION_ID,
|
|
path: "internal/db/migrations/0001_cloud_core_skeleton.sql",
|
|
tables: FROZEN_CLOUD_CORE_TABLES,
|
|
connectsToDatabase: false,
|
|
runtimeDurableAdapterSchemaVersion: "runtime-durable-postgres-v7",
|
|
runtimeDurableMigrationTable: CLOUD_RUNTIME_DURABLE_MIGRATION_TABLE
|
|
},
|
|
{
|
|
id: CLOUD_TRANSACTIONAL_REALTIME_MIGRATION_ID,
|
|
path: "internal/db/migrations/0008_workbench_kafka_realtime.sql",
|
|
tables: Object.freeze(["workbench_projection_outbox", "workbench_kafka_inbox", "workbench_kafka_dlq", "hwlab_kafka_outbox"]),
|
|
connectsToDatabase: false,
|
|
runtimeDurableAdapterSchemaVersion: CLOUD_TRANSACTIONAL_REALTIME_SCHEMA_VERSION,
|
|
runtimeDurableMigrationTable: CLOUD_RUNTIME_DURABLE_MIGRATION_TABLE
|
|
}
|
|
]);
|
|
|
|
export function assertFrozenCloudCoreTables(tables = FROZEN_CLOUD_CORE_TABLES) {
|
|
const missing = TABLES.filter((table) => !tables.includes(table));
|
|
if (missing.length > 0) {
|
|
throw new Error(`cloud core schema is missing frozen tables: ${missing.join(", ")}`);
|
|
}
|
|
}
|
|
|
|
export function requiredRuntimeDurableColumns() {
|
|
return Object.entries(CLOUD_RUNTIME_DURABLE_TABLE_COLUMNS).flatMap(([table, columns]) =>
|
|
columns.map((column) => `${table}.${column}`)
|
|
);
|
|
}
|
|
|
|
export function requiredTransactionalRealtimeColumns() {
|
|
return Object.entries(CLOUD_TRANSACTIONAL_REALTIME_TABLE_COLUMNS).flatMap(([table, columns]) =>
|
|
columns.map((column) => `${table}.${column}`)
|
|
);
|
|
}
|