Commit Graph
4 Commits
Author SHA1 Message Date
justinandClaude Opus 5 fe7b220ab9 feat(checkpoints): record agent and intent in the checkpoint name
Zerto's tagged checkpoint insert takes exactly one field. The 10.x
swagger model VpgInsertTagCheckpointDataApi has a single property,
checkpointName, and the 9.0 API reference lists CheckpointName as the
only request value. There is no description field, so who the agent is
and what it is about to do have to live inside the name.

Old name:
  ai:claude:chg-412:20260921T170829Z

New name:
  ai:claude | edit /home/justin/app-config.yaml | vm=jp-ubuntu |
  change=chg-412 | 20260921T170829Z

zerto_create_tagged_checkpoint and zerto_guard_before_mutate take a new
action argument: free text saying what the agent is about to do. The VM
name is filled in from the find result. An operator reading the journal
in the Zerto UI can now see which agent inserted a checkpoint and why,
without the agent transcript.

Field text is sanitised so the name stays one readable line: control
characters and runs of whitespace collapse to single spaces, ';' becomes
',' because Zerto appends "; Used for File Level Restore" to its own
tags, and '|' becomes '/' because ' | ' is our field separator. Capped
at TAG_MAX_LEN (250).

Measured against ZVM 10.x while picking the format:

- names of at least 400 chars are accepted, and spaces, slashes,
  parentheses, '=' and '|' all survive the round trip
- tagged checkpoint inserts fired back to back at one VPG are silently
  dropped. The POST returns 200 and queues a task, but only the first
  checkpoint appears. tag_vpgs already inserts then waits per VPG, so
  it is correct; added a comment so nobody turns that loop into an
  asyncio.gather().

Verified end to end: guard inserted cp 1197 on VPG jp-ubuntu, the name
read back byte-identical from the journal, and FLR from that checkpoint
returned the 158 byte pre-mutation file.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_016yVfC5nvZowoLFnEGWhLGn
2026-09-21 13:09:08 -04:00
justinandClaude Opus 5 94025b8d69 fix(flr): resolve guest paths into the FLR partition namespace
zerto_recover_file passed the guest absolute path straight to
POST /v1/flrs/{session}/download, which the ZVM rejects:

  HTTP 400 {"Message":"Invalid path: check location exists or
  correct path syntax."}

FLR browse/download is rooted at partitions, not the guest's /.
/home/justin/app-config.yaml is Volume2-Ext4/home/justin/app-config.yaml.
server.py already called browse_flr() but discarded the result, so
nothing ever resolved the path.

Add resolve_flr_path() and browsable_partitions() to recover.py:

- browse path "" returns {MainPathItem, PathItems}, not a bare list
- skip partitions with IsBrowsable false. A Linux guest reports
  Volume1-Unknown as "Cannot restore. Partition type Unknown is not
  supported." Do not assume the first partition is the right one.
- browse returns child paths percent-encoded
  (Volume2-Ext4%2fhome%2fjustin%2fapp-config.yaml); download wants
  them decoded with plain slashes
- raise a ZertoError naming what was searched when the file is
  absent, since "not replicated into that checkpoint yet" is the
  likely cause and is actionable

zerto_recover_file now returns the resolved flr_path.

Verified end to end against ZVM 10.x: guard tagged cp 1075 on VPG
jp-ubuntu, FLR mounted in ~3s, 158 bytes recovered from the
pre-mutation checkpoint with matching content.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_016yVfC5nvZowoLFnEGWhLGn
2026-09-21 13:04:08 -04:00
claude 2473d22d2e fix(flr): 10.9 session list + download path (#1)
Co-authored-by: claude <[email protected]>
2026-09-21 12:18:13 -04:00
claude 38ba9c1b50 feat(poc): rewind MCP, skill, and recover-ladder docs
Initial PoC: find_protection, tagged checkpoints, FLR, mutating catalog.
Lab 10.9 status enums (0=Initializing, 1=MeetingSLA). Credentials stay in gitignored config.json.
2026-09-21 12:09:11 -04:00