fix(agent+ui): whatsapp session audit — approvals, stuck indicator, stale execs
P1: add docker compose (logs|ps|top|config|images|port|cp) to read-only allowlist. docker compose logs was classified as config_mutation, causing individual approval cards for read-only inspection commands. P2: remove approval entries from activityLog. They were always status=running and never transitioned to done (the derived store builds from tool-call text, not execution status), causing AgentIndicator to latch onto a stale 'Approval: ...' entry and never clear — even after the session completed. P3: remove InlineApproval from Chat.svelte. The green 'Completed in 1s on lxc:...' boxes were noise in the chat stream. Approval UX belongs in the Operations page (already has it via Ops.svelte), not inline in the chat. P4: stale execution cleanup. Startup sweep (mark >1hr non-terminal as cancelled) + 5-min periodic sweep (mark >10min non-terminal as cancelled). 98 orphaned executions accumulated from eval testing (39 running from apt_upgrade:audit timeouts, 19 pending_approval, 3 approved). P5: refuse second config_mutation run when an approval is already pending for the session. Without this, the agent queues N individual approvals before the operator can respond — confirmed in session 20757eb9 (two approval cards for what should have been one plan-level approval). VERSION 0.7.0 → 0.7.1
This commit is contained in:
@@ -1295,6 +1295,26 @@ func classifyAndGate(ctx context.Context, pool *db.Pool, agentID, targetID uuid.
|
||||
return textResult(fmt.Sprintf("An identical command is already queued for approval on %s — execution %s. Wait for the operator, don't re-request.", targetSlug, existingID))
|
||||
}
|
||||
|
||||
// P5: if this is a config_mutation command, no assent window is active,
|
||||
// and there's already a pending_approval for this session, refuse —
|
||||
// don't queue a second approval. The operator should see ONE approval
|
||||
// (the plan), approve it (which opens the assent window), and then all
|
||||
// subsequent config_mutation commands auto-run. Without this gate, the
|
||||
// agent queues N individual approvals before the operator can respond,
|
||||
// flooding the chat with approval cards — confirmed in session 20757eb9
|
||||
// (WhatsApp bridge: two approvals for what should have been one plan).
|
||||
if riskClass == policy.RiskConfigMutation && sessionID != "" && !assentWindowActive(ctx, pool, agentID, sessionID) {
|
||||
var anyPending int
|
||||
pool.QueryRow(ctx, `
|
||||
SELECT COUNT(*) FROM nomos_plan_executions pe
|
||||
JOIN executions ex ON ex.entity_id = pe.execution_id
|
||||
WHERE pe.session_id = $1 AND ex.status = 'pending_approval'`,
|
||||
sessionID).Scan(&anyPending)
|
||||
if anyPending > 0 {
|
||||
return textResult("An approval is already pending for this plan. Present the plan and its steps to the operator, then STOP and wait for their approval (\"approved\", \"yes\", \"go ahead\"). Do not call run again until the operator responds — after approval, all config_mutation commands will auto-run.")
|
||||
}
|
||||
}
|
||||
|
||||
id, _ := uuid.NewV7()
|
||||
correlationID := uuid.New().String()
|
||||
execName := "run on " + targetSlug + " (" + id.String() + ")"
|
||||
|
||||
Reference in New Issue
Block a user