//! 审批后审计记录状态回填(audit_finalize) //! //! `audit_tool_call` 已移至 record.rs(审计记录写入操作归 audit record 子模块)。 //! re-export 经 audit/mod.rs `pub(crate) use finalize::audit_finalize;` 保持 //! `commands::ai::audit::*` 路径透明(调用方零变更)。 use crate::commands::now_millis; use crate::state::AppState; /// 审批后更新审计记录状态(按 tool_call_id 定位 pending 记录,回填 status/decided_by=human/executed_at/result) /// /// 走专用 find_by_tool_call_id —— 通用 query 宏硬编码 ORDER BY created_at DESC, /// 而 ai_tool_executions 无该列,调用会报 "no such column: created_at" 被 unwrap_or_default 吞掉, /// 导致审批后审计记录永久卡 pending。 pub(crate) async fn audit_finalize(state: &AppState, tool_call_id: &str, status: &str, result: Option) { // 区分 Err(DB 故障)与 Ok(None)(真无记录):原 unwrap_or_default 把 Err 压成 None, // DB 故障被「未找到」日志掩盖,审批后审计记录卡 pending 无确诊线索(B-260617-17 同款吞错)。 let mut rec = match state.ai_tool_executions.find_by_tool_call_id(tool_call_id).await { Ok(Some(rec)) => rec, Ok(None) => { tracing::warn!("audit_finalize: 未找到 tool_call_id={} 的审计记录", tool_call_id); return; } Err(e) => { tracing::error!("audit_finalize: 查询 tool_call_id={} 审计记录失败(DB 故障,状态未回填): {}", tool_call_id, e); return; } }; rec.status = status.to_string(); rec.decided_by = Some("human".to_string()); rec.executed_at = Some(now_millis()); if let Some(r) = result { rec.result = Some(r); } if let Err(e) = state.ai_tool_executions.update_full(&rec).await { tracing::error!("audit_finalize: 回填 tool_call_id={} 审计状态失败: {}", tool_call_id, e); } }