feat(governance): auto-deprecate low-trust unused playbooks (>30d)
Some checks failed
Code Review / ai-code-review (push) Successful in 41s
CD Pipeline / tests (push) Successful in 3m29s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled

trust_drift previously fired alerts forever for playbooks stuck below
the 0.2 threshold. With user authorization for governance-class
auto-fixes, check_trust_drift now retires playbooks that have been
unused for 30+ days (or never used and created 30+ days ago) by
flipping status to 'deprecated' before alerting.

Alerts now report drifted_count, auto_deprecated_count, and the kept
playbook_ids that still need human review (those in their 30d trial
window). Existing alert noise from the four currently-drifted
playbooks should drop to whatever fraction is genuinely in trial.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-05-02 12:07:32 +08:00
parent 607358c4dd
commit 3059897318
3 changed files with 150 additions and 7 deletions

View File

@@ -39,6 +39,10 @@ logger = structlog.get_logger(__name__)
# 閾值常數
# =============================================================================
TRUST_DRIFT_THRESHOLD = 0.2 # playbook trust_score 低於此值 → 告警
# 2026-05-02 ogt + Claude Sonnet 4.6: trust_drift auto-deprecate
# trust < 0.2 + (last_used > N 天前 OR 從沒用過 + 創建超過 N 天) → 自動 deprecate
# 這個 N 設 30 天,給 playbook 充足試用期,避免新提案被早期幾次失敗就廢棄
TRUST_DRIFT_AUTO_DEPRECATE_AFTER_DAYS = 30
KM_STALE_DAYS = 7 # 知識條目超過幾天未更新視為陳舊
KM_STALE_RATIO = 0.20 # 陳舊比例超過此值 → 告警
HALLUCINATION_RATE_THRESHOLD = 0.10 # LLM verification failed 比例超過此值 → 告警
@@ -69,9 +73,12 @@ class GovernanceAgent:
# =========================================================================
async def check_trust_drift(self) -> dict[str, Any]:
"""Playbook trust_score < 0.2 → 告警建議廢棄
"""Playbook trust_score < 0.2 → 告警建議廢棄30 天沒用過的直接 auto-deprecate
2026-04-26 P2.2 by Claude
2026-05-02 ogt + Claude Sonnet 4.6: 加 auto_deprecate_low_trust_unused 自治路徑
守衛條件trust < 0.2 AND (last_used_at < 30 天前 OR 從未使用且創建超過 30 天)
→ status 改 'deprecated'alert 改報「N 個告警 + M 個 auto-deprecated」
"""
async with get_db_context() as db:
result = await db.execute(
@@ -81,9 +88,31 @@ class GovernanceAgent:
)
all_records = result.scalars().all()
total = len(all_records)
drifted = [r for r in all_records if float(r.trust_score) < TRUST_DRIFT_THRESHOLD]
drifted_ids = [r.playbook_id for r in drifted[:10]]
total = len(all_records)
drifted = [r for r in all_records if float(r.trust_score) < TRUST_DRIFT_THRESHOLD]
# auto-deprecate eligibility
cutoff = now_taipei() - timedelta(days=TRUST_DRIFT_AUTO_DEPRECATE_AFTER_DAYS)
auto_deprecated_ids: list[str] = []
kept_ids: list[str] = []
for r in drifted:
last = r.last_used_at
created = r.created_at
# 沒用過 → 用 created_at 作為「進入系統時間」
ref_time = last if last is not None else created
if ref_time is not None and ref_time < cutoff:
r.status = "deprecated"
auto_deprecated_ids.append(r.playbook_id)
else:
kept_ids.append(r.playbook_id)
if auto_deprecated_ids:
await db.commit()
logger.info(
"governance_trust_drift_auto_deprecated",
count=len(auto_deprecated_ids),
ids=auto_deprecated_ids[:10],
)
if drifted:
await self._alert(
@@ -91,8 +120,11 @@ class GovernanceAgent:
{
"drifted_count": len(drifted),
"total_playbooks": total,
"playbook_ids": drifted_ids,
"playbook_ids": kept_ids[:10],
"auto_deprecated_count": len(auto_deprecated_ids),
"auto_deprecated_ids": auto_deprecated_ids[:10],
"threshold": TRUST_DRIFT_THRESHOLD,
"auto_deprecate_after_days": TRUST_DRIFT_AUTO_DEPRECATE_AFTER_DAYS,
},
)
@@ -100,8 +132,15 @@ class GovernanceAgent:
"governance_trust_drift_checked",
total=total,
drifted=len(drifted),
auto_deprecated=len(auto_deprecated_ids),
kept=len(kept_ids),
)
return {"checked": total, "drifted": len(drifted)}
return {
"checked": total,
"drifted": len(drifted),
"auto_deprecated": len(auto_deprecated_ids),
"kept": len(kept_ids),
}
# =========================================================================
# 2. 知識庫衰退