feat(trust): ADR-088 Trust Score 持久化 — L4 自動放行核心
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 10m40s
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 10m40s
TrustScoreManager 從記憶體升級為 PostgreSQL 持久化,
Pod 重啟後信任分數不再歸零,AI 能真正累積到 L4 自動放行門檻。
變更:
- migrations/adr088_trust_score_persistence.sql: trust_records 表
- db/models.py: TrustRecordDB ORM model
- repositories/interfaces.py: ITrustRepository Protocol
- repositories/trust_repository.py: PG upsert ON CONFLICT DO UPDATE
- services/trust_engine.py: bulk_load() 啟動 warm-up
- services/learning_service.py: _persist_trust() + 2 call sites
- main.py: 啟動時 load_all() → bulk_load()
流程: 批准 5 次 → score=5 寫入 DB → Pod 重啟 → warm-up 讀回
→ evaluate_adjusted_risk MEDIUM→LOW → 自動執行
2026-04-17 ogt + Claude Sonnet 4.6(亞太): ADR-088
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1175,3 +1175,56 @@ class AiGovernanceEvent(Base):
|
||||
Index("ix_ai_governance_triggered_at", "triggered_at"),
|
||||
Index("ix_ai_governance_resolved", "resolved"),
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TrustRecordDB - ADR-088 TrustScore 持久化
|
||||
# =============================================================================
|
||||
|
||||
class TrustRecordDB(Base):
|
||||
"""
|
||||
Trust Score 持久化記錄
|
||||
|
||||
ADR-088: TrustScoreManager 從記憶體升級為 PostgreSQL 持久化。
|
||||
Pod 重啟後分數不歸零,AI 能真正累積信任達到 L4 自動放行。
|
||||
|
||||
score >= 5: MEDIUM → LOW (自動執行)
|
||||
score >= 10: HIGH → MEDIUM (降一級)
|
||||
|
||||
2026-04-17 ogt + Claude Sonnet 4.6(亞太): Phase 4 信任持久化
|
||||
"""
|
||||
__tablename__ = "trust_records"
|
||||
|
||||
action_pattern: Mapped[str] = mapped_column(
|
||||
String(255), primary_key=True,
|
||||
comment="操作模式,例如 delete:nginx-frontend-*"
|
||||
)
|
||||
score: Mapped[int] = mapped_column(
|
||||
Integer, nullable=False, default=0,
|
||||
comment="累積信任分數。+1/approve,reject 歸零"
|
||||
)
|
||||
total_approvals: Mapped[int] = mapped_column(
|
||||
Integer, nullable=False, default=0,
|
||||
)
|
||||
total_rejections: Mapped[int] = mapped_column(
|
||||
Integer, nullable=False, default=0,
|
||||
)
|
||||
last_approval_by: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
||||
last_approval_at: Mapped[datetime | None] = mapped_column(
|
||||
DateTime(timezone=True), nullable=True,
|
||||
)
|
||||
last_rejection_by: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
||||
last_rejection_at: Mapped[datetime | None] = mapped_column(
|
||||
DateTime(timezone=True), nullable=True,
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, default=taipei_now,
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, default=taipei_now, onupdate=taipei_now,
|
||||
)
|
||||
|
||||
__table_args__ = (
|
||||
Index("ix_trust_records_score", "score"),
|
||||
Index("ix_trust_records_updated", "updated_at"),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user