Severity: Critical
Location: crates/librefang-kernel/src/approval.rs:36, 80, 277, 352
Problem
The pending: DashMap<Uuid, PendingRequest> is never persisted. Only the audit log and TOTP lockout state are written to SQLite. The waiting tool call's oneshot receiver was dropped when the daemon died, so on restart the agent loop receives no decision.
Failure scenario
Operator submits a high-stakes approval (deploy, transfer, send message); daemon is restarted (deploy, OOM, crash); on restart the pending entry is gone. A second operator approval attempt returns "not found or expired", with no audit trail of what was lost. The agent loop either hangs forever (paths without a per-call timeout) or treats it as denied, and there is no UI surface telling the user "we lost N pending approvals on the last restart".
Suggested fix
Persist PendingRequest to a pending_approvals table; replay on boot, re-broadcast NeedsApproval to whichever path is waiting (or treat replayed entries as failed and require resubmission, but at minimum surface them in the dashboard with a banner so operators are not silently misled).
Filed from cross-cutting bug/design audit (2026-04-28). Line numbers may drift across commits — verify before fixing.
Severity: Critical
Location:
crates/librefang-kernel/src/approval.rs:36, 80, 277, 352Problem
The
pending: DashMap<Uuid, PendingRequest>is never persisted. Only the audit log and TOTP lockout state are written to SQLite. The waiting tool call'soneshotreceiver was dropped when the daemon died, so on restart the agent loop receives no decision.Failure scenario
Operator submits a high-stakes approval (deploy, transfer, send message); daemon is restarted (deploy, OOM, crash); on restart the pending entry is gone. A second operator approval attempt returns "not found or expired", with no audit trail of what was lost. The agent loop either hangs forever (paths without a per-call timeout) or treats it as denied, and there is no UI surface telling the user "we lost N pending approvals on the last restart".
Suggested fix
Persist
PendingRequestto apending_approvalstable; replay on boot, re-broadcastNeedsApprovalto whichever path is waiting (or treat replayed entries as failed and require resubmission, but at minimum surface them in the dashboard with a banner so operators are not silently misled).Filed from cross-cutting bug/design audit (2026-04-28). Line numbers may drift across commits — verify before fixing.