Files
ss-tools/backend/alembic/versions/p2q3r4s5t6u7_add_verification_run_dashboard_id.py
busya 410afdf40e feat(037): verification pipeline automation + GET read-API (T080-T081)
Close the 037 pipeline-automation and read-API gaps found in the audit:
deploy/release hooks did not create VerificationRun, and GET endpoints for
history/detail were absent even though 039 UI and client call them.

T080 - _release_routes.py: create_release now fires best-effort
  _trigger_release_verification -> VerificationRun with trigger=release_create
  (metric+structure); verification scheduling failures never roll back the
  release transaction.
T081 - verification.py: add GET /verification/history (dashboard_id +
  environment_id filters, newest-first) and GET /verification/{run_id}
  (404 RUN_NOT_FOUND); reuse _record_to_response.
  - verification_run.py + alembic migration p2q3r4s5t6u7: nullable indexed
    dashboard_id populated from structure/visual/metric category_params.
  - verification_service.py: _derive_dashboard_id helper.

Verification: release routes (32) + verification API (8) + persistence (21)
= 53 passed; ruff clean for changed code (pre-existing RUF012/UP017 on old
lines left untouched).
2026-08-07 14:21:25 +07:00

45 lines
1.9 KiB
Python

# #region Alembic.VerificationRunDashboardId [C:2] [TYPE Module] [SEMANTICS alembic,verification,dashboard,history]
# @ingroup Alembic
# @BRIEF Add nullable verification_runs.dashboard_id for 037 T081 history filtering by dashboard.
# @LAYER Database
# @RELATION DEPENDS_ON -> [Models.VerificationRun]
# @INVARIANT The column is nullable and indexed — existing runs remain valid and history
# filtering by dashboard is a soft filter (runs without dashboard_id excluded only
# when the caller filters on dashboard_id).
# @RATIONALE VerificationRunRecord previously carried repository/release/environment but no
# dashboard identity; frontend getVerificationHistory(dashboardId, envId) needs a
# dashboard-scoped query. dashboard_id is populated from category_params at persist.
# @REJECTED Encoding dashboard identity into environment_id or release_id was rejected — it is
# a distinct dimension and would corrupt existing environment/release semantics.
"""add verification_runs.dashboard_id
Revision ID: p2q3r4s5t6u7
Revises: o1p2q3r4s5t6
Create Date: 2026-08-07 14:00:00.000000
"""
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision: str = "p2q3r4s5t6u7"
down_revision: str | Sequence[str] | None = "o1p2q3r4s5t6"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
"""Add nullable, indexed verification_runs.dashboard_id."""
op.add_column("verification_runs", sa.Column("dashboard_id", sa.Integer(), nullable=True))
op.create_index("ix_verification_runs_dashboard", "verification_runs", ["dashboard_id"])
def downgrade() -> None:
"""Drop the dashboard_id index and column."""
op.drop_index("ix_verification_runs_dashboard", table_name="verification_runs")
op.drop_column("verification_runs", "dashboard_id")
# #endregion Alembic.VerificationRunDashboardId