Three interrelated fixes:
1. api/workspace.py — clean workspace isolation with auto-migration
_clean_workspace_list(): sanitizes any workspace list by:
- Removing test artifacts (webui-mvp-test, test-workspace paths)
- Removing paths that no longer exist on disk
- Removing cross-profile leaks (paths under ~/.hermes/profiles/*)
- Renaming 'default' workspace label to 'Home' (avoids confusion
with the 'default' profile name)
_migrate_global_workspaces(): one-time migration for upgrading users.
Reads the legacy global workspaces.json, runs _clean_workspace_list,
rewrites it cleaned. This runs automatically on first load after upgrade
for the default profile only.
load_workspaces(): now cleans every read and persists cleaned version
if anything changed. Named profiles always start fresh (no global leak).
Empty results fall back to 'Home' entry pointing at profile's workspace.
Default label for auto-generated single-entry lists is 'Home', not 'default'.
2. api/models.py — legacy session profile backfill (already committed,
this commit adds the sessions.js filter tightening counterpart)
3. static/sessions.js — strict profile filter
Removed the '!s.profile' escape hatch from the profile filter.
Server now backfills profile='default' on legacy sessions, so every
session has an explicit tag. Filter is now exact:
s.profile === S.activeProfile
Named profiles see zero legacy clutter. Default profile sees its own
sessions. 'All profiles' toggle still shows everything.
Migration story for users pulling this update:
- Existing sessions (profile=null) -> attributed to 'default' at read time
- Global workspaces.json -> cleaned of test artifacts and cross-profile paths
on first server start after upgrade
- Named profile workspace files -> cleaned on first read, persisted clean
- No manual intervention needed
Tests: 426 passed, 0 failed.