Files
GTI_GERENCIADOR_FISCAL/central/alembic/versions/0027_rtc_auto_apply.py
T
gtiandClaude Sonnet 5 9f08998800 feat: deterministic cClassTrib resolver + gated CCLASSTRIB auto-apply (default OFF), RTC panel summary; 1.1.9
- resolver (rules RTC-R0..R4/A1..A3/G1..G2) over the official cClassTrib table 2026-06-22 and LC 214/2025 annexes; local vs official catalog comparison
- ONE root-cause RTC blocker per product (missing/unresolved/ambiguous/conflict/official mismatch/catalog outdated/evidence missing)
- auto-apply: C000025.CCLASSTRIB only, three switches (FIREBIRD_WRITES + RTC_AUTO_APPLY_ENABLED + Hub authorization), per-product re-read and re-decision, never overwrites, rowcount 1, audit table rtc_write_audits (migration 0027)
- copy-only write E2E (280/280 applied, only CCLASSTRIB changed, 2nd run 0 writes, stale decision 0 writes); real databases untouched
- docs: cclasstrib_resolution, rtc_auto_apply, unified_fiscal_completeness

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 21:18:34 -03:00

43 lines
2.0 KiB
Python

"""RTC auto-apply: per-installation authorization (default OFF) + immutable write audit.
Revision ID: 0027_rtc_auto_apply
Revises: 0026_central_processing_control
"""
from alembic import op
import sqlalchemy as sa
revision = "0027_rtc_auto_apply"
down_revision = "0026_central_processing_control"
branch_labels = None
depends_on = None
def upgrade():
op.add_column("installations", sa.Column("rtc_auto_apply_authorized", sa.Boolean(), nullable=False, server_default="false"))
op.create_table(
"rtc_write_audits",
sa.Column("id", sa.Integer(), primary_key=True),
sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id"), nullable=False, index=True),
sa.Column("installation_id", sa.Integer(), sa.ForeignKey("installations.id"), nullable=False, index=True),
sa.Column("agent_id", sa.Integer(), sa.ForeignKey("agents.id"), nullable=False, index=True),
sa.Column("job_id", sa.Integer(), nullable=True, index=True),
sa.Column("client", sa.String(255), nullable=True),
sa.Column("product_code", sa.String(64), nullable=False, index=True),
sa.Column("field", sa.String(32), nullable=False),
sa.Column("outcome", sa.String(16), nullable=False, index=True),
sa.Column("reason", sa.String(96), nullable=True),
sa.Column("old_value", sa.String(64), nullable=True),
sa.Column("new_value", sa.String(64), nullable=True),
sa.Column("rule_id", sa.String(32), nullable=True),
sa.Column("evidence", sa.JSON(), nullable=False, server_default="{}"),
sa.Column("official_source_version", sa.JSON(), nullable=False, server_default="{}"),
sa.Column("local_catalog_hash", sa.String(64), nullable=True),
sa.Column("written_at", sa.String(40), nullable=True),
sa.Column("recorded_at", sa.DateTime(timezone=True), server_default=sa.func.now(), index=True),
)
def downgrade():
op.drop_table("rtc_write_audits")
op.drop_column("installations", "rtc_auto_apply_authorized")