Files
ss-tools/backend/alembic/versions/h2i3j4k5l6m7_add_verification_runs.py
busya a32ca0631b feat(037): capture, verification lifecycle, inheritance + close 036 stabilization
- Authoritative candidate capture with server-issued artifacts and raw-byte
  immutability hashing (source_response_hash server-owned)
- Closed-period lifecycle: request-hash bound approvals, persisted closure
  immutability violations, byte-for-byte catalog stability on reclosure
- Verification runs: persisted VerificationRun model + FK migration,
  publish gate (block_publish), scheduled observability runs (02:00 UTC)
- FR-013 baseline inheritance: prior_release_id migration, plan_inheritance/
  execute_inheritance classification and re-extraction, API endpoints
- Visual executor bound to release-deployment environment; caller mismatch
  rejected; visual SSIM/reconciliation modules
- Query execution decomposed: envelope/model/executor split, no direct SQL
- AgentRun approvals extracted to submodule; evidence adapter; _utils
- Dashboard testing service decomposed into 30+ modules (all <400 LOC)
- Five Feature-037 agent tools with permission guards (tools_037.py)
- API readiness endpoint; Alembic env/migrations; test fixture repos
- Specs 036/037 contracts, openapi.yaml, schema.json, tasks/traceability
  updated; semantic index rebuilt with 0 parse warnings
- Fix ADR-0003 parser ambiguity: remove [DEF🆔ADR] prose example
- Add axiom-mcp-agent-feedback.md: agent findings for MCP rework plan
- Tests: 298 service + 1464 API + 45 agent passing; ruff clean
2026-07-31 11:28:50 +03:00

84 lines
3.2 KiB
Python

# #region Alembic.AddVerificationRuns [C:3] [TYPE Module] [SEMANTICS alembic,verification,run,persistence]
# @ingroup Alembic
# @BRIEF Add verification_runs table for per-category verification outcome persistence.
# @LAYER Database
# @RELATION DEPENDS_ON -> [Models.VerificationRun]
# @INVARIANT FK on agent_run_id uses ON DELETE SET NULL — run survives agent run deletion.
# @INVARIANT FK on release_id uses ON DELETE SET NULL — run survives release deletion (audit retention).
# @RATIONALE Verification runs have their own identity and lifecycle independent of agent
# scenarios. The table stores immutable per-category outcomes with evidence refs.
# Release FK uses SET NULL so historical runs are preserved for audit when a release
# is deleted (audit-retention requirement).
# @REJECTED Embedding outcomes in AgentRun.events was rejected — verification runs have
# their own lifecycle. Storing as JSON on DashboardRelease was rejected — a
# release may have multiple verification runs over time.
"""add verification_runs table
Revision ID: h2i3j4k5l6m7
Revises: g1h2i3j4k5l6
Create Date: 2026-07-30 12:00:00.000000
"""
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision: str = "h2i3j4k5l6m7"
down_revision: str | Sequence[str] | None = "g1h2i3j4k5l6"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
"""Create verification_runs table with FK to agent_runs and dashboard_releases."""
op.create_table(
"verification_runs",
sa.Column("id", sa.String(), nullable=False),
sa.Column(
"agent_run_id",
sa.String(),
sa.ForeignKey("agent_runs.id", ondelete="SET NULL"),
nullable=True,
index=True,
),
sa.Column("repository_id", sa.String(), nullable=False),
sa.Column(
"release_id",
sa.String(),
sa.ForeignKey("dashboard_releases.id", ondelete="SET NULL"),
nullable=True,
index=True,
),
sa.Column("trigger", sa.String(), nullable=False),
sa.Column("environment_id", sa.String(), nullable=False),
sa.Column("categories_run", sa.JSON(), nullable=False),
sa.Column("category_outcomes", sa.JSON(), nullable=False),
sa.Column("overall_status", sa.String(), nullable=False),
sa.Column("summary", sa.Text(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("created_by", sa.String(), nullable=False),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
"ix_verification_runs_agent_run",
"verification_runs",
["agent_run_id"],
)
op.create_index(
"ix_verification_runs_created",
"verification_runs",
["created_at"],
)
def downgrade() -> None:
"""Drop verification_runs table and its indexes."""
op.drop_index("ix_verification_runs_agent_run", table_name="verification_runs")
op.drop_index("ix_verification_runs_created", table_name="verification_runs")
op.drop_table("verification_runs")
# #endregion Alembic.AddVerificationRuns