"""Add run, run_node, run_metric and run_artifact Runs are the batch shape of the engine: a flow taken from its inputs to its outputs once, with parameters that identify it and a result worth keeping. Deliberately its own tables rather than columns on flow_run — a cascade row is rolled up and pruned on a retention window, and an experiment must not be. Revision ID: a3f1c07b52d9 Revises: 087c44e16304 Create Date: 2026-08-18 09:12:44.108312 """ import sqlalchemy as sa import sqlmodel.sql.sqltypes from alembic import op # revision identifiers, used by Alembic. revision = 'a3f1c07b52d9' down_revision = '087c44e16304' branch_labels = None depends_on = None def upgrade(): op.create_table( 'run', sa.Column('id', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('flow', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), sa.Column('flow_version', sa.Integer(), nullable=False), sa.Column('commit', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('params', sa.JSON(), nullable=True), sa.Column( 'params_digest', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False, ), sa.Column('seed', sa.Integer(), nullable=True), sa.Column('group_id', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=True), sa.Column('parent_id', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=True), sa.Column('cause', sqlmodel.sql.sqltypes.AutoString(length=32), nullable=False), sa.Column('status', sqlmodel.sql.sqltypes.AutoString(length=16), nullable=False), sa.Column( 'status_reason', sqlmodel.sql.sqltypes.AutoString(length=1024), nullable=False, ), sa.Column('labels', sa.JSON(), nullable=True), sa.Column('created_at', sa.DateTime(timezone=True), nullable=False), sa.Column('started_at', sa.DateTime(timezone=True), nullable=True), sa.Column('finished_at', sa.DateTime(timezone=True), nullable=True), sa.Column('duration_ms', sa.Float(), nullable=False), sa.Column('result', sa.JSON(), nullable=True), sa.Column('engine', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('lease_at', sa.DateTime(timezone=True), nullable=True), sa.Column('actor', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), sa.PrimaryKeyConstraint('id'), ) op.create_index(op.f('ix_run_flow'), 'run', ['flow'], unique=False) op.create_index(op.f('ix_run_status'), 'run', ['status'], unique=False) op.create_index(op.f('ix_run_group_id'), 'run', ['group_id'], unique=False) op.create_index(op.f('ix_run_created_at'), 'run', ['created_at'], unique=False) op.create_index( op.f('ix_run_params_digest'), 'run', ['params_digest'], unique=False ) op.create_table( 'run_node', sa.Column('run_id', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('node', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), sa.Column('status', sqlmodel.sql.sqltypes.AutoString(length=16), nullable=False), sa.Column('attempt', sa.Integer(), nullable=False), sa.Column('started_at', sa.DateTime(timezone=True), nullable=True), sa.Column('duration_ms', sa.Float(), nullable=False), sa.Column('worker', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('error', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('logs', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column( 'cache_key', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False ), sa.PrimaryKeyConstraint('run_id', 'node'), ) op.create_index( op.f('ix_run_node_cache_key'), 'run_node', ['cache_key'], unique=False ) op.create_table( 'run_metric', sa.Column('run_id', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('name', sqlmodel.sql.sqltypes.AutoString(length=128), nullable=False), sa.Column('step', sa.Integer(), nullable=False), sa.Column('node', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), sa.Column('ts', sa.Float(), nullable=False), sa.Column('value', sa.Float(), nullable=False), sa.PrimaryKeyConstraint('run_id', 'name', 'step'), ) op.create_table( 'run_artifact', sa.Column('run_id', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), sa.Column('node', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), sa.Column('digest', sqlmodel.sql.sqltypes.AutoString(length=71), nullable=False), sa.Column('size', sa.BigInteger(), nullable=False), sa.Column( 'media_type', sqlmodel.sql.sqltypes.AutoString(length=128), nullable=False ), sa.Column('created_at', sa.DateTime(timezone=True), nullable=False), sa.PrimaryKeyConstraint('run_id', 'name'), ) op.create_index( op.f('ix_run_artifact_digest'), 'run_artifact', ['digest'], unique=False ) def downgrade(): op.drop_index(op.f('ix_run_artifact_digest'), table_name='run_artifact') op.drop_table('run_artifact') op.drop_table('run_metric') op.drop_index(op.f('ix_run_node_cache_key'), table_name='run_node') op.drop_table('run_node') op.drop_index(op.f('ix_run_params_digest'), table_name='run') op.drop_index(op.f('ix_run_created_at'), table_name='run') op.drop_index(op.f('ix_run_group_id'), table_name='run') op.drop_index(op.f('ix_run_status'), table_name='run') op.drop_index(op.f('ix_run_flow'), table_name='run') op.drop_table('run')