Admin-gated soft-delete + purge so operators can clear ghost machines/sessions
(the ~15-rows-for-one-host accumulation) from the console.
- migration 009: deleted_at on connect_sessions + connect_machines, with partial
indexes WHERE deleted_at IS NULL.
- DELETE /api/machines/:agent_id?purge=true and DELETE /api/sessions/:id?purge=true
soft-delete the row and purge the in-memory session (remove_session); the
non-purge path keeps the legacy hard-delete / live-only disconnect. POST
/api/machines/bulk-remove handles multi-select (batch cap 500). All admin-gated
(AdminUser -> 403; tightens the prior any-user delete) and audited to
connect_session_events (actor + target + trusted client IP).
- list/get queries filter deleted_at IS NULL so removed units leave the console;
upsert revives (deleted_at = NULL) a genuinely-reconnecting machine. The
keyed-reattach identity resolver (get_machine_by_id) is intentionally unfiltered.
Dashboard removal UI is the A3b follow-up. 86 server tests pass; fmt/clippy/test
clean. Implements specs/v2-stable-identity/plan.md Task 5 (server portion).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>