"""v0.2 baseline schema (Postgres) Revision ID: 9f2a6c79667e Revises: Create Date: 2026-05-16 17:58:43.967026 """ from collections.abc import Sequence import sqlalchemy as sa from alembic import op # revision identifiers, used by Alembic. revision: str = "9f2a6c79667e" down_revision: str | Sequence[str] | None = None branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None def upgrade() -> None: """Upgrade schema.""" # ### commands auto generated by Alembic - please adjust! ### op.create_table( "agent_personas", sa.Column("id", sa.String(length=36), nullable=False), sa.Column("name", sa.Text(), nullable=False), sa.Column("version", sa.Integer(), nullable=False), sa.Column("hash", sa.Text(), nullable=False), sa.Column("definition", sa.JSON(), nullable=False), sa.Column("created_at", sa.Text(), nullable=False), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("hash"), ) op.create_table( "budget_ledger", sa.Column("scope", sa.Text(), nullable=False), sa.Column("spent_usd", sa.Float(), nullable=False), sa.Column("cap_usd", sa.Float(), nullable=True), sa.Column("last_updated", sa.Text(), nullable=False), sa.PrimaryKeyConstraint("scope"), ) op.create_table( "model_pricing", sa.Column("model", sa.Text(), nullable=False), sa.Column("input_per_1k_usd", sa.Float(), nullable=False), sa.Column("output_per_1k_usd", sa.Float(), nullable=False), sa.Column("context_length", sa.Integer(), nullable=False), sa.Column("fetched_at", sa.Text(), nullable=False), sa.Column("raw_payload", sa.Text(), nullable=False), sa.PrimaryKeyConstraint("model"), ) op.create_table( "persona_consents", sa.Column("persona_hash", sa.Text(), nullable=False), sa.Column("persona_name", sa.Text(), nullable=False), sa.Column("persona_version", sa.Integer(), nullable=False), sa.Column("decision", sa.Text(), nullable=False), sa.Column("decided_at", sa.Text(), nullable=False), sa.PrimaryKeyConstraint("persona_hash"), ) op.create_table( "workflow_templates", sa.Column("id", sa.String(length=36), nullable=False), sa.Column("name", sa.Text(), nullable=False), sa.Column("version", sa.Integer(), nullable=False), sa.Column("hash", sa.Text(), nullable=False), sa.Column("definition", sa.JSON(), nullable=False), sa.Column("created_at", sa.Text(), nullable=False), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("hash"), ) op.create_table( "interactive_sessions", sa.Column("id", sa.String(length=36), nullable=False), sa.Column("persona_id", sa.String(length=36), nullable=False), sa.Column("persona_hash", sa.Text(), nullable=False), sa.Column("started_at", sa.Text(), nullable=True), sa.Column("ended_at", sa.Text(), nullable=True), sa.Column("last_message_at", sa.Text(), nullable=True), sa.Column("state", sa.Text(), nullable=False), sa.ForeignKeyConstraint(["persona_id"], ["agent_personas.id"], ondelete="RESTRICT"), sa.PrimaryKeyConstraint("id"), ) op.create_table( "runs", sa.Column("id", sa.String(length=36), nullable=False), sa.Column("template_id", sa.String(length=36), nullable=False), sa.Column("template_hash", sa.Text(), nullable=False), sa.Column("state", sa.Text(), nullable=False), sa.Column("repo_path", sa.Text(), nullable=False), sa.Column("base_branch", sa.Text(), nullable=False), sa.Column("worktree_root", sa.Text(), nullable=False), sa.Column("current_phase_id", sa.String(length=36), nullable=True), sa.Column("started_at", sa.Text(), nullable=True), sa.Column("ended_at", sa.Text(), nullable=True), sa.Column("final_report_path", sa.Text(), nullable=True), sa.Column("paused_from_state", sa.Text(), nullable=True), sa.Column("created_at", sa.Text(), nullable=False), sa.Column("updated_at", sa.Text(), nullable=False), sa.ForeignKeyConstraint(["template_id"], ["workflow_templates.id"], ondelete="RESTRICT"), sa.PrimaryKeyConstraint("id"), ) op.create_index( "ux_active_run_repo_base", "runs", ["repo_path", "base_branch"], unique=True, postgresql_where=sa.text("state NOT IN ('completed', 'failed', 'aborted')"), sqlite_where=sa.text("state NOT IN ('completed', 'failed', 'aborted')"), ) op.create_table( "run_bindings", sa.Column("id", sa.String(length=36), nullable=False), sa.Column("run_id", sa.String(length=36), nullable=False), sa.Column("role_id", sa.Text(), nullable=False), sa.Column("persona_id", sa.String(length=36), nullable=False), sa.Column("persona_hash", sa.Text(), nullable=False), sa.Column("backend", sa.Text(), nullable=False), sa.Column("binding_hash", sa.Text(), nullable=False), sa.ForeignKeyConstraint(["persona_id"], ["agent_personas.id"], ondelete="RESTRICT"), sa.ForeignKeyConstraint(["run_id"], ["runs.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("run_id", "role_id", name="uq_run_bindings_run_role"), ) op.create_table( "run_commands", sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), sa.Column("run_id", sa.String(length=36), nullable=False), sa.Column("command", sa.Text(), nullable=False), sa.Column("payload", sa.JSON(), nullable=False), sa.Column("idempotency_key", sa.Text(), nullable=False), sa.Column("created_at", sa.Text(), nullable=False), sa.Column("processed_at", sa.Text(), nullable=True), sa.ForeignKeyConstraint(["run_id"], ["runs.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("idempotency_key"), ) op.create_table( "run_inputs", sa.Column("id", sa.String(length=36), nullable=False), sa.Column("run_id", sa.String(length=36), nullable=False), sa.Column("requirements_md", sa.Text(), nullable=False), sa.Column("objective", sa.JSON(), nullable=False), sa.Column("extra", sa.JSON(), nullable=False), sa.Column("input_hash", sa.Text(), nullable=False), sa.ForeignKeyConstraint(["run_id"], ["runs.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("run_id"), ) op.create_table( "run_phases", sa.Column("id", sa.String(length=36), nullable=False), sa.Column("run_id", sa.String(length=36), nullable=False), sa.Column("phase_key", sa.Text(), nullable=False), sa.Column("seq", sa.Integer(), nullable=False), sa.Column("state", sa.Text(), nullable=False), sa.Column("attempts", sa.Integer(), nullable=False), sa.Column("started_at", sa.Text(), nullable=True), sa.Column("ended_at", sa.Text(), nullable=True), sa.ForeignKeyConstraint(["run_id"], ["runs.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("run_id", "phase_key", name="uq_run_phases_run_phase"), ) op.create_table( "approval_requests", sa.Column("id", sa.String(length=36), nullable=False), sa.Column("run_id", sa.String(length=36), nullable=False), sa.Column("phase_id", sa.String(length=36), nullable=True), sa.Column("gate_key", sa.Text(), nullable=False), sa.Column("state", sa.Text(), nullable=False), sa.Column("idempotency_key", sa.Text(), nullable=False), sa.Column("payload", sa.JSON(), nullable=False), sa.Column("created_at", sa.Text(), nullable=False), sa.Column("resolved_at", sa.Text(), nullable=True), sa.ForeignKeyConstraint(["phase_id"], ["run_phases.id"], ondelete="CASCADE"), sa.ForeignKeyConstraint(["run_id"], ["runs.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("idempotency_key"), ) op.create_table( "artifacts", sa.Column("id", sa.String(length=36), nullable=False), sa.Column("run_id", sa.String(length=36), nullable=False), sa.Column("phase_id", sa.String(length=36), nullable=True), sa.Column("path", sa.Text(), nullable=False), sa.Column("schema_id", sa.Text(), nullable=False), sa.Column("hash", sa.Text(), nullable=False), sa.Column("valid", sa.Boolean(), nullable=False), sa.Column("validation_error", sa.JSON(), nullable=True), sa.Column("created_at", sa.Text(), nullable=False), sa.ForeignKeyConstraint(["phase_id"], ["run_phases.id"], ondelete="CASCADE"), sa.ForeignKeyConstraint(["run_id"], ["runs.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("run_id", "path", "hash", name="uq_artifacts_run_path_hash"), ) op.create_table( "llm_calls", sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), sa.Column("run_id", sa.String(length=36), nullable=True), sa.Column("phase_id", sa.String(length=36), nullable=True), sa.Column("interactive_session_id", sa.String(length=36), nullable=True), sa.Column("thread_id", sa.Text(), nullable=False), sa.Column("persona_name", sa.Text(), nullable=False), sa.Column("persona_version", sa.Integer(), nullable=False), sa.Column("model", sa.Text(), nullable=False), sa.Column("role", sa.Text(), nullable=False), sa.Column("turn_index", sa.Integer(), nullable=False), sa.Column("input_tokens", sa.Integer(), nullable=False), sa.Column("output_tokens", sa.Integer(), nullable=False), sa.Column("cached_tokens", sa.Integer(), nullable=False), sa.Column("reasoning_tokens", sa.Integer(), nullable=False), sa.Column("cost_usd_input", sa.Float(), nullable=False), sa.Column("cost_usd_output", sa.Float(), nullable=False), sa.Column("cost_usd_total", sa.Float(), nullable=False), sa.Column("latency_ms", sa.Integer(), nullable=False), sa.Column("status", sa.Text(), nullable=False), sa.Column("error_code", sa.Text(), nullable=True), sa.Column("request_id", sa.Text(), nullable=True), sa.Column("ts", sa.Text(), nullable=False), sa.ForeignKeyConstraint( ["interactive_session_id"], ["interactive_sessions.id"], ondelete="CASCADE" ), sa.ForeignKeyConstraint(["phase_id"], ["run_phases.id"], ondelete="CASCADE"), sa.ForeignKeyConstraint(["run_id"], ["runs.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), ) op.create_index( "llm_calls_interactive_session_id_ts_idx", "llm_calls", ["interactive_session_id", "ts"], unique=False, ) op.create_index("llm_calls_model_ts_idx", "llm_calls", ["model", "ts"], unique=False) op.create_index("llm_calls_run_id_ts_idx", "llm_calls", ["run_id", "ts"], unique=False) op.create_table( "phase_feedback", sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), sa.Column("run_id", sa.String(length=36), nullable=False), sa.Column("phase_id", sa.String(length=36), nullable=False), sa.Column("reaction", sa.Text(), nullable=True), sa.Column("comment", sa.Text(), nullable=True), sa.Column("created_at", sa.Text(), nullable=False), sa.ForeignKeyConstraint(["phase_id"], ["run_phases.id"], ondelete="CASCADE"), sa.ForeignKeyConstraint(["run_id"], ["runs.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), ) op.create_table( "run_events", sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), sa.Column("run_id", sa.String(length=36), nullable=False), sa.Column("phase_id", sa.String(length=36), nullable=True), sa.Column("seq", sa.Integer(), nullable=False), sa.Column("type", sa.Text(), nullable=False), sa.Column("payload", sa.JSON(), nullable=False), sa.Column("idempotency_key", sa.Text(), nullable=False), sa.Column("ts", sa.Text(), nullable=False), sa.ForeignKeyConstraint(["phase_id"], ["run_phases.id"], ondelete="CASCADE"), sa.ForeignKeyConstraint(["run_id"], ["runs.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("run_id", "idempotency_key", name="uq_run_events_run_idempotency"), sa.UniqueConstraint("run_id", "seq", name="uq_run_events_run_seq"), ) op.create_index("run_events_run_id_ts_idx", "run_events", ["run_id", "ts"], unique=False) op.create_table( "tool_calls", sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), sa.Column("run_id", sa.String(length=36), nullable=True), sa.Column("phase_id", sa.String(length=36), nullable=True), sa.Column("interactive_session_id", sa.String(length=36), nullable=True), sa.Column("tool_name", sa.Text(), nullable=False), sa.Column("args", sa.JSON(), nullable=False), sa.Column("result", sa.JSON(), nullable=True), sa.Column("error", sa.Text(), nullable=True), sa.Column("duration_ms", sa.Integer(), nullable=False), sa.Column("ts", sa.Text(), nullable=False), sa.ForeignKeyConstraint( ["interactive_session_id"], ["interactive_sessions.id"], ondelete="CASCADE" ), sa.ForeignKeyConstraint(["phase_id"], ["run_phases.id"], ondelete="CASCADE"), sa.ForeignKeyConstraint(["run_id"], ["runs.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), ) op.create_index("tool_calls_run_id_ts_idx", "tool_calls", ["run_id", "ts"], unique=False) op.create_table( "approval_decisions", sa.Column("id", sa.String(length=36), nullable=False), sa.Column("approval_request_id", sa.String(length=36), nullable=False), sa.Column("action", sa.Text(), nullable=False), sa.Column("comment", sa.Text(), nullable=True), sa.Column("decided_at", sa.Text(), nullable=False), sa.Column("idempotency_key", sa.Text(), nullable=False), sa.ForeignKeyConstraint( ["approval_request_id"], ["approval_requests.id"], ondelete="CASCADE" ), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("idempotency_key"), ) # ### end Alembic commands ### def downgrade() -> None: """Downgrade schema.""" # ### commands auto generated by Alembic - please adjust! ### op.drop_table("approval_decisions") op.drop_index("tool_calls_run_id_ts_idx", table_name="tool_calls") op.drop_table("tool_calls") op.drop_index("run_events_run_id_ts_idx", table_name="run_events") op.drop_table("run_events") op.drop_table("phase_feedback") op.drop_index("llm_calls_run_id_ts_idx", table_name="llm_calls") op.drop_index("llm_calls_model_ts_idx", table_name="llm_calls") op.drop_index("llm_calls_interactive_session_id_ts_idx", table_name="llm_calls") op.drop_table("llm_calls") op.drop_table("artifacts") op.drop_table("approval_requests") op.drop_table("run_phases") op.drop_table("run_inputs") op.drop_table("run_commands") op.drop_table("run_bindings") op.drop_index( "ux_active_run_repo_base", table_name="runs", postgresql_where=sa.text("state NOT IN ('completed', 'failed', 'aborted')"), sqlite_where=sa.text("state NOT IN ('completed', 'failed', 'aborted')"), ) op.drop_table("runs") op.drop_table("interactive_sessions") op.drop_table("workflow_templates") op.drop_table("persona_consents") op.drop_table("model_pricing") op.drop_table("budget_ledger") op.drop_table("agent_personas") # ### end Alembic commands ###