Feature: FsDirectoryHandler uncovered-line coverage
  Exercise code paths in fs_directory.py that lack test coverage:
  delete with empty path (L133), delete subdirectory (L143),
  diff with missing files on either side (L197, L204),
  create_checkpoint with no sandbox (L287-289),
  rollback_to with no sandbox (L329-331),
  rollback_to with missing checkpoint (L336-339),
  rollback_to .git skipping and directory handling (L347,349,357,360),
  and discard_checkpoints (L374-381).

  Scenario: Delete with empty path raises PermissionError
    Given fsdcov a temp directory with a file "hello.txt"
    When fsdcov I delete with an empty path
    Then fsdcov a PermissionError is raised with message "Cannot delete the resource root"

  Scenario: Delete a subdirectory removes it via rmtree
    Given fsdcov a temp directory with a subdirectory "subdir" containing "inner.txt"
    When fsdcov I delete subdirectory "subdir"
    Then fsdcov the delete result is successful
    And fsdcov the subdirectory "subdir" no longer exists

  Scenario: Diff when a file exists only in the other location
    Given fsdcov a temp directory "dir_a" with no files
    And fsdcov a temp directory "dir_b" with file "only_b.txt" containing "new content"
    When fsdcov I diff dir_a against dir_b
    Then fsdcov the diff shows changes with insertions

  Scenario: Diff when a file exists only in the resource location
    Given fsdcov a temp directory "dir_a" with file "only_a.txt" containing "old content"
    And fsdcov a temp directory "dir_b" with no files
    When fsdcov I diff dir_a against dir_b
    Then fsdcov the diff shows changes with deletions

  Scenario: create_checkpoint raises RuntimeError when sandbox is None
    Given fsdcov a handler and a resource with location
    And fsdcov a sandbox manager that returns None for get_sandbox
    When fsdcov I call create_checkpoint
    Then fsdcov a RuntimeError is raised with message "No active sandbox"

  Scenario: create_checkpoint raises RuntimeError when sandbox context is None
    Given fsdcov a handler and a resource with location
    And fsdcov a sandbox manager that returns sandbox with no context
    When fsdcov I call create_checkpoint
    Then fsdcov a RuntimeError is raised with message "No active sandbox"

  Scenario: rollback_to raises RuntimeError when sandbox is None
    Given fsdcov a handler and a resource with location
    And fsdcov a sandbox manager that returns None for get_sandbox
    When fsdcov I call rollback_to with checkpoint "ckpt-1"
    Then fsdcov a RuntimeError is raised with message "No active sandbox"

  Scenario: rollback_to raises RuntimeError when sandbox context is None
    Given fsdcov a handler and a resource with location
    And fsdcov a sandbox manager that returns sandbox with no context
    When fsdcov I call rollback_to with checkpoint "ckpt-1"
    Then fsdcov a RuntimeError is raised with message "No active sandbox"

  Scenario: rollback_to returns failure for unknown checkpoint
    Given fsdcov a handler and a resource with location
    And fsdcov a sandbox manager with a valid sandbox
    When fsdcov I call rollback_to with checkpoint "nonexistent-ckpt"
    Then fsdcov the rollback result is unsuccessful with message "not found or expired"

  Scenario: rollback_to returns failure for expired checkpoint path
    Given fsdcov a handler with a checkpoint pointing to a deleted path
    And fsdcov a sandbox manager with a valid sandbox
    When fsdcov I call rollback_to with the expired checkpoint
    Then fsdcov the rollback result is unsuccessful with message "not found or expired"

  Scenario: rollback_to skips .git and restores dirs and files
    Given fsdcov a handler with a real checkpoint snapshot
    And fsdcov a sandbox with .git dir and other content
    When fsdcov I call rollback_to with the real checkpoint
    Then fsdcov the rollback result is successful
    And fsdcov the .git directory is preserved in the sandbox
    And fsdcov the snapshot content is restored in the sandbox

  Scenario: discard_checkpoints removes matching checkpoints
    Given fsdcov a handler with two checkpoints for plan "plan-abc"
    When fsdcov I call discard_checkpoints with plan_id "plan-abc"
    Then fsdcov discard_checkpoints returns 2
    And fsdcov no checkpoints remain for plan "plan-abc"

  Scenario: discard_checkpoints with empty plan_id removes all
    Given fsdcov a handler with checkpoints for different plans
    When fsdcov I call discard_checkpoints with empty plan_id
    Then fsdcov all checkpoints are removed
