"""고증 판정 기록 정본 테이블 (append-only).

사람이 **그 사진이 그 시대·그 지역 것인지** 정한 기록. coarse 심판은
「무엇인가 · 보이는가」만 보므로, 그 사진이 맞는지는 사람만 정한다
(사용자 확정 2026-08-31 · Codex 계약 2026-09-02).

★additive 다. 기존 테이블·칸을 하나도 안 건드린다 — 되돌리기가 drop 하나다.

Revision ID: 012_grounding_fidelity_review

★id 는 **32자 안**이어야 한다 — `alembic_version.version_num` 이
  `varchar(32)` 다. 앞 판은 39자라 표는 만들고 판 기록에서 죽었다.
Revises: 011_grounding_research_revision
"""
from typing import Sequence, Union

import sqlalchemy as sa
from alembic import op

revision: str = "012_grounding_fidelity_review"
down_revision: Union[str, None] = "011_grounding_research_revision"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    op.create_table(
        "grounding_reference_fidelity_review",
        sa.Column("id", sa.Text(), primary_key=True),
        sa.Column("project_id", sa.Text(),
                  sa.ForeignKey("project_registry.id"), nullable=False),
        sa.Column("episode_id", sa.Text(), nullable=False),
        # ★조회용 칸들 — **정본은 `review_input_json`** 하나다.
        sa.Column("research_subject_id", sa.Text(), nullable=False),
        sa.Column("final_id", sa.Text(), nullable=False, server_default=""),
        sa.Column("purpose", sa.Text(), nullable=False, server_default=""),
        sa.Column("acquisition_identity", sa.Text(), nullable=False),
        sa.Column("image_sha256", sa.Text(), nullable=False),
        # ★요구된 좌표 **원문**. 없으면 빈 값 — 만들지 않는다.
        sa.Column("era", sa.Text(), nullable=False, server_default=""),
        sa.Column("region", sa.Text(), nullable=False, server_default=""),
        # ★입력 신원의 정본 bytes 와 그것에서 계산한 hash.
        sa.Column("review_input_json", sa.Text(), nullable=False),
        sa.Column("review_input_hash", sa.Text(), nullable=False),
        # ★verified | rejected — 닫힌 목록.
        sa.Column("verdict", sa.Text(), nullable=False),
        sa.Column("reason", sa.Text(), nullable=False, server_default=""),
        # ★서버의 인증 주체에서 받는다 — 클라이언트가 임의로 못 보낸다.
        sa.Column("reviewer_actor", sa.Text(), nullable=False),
        sa.Column("reviewed_at", sa.Text(), nullable=False),
        sa.Column("review_contract_version", sa.Text(), nullable=False),
        # ★사람이 **실제로 본** 좌표와 사진 SHA.
        sa.Column("observed_json", sa.Text(), nullable=False,
                  server_default="{}"),
        # ★정정은 새 행이다 — 앞 행은 안 지운다.
        sa.Column("supersedes_id", sa.Text(), nullable=True),
        sa.Column("idempotency_key", sa.Text(), nullable=False),
        sa.Column("created_at", sa.Text(), nullable=False),
        sa.UniqueConstraint("project_id", "episode_id", "idempotency_key",
                            name="uq_grounding_fidelity_review_idem"),
    )
    # ★투영이 「이 대상의 유효 결정」을 매번 묻는다.
    op.create_index("ix_grounding_fidelity_review_scope",
                    "grounding_reference_fidelity_review",
                    ["project_id", "episode_id", "review_input_hash"])


def downgrade() -> None:
    op.drop_index("ix_grounding_fidelity_review_scope",
                  table_name="grounding_reference_fidelity_review")
    op.drop_table("grounding_reference_fidelity_review")
