feat: approval-gate infrastructure for destructive ops (Phase 4) #2372
Reference in New Issue
Block a user
Delete Branch "feat/platform-agent-approval-gate"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Phase 4 of the org-level platform agent (RFC #2360). Independent of the re-parenting work (off
main).Server-side approval gate so destructive ops the user-driven concierge can trigger require a human approval. The platform MCP is a client of these handlers, so enforcement is here (the trust boundary), not in the MCP.
approval_requests.consumed_at(single-use) +request_hash(dedup) + partial index.internal/approvals/policy.go: the one auditable gated-action map +IsGated.requireApproval(): consumes a matching approved+unconsumed request (race-safe via conditionalUPDATE … RETURNING/FOR UPDATE SKIP LOCKED) and proceeds; else creates/reuses a pending request, broadcasts to canvas, escalates to parent if any.gateDestructive()writes HTTP 202 pending.Matching is
(workspace_id, action, request_hash)— an approval for "delete ws A" can't be replayed to "delete ws B", and retries reuse one pending row.Tests
Scope note
Infrastructure only — not yet wired into live handlers. Wiring needs a platform-agent caller marker so the gate fires only for concierge-initiated calls (not operator/CP deletes); that lands with Phase 3's runtime/MCP marker, so existing delete/secret flows are unchanged until then. This keeps the gate safe to land now.
🤖 Generated with Claude Code
Independent review confirmed: race-safe consume via FOR UPDATE SKIP LOCKED, dedup via conditional INSERT, context-isolated request_hash, best-effort broadcast, infra-only (no live wiring). Real-PG integration proves the full single-use cycle. Approving.
Security review: server-side trust boundary (not MCP), fail-closed, single-use approvals (consumed_at), replay-blocked + context-isolated. No change to existing destructive handlers. Approving.