"""The shape ledger: code_shapes (#2787, milestone 294)

Revision ID: 0079
Revises: 0078
Create Date: 2026-08-19

The accounting half of the pattern system (governing note 2786): the snippet
library records canon (small); this table accounts for EVERY shape the
coverage extractor finds in a bound repo (total). Rows arrive `unclassified`
from the coverage sync (step 2) and gain judgments — canonical / instance /
variant / exempt — from audits, hooks, and the mechanical proposer.
Unclassified IS the todo list.
"""
import sqlalchemy as sa
from alembic import op

revision = "0079"
down_revision = "0078"
branch_labels = None
depends_on = None


def upgrade() -> None:
    op.create_table(
        "code_shapes",
        sa.Column("id", sa.Integer(), primary_key=True),
        sa.Column(
            "project_id",
            sa.Integer(),
            sa.ForeignKey("projects.id", ondelete="CASCADE"),
            nullable=False,
        ),
        sa.Column("repo_key", sa.Text(), nullable=False),
        sa.Column("path", sa.Text(), nullable=False),
        sa.Column("symbol", sa.Text(), nullable=False),
        sa.Column("kind", sa.Text(), nullable=False),
        sa.Column("status", sa.Text(), nullable=False, server_default="unclassified"),
        sa.Column(
            "snippet_id",
            sa.BigInteger(),
            sa.ForeignKey("notes.id", ondelete="SET NULL"),
            nullable=True,
        ),
        sa.Column("reason", sa.Text(), nullable=True),
        sa.Column("classified_by", sa.Text(), nullable=True),
        sa.Column("classified_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column("first_seen_commit", sa.Text(), nullable=False, server_default=""),
        sa.Column("last_seen_commit", sa.Text(), nullable=False, server_default=""),
        sa.Column("vanished_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
        sa.UniqueConstraint(
            "project_id", "repo_key", "path", "symbol", "kind",
            name="uq_code_shapes_identity",
        ),
    )
    op.create_index(
        "ix_code_shapes_project_status", "code_shapes", ["project_id", "status"]
    )
    op.create_index("ix_code_shapes_snippet", "code_shapes", ["snippet_id"])


def downgrade() -> None:
    op.drop_index("ix_code_shapes_snippet", table_name="code_shapes")
    op.drop_index("ix_code_shapes_project_status", table_name="code_shapes")
    op.drop_table("code_shapes")
