Skip to content

Profile change proposals (admin)

HTTP routes and behavior for profile change proposals (admin).

GET /api/admin/profile-change-proposals # pending by default; ?status=all for recent history
GET /api/admin/profile-change-proposals/{id} # detail; pending rows add a live applicability check
POST /api/admin/profile-change-proposals/{id}/approve # re-validate live state, execute the verified write
POST /api/admin/profile-change-proposals/{id}/reject # { note } -- decline without touching the arr

The consent surface for quality-profile changes proposed over external MCP. The in-app preview/apply pair proves admin intent through same-turn chat provenance the server itself witnessed; an external agent has no server-witnessed turn, so its preview_profile_change call parks a durable proposal here instead; the server-computed plan, diff, and drift hashes, bound to the proposing user and MCP client device; and pages admins (profile_change_pending, sharing the agent_action_pending preference). The app lists proposals at Settings > Profile Change Approvals. Approval re-runs the full apply pipeline: fresh reauthorization, instance-binding and hash-pinned drift refusal (a drifted profile terminally fails the proposal; ask the agent to re-propose; a merely unreachable arr releases it back to pending), the verified full-object write, and a configuration-history record whose actor is the proposer with source external_mcp; consent lives on the proposal row (decided_by). One pending proposal per profile: a newer proposal supersedes the older, and its push (collapse-keyed per target) replaces the stale alert. Proposals expire after 7 days undecided. Rejection never touches the arr. Both proposal events carry the authoritative pending_count, and every decision (applied, rejected, or terminally failed) broadcasts profile_change_decided (WS-only) so the app’s needs-attention badge drains on every admin’s device, not just the one that decided.

View the maintained source for this page.