Feature: ResourceFileWatcher coverage boost Additional scenarios that exercise previously uncovered error-handling and fallback code paths in resource_file_watcher.py. Background: Given the resource_file_watcher module is imported # ---- start() OSError fallback to PollingObserver (lines 255-264) ---- Scenario: start falls back to PollingObserver when inotify raises OSError Given a ResourceFileWatcher with default auto_reindex enabled And the native Observer start method is patched to raise OSError When the watcher start method is called Then the watcher should be running And the watcher should be using polling observer # ---- watch() schedule OSError fallback when not using polling (lines 168-180, 295-304) ---- Scenario: watch falls back to polling when schedule raises OSError on non-polling observer Given a ResourceFileWatcher that is running with a mock native observer And a temporary file exists for watching And the mock observer schedule method raises OSError When I watch the temporary file with resource "res-fallback" project "proj-fallback" Then the watcher should have switched to polling observer And the temporary file should be in the watched paths # ---- watch() schedule OSError re-raise when already polling (line 183) ---- Scenario: watch re-raises OSError when schedule fails and already using polling Given a ResourceFileWatcher that is running with a mock polling observer And a temporary file exists for watching And the mock observer schedule method raises OSError When I watch the temporary file expecting OSError with resource "res-reraise" project "proj-reraise" Then the watch call should have raised OSError # ---- stop() with observer that stays alive after join (lines 325-329) ---- Scenario: stop logs warning when observer thread does not terminate in time Given a ResourceFileWatcher with a mock observer that stays alive after join When the watcher is stopped Then the watcher should not be running after stop And the observer join timeout warning path should have been exercised # ---- _switch_to_polling_observer_locked with existing observer (lines 297-304) ---- Scenario: switch to polling observer stops old observer and creates new one Given a ResourceFileWatcher with a mock native observer and watched paths And a temporary file exists for watching When _switch_to_polling_observer_locked is called directly Then the old observer should have been stopped And the watcher should now have a polling observer # ---- start() with pre-registered paths rebuilds watches with polling fallback ---- Scenario: start with pre-registered paths falls back to polling on OSError Given a ResourceFileWatcher with a pre-registered watched path And the native Observer start method is patched to raise OSError When the watcher start method is called Then the watcher should be running And the watcher should be using polling observer And the directory watches should include the pre-registered path parent # ---- _fire_change with dest_path populates event details ---- Scenario: _fire_change includes dest_path in EventBus event details Given a ResourceFileWatcher with a tracking EventBus and debounce 0 And the watcher is marked as running When _fire_change is invoked with a dest_path argument Then the emitted event details should contain the dest_path # ---- _fire_change when watcher not running exits early (line 459) ---- Scenario: _fire_change exits early when watcher is not running Given a ResourceFileWatcher with a tracking callback And the watcher is not running When _fire_change is invoked directly Then the callback should not have been called