"""Seed the daily answer-library freshness job. Revision ID: 502 Revises: 501 标记只在有任务去算的时候才存在。这个 cron 每天 05:10 重算每条启用答案的过时 状态:依据的控制项翻红(可能已经说错)、或超过它自己声明的复核周期没人看过。 只标记、不自动重写 —— 自动重起草会把没人看过的 AI 文本推进一份要发给客户的 合规材料里,而答案库的既有纪律是「起草可以自动,发送永远留人」。 """ import uuid import sqlalchemy as sa from alembic import op revision = "502" down_revision = "501" branch_labels = None depends_on = None _KEY = "auditor.answer_library_freshness" _DISPLAY = "安全问卷答案库·过时标记" _DESCRIPTION = ( "每天 05:10(Asia/Shanghai)重算答案库每条启用答案的过时状态:\n" "① backing_control_failing —— 这条答案依据的控制项不再通过,它的说法可能" "已经不成立(紧急);\n" "② review_interval_elapsed —— 没有已知错误,但超过了这条答案自己声明的" "复核周期没人看过。\n" "【只标记,不自动重写】自动重起草会把没人看过的 AI 文本推进一份要发给客户的" "合规材料里;答案库的既有纪律是「起草可以自动,发送永远留人」。过时标记的作用" "是把「该复核了」变成可见信号,而不是替人做决定。\n" "控制项恢复通过、或有人复核过之后,标记会在下一次运行时自动清除。\n" "只读外部:不打厂商接口、不调用模型。" ) # 05:10:排在 04:10 的漂移扫描之后 —— 控制项状态当天已经收敛,标记才准。 _CRON = "10 5 * * *" def upgrade() -> None: op.get_bind().execute( sa.text( "INSERT INTO scheduled_jobs " "(id, name, handler_key, display_name, description, " " trigger_type, cron_expr, timezone, enabled, config, " " created_at, updated_at) " "SELECT :id, :name, :k, :dn, :desc, 'cron', :cron, " " 'Asia/Shanghai', 1, '{}', NOW(), NOW() " "FROM DUAL WHERE NOT EXISTS (" " SELECT 1 FROM scheduled_jobs WHERE handler_key = :k)" ), { "id": str(uuid.uuid4()), "name": _KEY, "k": _KEY, "dn": _DISPLAY, "desc": _DESCRIPTION, "cron": _CRON, }, ) def downgrade() -> None: op.get_bind().execute( sa.text("DELETE FROM scheduled_jobs WHERE handler_key = :k"), {"k": _KEY}, )