UAT: CheckpointManager.rollback_to() always silently fails — sandbox_path is never stored in checkpoint metadata #4061

Open
opened 2026-04-06 09:48:53 +00:00 by freemo · 0 comments
Owner

Metadata

  • Branch: fix/checkpoint-manager-sandbox-path-not-stored
  • Commit Message: fix(checkpoint): store sandbox_path in checkpoint metadata to enable rollback
  • Milestone: (none — backlog)
  • Parent Epic: #397

Bug Report

What was tested:
CheckpointManager in src/cleveragents/infrastructure/sandbox/checkpoint.py — specifically the interaction between create_checkpoint() and rollback_to().

Expected behavior (from spec):
Per docs/specification.md, the agents plan rollback <PLAN_ID> <CHECKPOINT_ID> command must successfully restore the sandbox to the checkpointed state. The CheckpointManager.rollback_to() method must be able to locate the sandbox filesystem path from the checkpoint's persisted metadata in order to perform the directory restore.

Actual behavior:
rollback_to() always returns False and logs "Rollback skipped: sandbox path unknown or missing" because sandbox_path is never stored in checkpoint.metadata. The rollback silently fails on every invocation unless the caller manually injects sandbox_path into the metadata dict at checkpoint creation time — which no caller currently does.

Root cause:
In create_checkpoint() (lines ~140–165), sandbox_path is captured from sandbox.context.sandbox_path and passed to _snapshot_directory() to create the filesystem snapshot. However, it is never written into the meta dict before the SandboxCheckpoint is constructed. Since SandboxCheckpoint is a frozen (immutable) Pydantic model, sandbox_path cannot be added after construction.

In rollback_to() (lines ~167–230), the method reads checkpoint.metadata.get("sandbox_path") to find the path to restore — but this key is always absent, so the guard condition short-circuits and returns False.

Code locations:

  • src/cleveragents/infrastructure/sandbox/checkpoint.py
    • create_checkpoint() (~lines 140–165): captures sandbox_path but only passes it to _snapshot_directory(), never stores it in meta
    • rollback_to() (~lines 167–230): reads checkpoint.metadata.get("sandbox_path") which is always None

Fix:
In create_checkpoint(), add sandbox_path to the meta dict before constructing the SandboxCheckpoint:

if sandbox_path is not None:
    meta["sandbox_path"] = sandbox_path

This must be done before SandboxCheckpoint(...) is called since the model is frozen/immutable.

Subtasks

  • Add meta["sandbox_path"] = sandbox_path (guarded by if sandbox_path is not None) in create_checkpoint() before SandboxCheckpoint construction
  • Verify rollback_to() correctly reads checkpoint.metadata.get("sandbox_path") after the fix (no changes needed there)
  • Write a Behave unit test (TDD: failing test first) that creates a checkpoint and asserts checkpoint.metadata["sandbox_path"] is set
  • Write a Behave unit test that calls rollback_to() and asserts it returns True and restores the directory (not False with the skip log)
  • Run nox -e unit_tests and confirm all tests pass
  • Run nox -e typecheck and confirm no type errors
  • Run nox -e coverage_report and confirm coverage ≥ 97%

Definition of Done

  • create_checkpoint() stores sandbox_path in checkpoint.metadata when a sandbox path is available
  • rollback_to() successfully restores the sandbox directory when called on a checkpoint created by create_checkpoint()
  • rollback_to() no longer returns False with "Rollback skipped: sandbox path unknown or missing" for normally-created checkpoints
  • Behave unit tests cover: (a) sandbox_path persisted in metadata, (b) successful rollback restores directory, (c) rollback still skips gracefully when sandbox_path is genuinely absent
  • All nox stages pass
  • Coverage ≥ 97%

Backlog note: This issue was discovered during autonomous operation
on milestone v3.3.0. It does not block milestone completion and has been
placed in the backlog for human review and future milestone assignment.


Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-uat-tester

