fix: auto-verify验证引擎4项缺陷修复 verify-fix (OKR幂等防重累加/entity_id多租户回填/period期间过滤/status done->completed)

This commit is contained in:
Hermes CI Fix
2026-08-30 19:16:19 +08:00
parent 2da4cfc42d
commit 6910d90288
4 changed files with 340 additions and 12 deletions
@@ -0,0 +1,84 @@
"""verify-engine-fix-20260830 DB 迁移脚本
1. kpi_values.entity_id 回填:kpi_id → kpi_definitions.entity_id(现有 67 条 NULL
2. action_plans.status 'done''completed'(枚举修正;当前 0 条,防御性执行)
执行前先 SELECT 预览影响行数,再执行 UPDATE,最后回查验证。
用法: venv/bin/python3 scripts/migrate_verify_fix_20260830.py
"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from sqlalchemy import text
from app.database import get_engine
def main():
engine = get_engine()
with engine.connect() as conn:
# ── 1. 预览 ──
preview_null = conn.execute(text(
"SELECT COUNT(*) AS cnt FROM kpi_values kv "
"LEFT JOIN kpi_definitions kd ON kv.kpi_id = kd.id "
"WHERE kv.entity_id IS NULL AND kd.entity_id IS NOT NULL"
)).fetchone()
preview_orphan = conn.execute(text(
"SELECT COUNT(*) AS cnt FROM kpi_values kv "
"LEFT JOIN kpi_definitions kd ON kv.kpi_id = kd.id "
"WHERE kv.entity_id IS NULL AND kd.id IS NULL"
)).fetchone()
preview_done = conn.execute(text(
"SELECT COUNT(*) AS cnt FROM action_plans WHERE status = 'done'"
)).fetchone()
print(f"[预览] 可回填(entity_id NULL 且 kpi 存在): {preview_null.cnt}")
print(f"[预览] 无法回填(kpi 不存在): {preview_orphan.cnt}")
print(f"[预览] action_plans status='done': {preview_done.cnt}")
# ── 2. 执行回填 ──
r = conn.execute(text(
"UPDATE kpi_values kv "
"JOIN kpi_definitions kd ON kv.kpi_id = kd.id "
"SET kv.entity_id = kd.entity_id "
"WHERE kv.entity_id IS NULL AND kd.entity_id IS NOT NULL"
))
print(f"[执行] kpi_values entity_id 回填 {r.rowcount}")
# 无法关联的孤儿行(kpi 不存在)→ 置默认 entity_id=1 并留 remark
r2 = conn.execute(text(
"UPDATE kpi_values kv "
"LEFT JOIN kpi_definitions kd ON kv.kpi_id = kd.id "
"SET kv.entity_id = 1, kv.remark = CONCAT(COALESCE(kv.remark, ''), '; verify-fix-20260830 孤儿行默认entity_id=1') "
"WHERE kv.entity_id IS NULL AND kd.id IS NULL"
))
if r2.rowcount:
print(f"[执行] 孤儿行置默认 entity_id=1: {r2.rowcount}")
else:
print("[执行] 无孤儿行需处理")
# ── 3. status done → completed ──
r3 = conn.execute(text(
"UPDATE action_plans SET status = 'completed' WHERE status = 'done'"
))
print(f"[执行] action_plans status done→completed: {r3.rowcount}")
conn.commit()
# ── 4. 验证 ──
after_null = conn.execute(text(
"SELECT COUNT(*) AS cnt FROM kpi_values WHERE entity_id IS NULL"
)).fetchone()
after_done = conn.execute(text(
"SELECT COUNT(*) AS cnt FROM action_plans WHERE status = 'done'"
)).fetchone()
print(f"[验证] kpi_values entity_id IS NULL 残留: {after_null.cnt}(目标 0")
print(f"[验证] action_plans status='done' 残留: {after_done.cnt}(目标 0")
if after_null.cnt != 0:
print("[结果] ❌ 回填不彻底,请人工检查")
sys.exit(1)
print("[结果] ✅ 迁移完成")
if __name__ == "__main__":
main()