refactor(checkpoints): slim the profile-rename rekey and name it as a checkpoint_manager sibling

Follow-up to the cherry-picked fix from #112724 (@poijygfdyy):

- tools/checkpoint_profile_migration.py -> tools/checkpoint_manager_profile_rename.py, the
  repo's `<stem>_<topic>.py` sibling convention for code that extends checkpoint_manager.
- Replace the fail-closed target-collision check plus temp-file/rollback choreography with an
  idempotent rekey: every step overwrites and the old project metadata is removed last, so a
  mid-way failure is repaired by `hermes profile migrate-identity` redoing the same writes.
  A genuine collision cannot occur — `profiles/<new>` must not exist for the rename to run.
  192 -> 98 lines.
- Metadata/ledger writes go through the same idiom as checkpoint_manager itself
  (`_register_project` plain write, `_save_ledger`), dropping the private temp-file helpers.
- Keep the git-present precondition as a single early check: without git the ref cannot move
  and rekeying only the metadata would orphan the history.
- Test: `create_profile` now seeds `workspace/`, so the fixture uses `project/`; add the control
  assertion that a workdir outside the profile dir keeps its history unchanged.
- Docs: the profile rename / migrate-identity reference notes that checkpoint history is preserved.

Fixes #112973
This commit is contained in:
teknium1
2026-09-16 09:57:11 -07:00
committed by Teknium
parent 8a2c9edac6
commit c055eee1fe
5 changed files with 112 additions and 198 deletions

View File

@@ -164,7 +164,7 @@ def _gateway_accepts_profile_identity_verb(root: Path) -> bool:
def _migrate_checkpoint_identity(old_canon: str, new_canon: str) -> bool:
"""Rekey checkpoint projects whose absolute workdirs moved with the profile directory."""
from hermes_cli.profiles import get_profile_dir
from tools.checkpoint_profile_migration import migrate_profile_checkpoint_projects
from tools.checkpoint_manager_profile_rename import migrate_profile_checkpoint_projects
old_dir = get_profile_dir(old_canon)
new_dir = get_profile_dir(new_canon)