## Metadata - **Branch**: `fix/checkpoint-manager-sandbox-path-not-stored` - **Commit Message**: `fix(checkpoint): store sandbox_path in checkpoint metadata to enable rollback` - **Milestone**: *(none — backlog)* - **Parent Epic**: #397 ## Bug Report **What was tested:** `CheckpointManager` in `src/cleveragents/infrastructure/sandbox/checkpoint.py` — specifically the interaction between `create_checkpoint()` and `rollback_to()`. **Expected behavior (from spec):** Per `docs/specification.md`, the `agents plan rollback <PLAN_ID> <CHECKPOINT_ID>` command must successfully restore the sandbox to the checkpointed state. The `CheckpointManager.rollback_to()` method must be able to locate the sandbox filesystem path from the checkpoint's persisted metadata in order to perform the directory restore. **Actual behavior:** `rollback_to()` always returns `False` and logs `"Rollback skipped: sandbox path unknown or missing"` because `sandbox_path` is never stored in `checkpoint.metadata`. The rollback silently fails on every invocation unless the caller manually injects `sandbox_path` into the metadata dict at checkpoint creation time — which no caller currently does. **Root cause:** In `create_checkpoint()` (lines ~140–165), `sandbox_path` is captured from `sandbox.context.sandbox_path` and passed to `_snapshot_directory()` to create the filesystem snapshot. However, it is **never written into the `meta` dict** before the `SandboxCheckpoint` is constructed. Since `SandboxCheckpoint` is a frozen (immutable) Pydantic model, `sandbox_path` cannot be added after construction. In `rollback_to()` (lines ~167–230), the method reads `checkpoint.metadata.get("sandbox_path")` to find the path to restore — but this key is always absent, so the guard condition short-circuits and returns `False`. **Code locations:** - `src/cleveragents/infrastructure/sandbox/checkpoint.py` - `create_checkpoint()` (~lines 140–165): captures `sandbox_path` but only passes it to `_snapshot_directory()`, never stores it in `meta` - `rollback_to()` (~lines 167–230): reads `checkpoint.metadata.get("sandbox_path")` which is always `None` **Fix:** In `create_checkpoint()`, add `sandbox_path` to the `meta` dict **before** constructing the `SandboxCheckpoint`: ```python if sandbox_path is not None: meta["sandbox_path"] = sandbox_path ``` This must be done before `SandboxCheckpoint(...)` is called since the model is frozen/immutable. ## Subtasks - [ ] Add `meta["sandbox_path"] = sandbox_path` (guarded by `if sandbox_path is not None`) in `create_checkpoint()` before `SandboxCheckpoint` construction - [ ] Verify `rollback_to()` correctly reads `checkpoint.metadata.get("sandbox_path")` after the fix (no changes needed there) - [ ] Write a Behave unit test (TDD: failing test first) that creates a checkpoint and asserts `checkpoint.metadata["sandbox_path"]` is set - [ ] Write a Behave unit test that calls `rollback_to()` and asserts it returns `True` and restores the directory (not `False` with the skip log) - [ ] Run `nox -e unit_tests` and confirm all tests pass - [ ] Run `nox -e typecheck` and confirm no type errors - [ ] Run `nox -e coverage_report` and confirm coverage ≥ 97% ## Definition of Done - [ ] `create_checkpoint()` stores `sandbox_path` in `checkpoint.metadata` when a sandbox path is available - [ ] `rollback_to()` successfully restores the sandbox directory when called on a checkpoint created by `create_checkpoint()` - [ ] `rollback_to()` no longer returns `False` with `"Rollback skipped: sandbox path unknown or missing"` for normally-created checkpoints - [ ] Behave unit tests cover: (a) `sandbox_path` persisted in metadata, (b) successful rollback restores directory, (c) rollback still skips gracefully when `sandbox_path` is genuinely absent - [ ] All nox stages pass - [ ] Coverage ≥ 97% > **Backlog note:** This issue was discovered during autonomous operation > on milestone v3.3.0. It does not block milestone completion and has been > placed in the backlog for human review and future milestone assignment. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-uat-tester
HAL9000 added this to the v3.5.0 milestone 2026-04-09 03:11:31 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Blocks
#397 Epic: Server & Autonomy Infrastructure
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#4061
No description provided.