Feature: Overlay sandbox coverage round 3
  Additional BDD scenarios exercising uncovered lines in overlay.py,
  including _is_overlayfs_available, real overlay mode, _mount_overlay,
  _unmount_overlay, commit/rollback error paths, and cleanup edge cases.

  # ===================================================================
  # Group 1: _is_overlayfs_available() — lines 49, 51-53, 58-79
  # ===================================================================

  Scenario: oscov3 overlayfs unavailable when overlay not in proc filesystems
    Given oscov3 the lru_cache for _is_overlayfs_available is cleared
    And oscov3 /proc/filesystems is mocked to contain "nofilesystem ext4"
    When oscov3 _is_overlayfs_available is called
    Then oscov3 the result should be False

  Scenario: oscov3 overlayfs unavailable when proc filesystems is not a file
    Given oscov3 the lru_cache for _is_overlayfs_available is cleared
    And oscov3 os.path.isfile is mocked to return False for /proc/filesystems
    When oscov3 _is_overlayfs_available is called
    Then oscov3 the result should be False

  Scenario: oscov3 overlayfs unavailable when reading proc filesystems raises OSError
    Given oscov3 the lru_cache for _is_overlayfs_available is cleared
    And oscov3 open is mocked to raise OSError for /proc/filesystems
    When oscov3 _is_overlayfs_available is called
    Then oscov3 the result should be False

  Scenario: oscov3 overlayfs probe succeeds when mount returns zero
    Given oscov3 the lru_cache for _is_overlayfs_available is cleared
    And oscov3 the system is mocked as root with overlay in proc filesystems
    And oscov3 subprocess.run is mocked for successful mount probe
    When oscov3 _is_overlayfs_available is called
    Then oscov3 the result should be True

  Scenario: oscov3 overlayfs probe fails when mount returns non-zero
    Given oscov3 the lru_cache for _is_overlayfs_available is cleared
    And oscov3 the system is mocked as root with overlay in proc filesystems
    And oscov3 subprocess.run is mocked for failed mount probe
    When oscov3 _is_overlayfs_available is called
    Then oscov3 the result should be False

  Scenario: oscov3 overlayfs probe returns False on OSError
    Given oscov3 the lru_cache for _is_overlayfs_available is cleared
    And oscov3 the system is mocked as root with overlay in proc filesystems
    And oscov3 subprocess.run is mocked to raise OSError during probe
    When oscov3 _is_overlayfs_available is called
    Then oscov3 the result should be False

  Scenario: oscov3 overlayfs probe returns False on TimeoutExpired
    Given oscov3 the lru_cache for _is_overlayfs_available is cleared
    And oscov3 the system is mocked as root with overlay in proc filesystems
    And oscov3 subprocess.run is mocked to raise TimeoutExpired during probe
    When oscov3 _is_overlayfs_available is called
    Then oscov3 the result should be False

  # ===================================================================
  # Group 2: Real overlay in create — line 180
  # ===================================================================

  Scenario: oscov3 create with real overlay calls _mount_overlay
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created with _use_real_overlay forced to True
    And oscov3 _mount_overlay is mocked to succeed
    When oscov3 the sandbox create is called for plan "plan-real-ov"
    Then oscov3 the sandbox should be in "created" state
    And oscov3 _mount_overlay should have been called

  # ===================================================================
  # Group 3: Commit edge cases — lines 283, 309-311, 343-348
  # ===================================================================

  Scenario: oscov3 commit with merged_dir None raises SandboxStateError
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created and activated for plan "plan-commit-none"
    And oscov3 merged_dir is forced to None
    When oscov3 commit is attempted
    Then oscov3 a SandboxStateError should have been raised with "merged directory not set"

  Scenario: oscov3 commit backup_directory failure cleans up temp dir
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created and activated for plan "plan-backup-fail"
    And oscov3 a file "trigger.txt" is added to the sandbox
    And oscov3 backup_directory is mocked to raise RuntimeError
    When oscov3 commit is attempted
    Then oscov3 a SandboxCommitError should have been raised
    And oscov3 the sandbox should be in "errored" state

  Scenario: oscov3 commit fails and safe_restore also fails logs warning
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created and activated for plan "plan-double-fail"
    And oscov3 a file "trigger.txt" is added to the sandbox
    And oscov3 copy2 is mocked to fail after backup succeeds
    And oscov3 safe_restore is mocked to raise RuntimeError
    When oscov3 commit is attempted
    Then oscov3 a SandboxCommitError should have been raised
    And oscov3 the sandbox should be in "errored" state

  # ===================================================================
  # Group 4: Rollback edge cases — lines 402, 436-459, 471-479, 498-499
  # ===================================================================

  Scenario: oscov3 rollback with merged_dir None raises SandboxStateError
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created and activated for plan "plan-rb-none"
    And oscov3 merged_dir is forced to None
    When oscov3 rollback is attempted
    Then oscov3 a SandboxStateError should have been raised with "merged directory not set"

  Scenario: oscov3 rollback from COMMITTED with real overlay happy path
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created and activated for plan "plan-rb-real"
    And oscov3 _use_real_overlay is forced to True
    And oscov3 a file "data.txt" is added to the sandbox
    And oscov3 the sandbox is committed successfully
    And oscov3 subprocess.run is mocked for umount and mount during rollback
    When oscov3 rollback is called
    Then oscov3 the sandbox should be in "rolled_back" state

  Scenario: oscov3 rollback from COMMITTED real overlay umount fails
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created and activated for plan "plan-rb-umount-fail"
    And oscov3 _use_real_overlay is forced to True
    And oscov3 a file "data.txt" is added to the sandbox
    And oscov3 the sandbox is committed successfully
    And oscov3 subprocess.run is mocked to raise CalledProcessError for umount
    When oscov3 rollback is attempted
    Then oscov3 a SandboxRollbackError should have been raised
    And oscov3 the sandbox should be in "errored" state

  Scenario: oscov3 rollback from ACTIVE with real overlay
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created and activated for plan "plan-rb-active-real"
    And oscov3 _use_real_overlay is forced to True
    And oscov3 subprocess.run is mocked for unmount and mount during active rollback
    When oscov3 rollback is called
    Then oscov3 the sandbox should be in "rolled_back" state

  # ===================================================================
  # Group 5: Cleanup — lines 532, 539-541
  # ===================================================================

  Scenario: oscov3 cleanup with real overlay calls _unmount_overlay
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created for plan "plan-cleanup-real"
    And oscov3 _use_real_overlay is forced to True
    And oscov3 _unmount_overlay is mocked
    When oscov3 cleanup is called
    Then oscov3 the sandbox should be in "cleaned_up" state
    And oscov3 _unmount_overlay should have been called

  Scenario: oscov3 cleanup removes pre_commit_backup
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created for plan "plan-cleanup-backup"
    And oscov3 a pre_commit_backup directory exists
    When oscov3 cleanup is called
    Then oscov3 the sandbox should be in "cleaned_up" state
    And oscov3 pre_commit_backup should be None

  Scenario: oscov3 cleanup removes pre_commit_backup even if dir missing
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created for plan "plan-cleanup-backup2"
    And oscov3 pre_commit_backup is set to a non-existent path
    When oscov3 cleanup is called
    Then oscov3 the sandbox should be in "cleaned_up" state
    And oscov3 pre_commit_backup should be None

  # ===================================================================
  # Group 6: _mount_overlay / _unmount_overlay — lines 562-618
  # ===================================================================

  Scenario: oscov3 _mount_overlay raises error when path contains comma
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created for plan "plan-comma"
    And oscov3 _original_path contains a comma
    When oscov3 _mount_overlay is called directly
    Then oscov3 a SandboxCreationError should have been raised with "comma"

  Scenario: oscov3 _mount_overlay raises error when upper_dir contains comma
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created for plan "plan-comma-upper"
    And oscov3 _upper_dir contains a comma
    When oscov3 _mount_overlay is called directly
    Then oscov3 a SandboxCreationError should have been raised with "comma"

  Scenario: oscov3 _mount_overlay succeeds with mocked subprocess
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created for plan "plan-mount-ok"
    And oscov3 subprocess.run is mocked for successful mount
    When oscov3 _mount_overlay is called directly
    Then oscov3 no error should have been raised

  Scenario: oscov3 _mount_overlay fails with CalledProcessError
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created for plan "plan-mount-fail"
    And oscov3 subprocess.run is mocked to raise CalledProcessError for mount
    When oscov3 _mount_overlay is called directly
    Then oscov3 a SandboxCreationError should have been raised with "Failed to mount"

  Scenario: oscov3 _mount_overlay fails with TimeoutExpired
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created for plan "plan-mount-timeout"
    And oscov3 subprocess.run is mocked to raise TimeoutExpired for mount
    When oscov3 _mount_overlay is called directly
    Then oscov3 a SandboxCreationError should have been raised with "Failed to mount"

  Scenario: oscov3 _mount_overlay fails with OSError
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created for plan "plan-mount-oserr"
    And oscov3 subprocess.run is mocked to raise OSError for mount
    When oscov3 _mount_overlay is called directly
    Then oscov3 a SandboxCreationError should have been raised with "Failed to mount"

  Scenario: oscov3 _unmount_overlay succeeds
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created for plan "plan-umount-ok"
    And oscov3 subprocess.run is mocked for successful umount
    When oscov3 _unmount_overlay is called directly
    Then oscov3 no error should have been raised

  Scenario: oscov3 _unmount_overlay fails and logs warning
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created for plan "plan-umount-fail"
    And oscov3 subprocess.run is mocked to raise CalledProcessError for umount
    When oscov3 _unmount_overlay is called directly
    Then oscov3 no error should have been raised

  Scenario: oscov3 _unmount_overlay with merged_dir None is a no-op
    Given oscov3 a test directory is initialised
    And oscov3 a sandbox is created for plan "plan-umount-none"
    And oscov3 merged_dir is forced to None
    When oscov3 _unmount_overlay is called directly
    Then oscov3 no error should have been raised
