Repository Analysis

gorakhargosh/watchdog

Python library and shell utilities to monitor filesystem events.

14.6 Low AI signal View on GitHub

Analysis Overview

This report presents the forensic synthetic code analysis of gorakhargosh/watchdog, a Python project with 7,393 GitHub stars. SynthScan v2.0 examined 15,362 lines of code across 79 source files, recording 189 pattern matches distributed across 10 syntactic categories. The overall adjusted score of 14.6 places this repository in the Low AI signal band.

The scanner applied 160+ deterministic lexical heuristics, multi-line block detectors, abstract syntax tree depth profilers, and a cross-file Jaccard similarity matrix to construct a statistically normalised synthetic code estimate. All matches are individually weighted by severity coefficient and contextual multiplier before summation, and the resulting headline score is temporally discounted to account for the repository's development history relative to the commercial emergence of large language model coding tooling (November 2022 onward).

14.6
Adjusted Score
14.6
Raw Score
100%
Time Factor
2026-08-07
Last Push
7.4K
Stars
Python
Language
15.4K
Lines of Code
79
Files
189
Pattern Hits
2026-08-09
Scan Date
0.08
HC Hit Rate

What These Metrics Mean

Adjusted Score
Primary synthetic code indicator. Raw score normalised per 1,000 lines of code and multiplied by the temporal discount factor. This is the definitive comparative metric — use it to rank repositories by AI authorship density.
Raw Score
The unmodified sum of all severity-weighted, context-multiplied pattern match scores before temporal discounting. Reflects the absolute signal strength independent of when the repository was last active.
Time Factor
The temporal discount multiplier (0–100%) applied to the raw score. Repositories last updated before ChatGPT's launch (Nov 2022) receive a 5% factor. Full signal is only assigned to repositories active in the post-adoption era (Jan 2024+).
Pattern Hits
Total count of individual pattern matches across all files and categories. A high hit count with a low score may indicate a very large codebase with isolated AI snippets; a low count with a high score indicates dense, concentrated AI signatures.
HC Hit Rate
High+Critical pattern hits per file, averaged across the repository. This orthogonal signal catches repositories where a few files are densely packed with high-severity AI tells — a strong indicator even when the normalised score appears moderate due to codebase size.
Lines of Code / Files
Total lines and files analysed. The scanner examines 94 file extensions. These denominators are used to normalise the score, enabling fair comparison between repositories of vastly different sizes.

Score History

Longitudinal tracking requires multiple scan runs. Once this repository is re-scanned after new commits land, this chart will visualise how the synthetic code signal evolves over time — enabling you to detect whether AI authorship is growing, stabilising, or being actively corrected by human engineers.

No multi-scan history yet — run the scanner again to build trend data.

Severity Breakdown

Classifies detected patterns by their diagnostic confidence and structural impact. CRITICAL patterns (coefficient 10) represent definitive synthetic signatures — hallucinated imports, explicit LLM attribution metadata — virtually never produced by human authors. HIGH (5) indicates strong structural tells such as cross-file repetition or cross-linguistic idioms. MEDIUM (2) covers recognisable conversational padding and AI-specific vocabulary. LOW (1) captures subtle indicators like tautological comments and generic boilerplate that require density to carry independent signal.

CRITICAL 0HIGH 6MEDIUM 4LOW 179

Directory Score Breakdown

This horizontal bar chart decomposes the repository's raw synthetic code score by top-level directory, allowing you to pinpoint precisely which modules or components carry the highest AI authorship density. Directories with disproportionately high scores relative to their size warrant targeted manual review: concentrated AI signatures often trace back to mass-generated configuration layers, auto-ported test suites, LLM-scaffolded boilerplate classes, or entire subsystems authored under heavy copilot assistance. Use this view to prioritise your human code-review effort.

Pattern Findings

The scanner identified 189 distinct pattern matches across 10 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a statistically significant AI authorship indicator. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.

Reading the findings table: The Severity column indicates the diagnostic confidence level (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — comment-context matches receive a ×1.5 weight because LLMs systematically over-annotate. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier as dense clusters constitute far stronger evidence of synthetic authorship than isolated hits.

Hyper-Verbose Identifiers72 hits · 74 pts
SeverityFileLineSnippetContext
LOWtests/test_inotify_c.py44def test_late_double_deletion(helper: Helper, p: P, event_queue: TestEventQueue, start_watching: StartWatching) -> None:CODE
LOWtests/test_kqueue.py19def test_register_kevent_ignores_permission_errors(tmpdir, err):CODE
LOWtests/test_logging_event_handler.py63def test_logging_event_handler_dispatch():CODE
LOWtests/test_isolated.py13def test_observer_stops_in_eventlet():CODE
LOWtests/test_isolated.py21def test_eventlet_skip_repeat_queue():CODE
LOWtests/test_snapshot_diff.py44def test_move_to_with_context_manager(p):CODE
LOWtests/test_snapshot_diff.py93def test_dir_modify_on_create(p):CODE
LOWtests/test_snapshot_diff.py112def test_detect_modify_for_moved_files(p):CODE
LOWtests/test_snapshot_diff.py123def test_replace_dir_with_file(p):CODE
LOWtests/test_observer.py35def test_schedule_should_start_emitter_if_running(observer):CODE
LOWtests/test_observer.py42def test_schedule_should_not_start_emitter_if_not_running(observer):CODE
LOWtests/test_observer.py48def test_start_should_start_emitter(observer):CODE
LOWtests/test_observer.py55def test_stop_should_stop_emitter(observer):CODE
LOWtests/test_observer.py88def test_schedule_after_unschedule_all(observer):CODE
LOWtests/test_observer.py110def test_start_failure_should_not_prevent_further_try(observer):CODE
LOWtests/test_observer.py135def test_schedule_failure_should_not_prevent_future_schedules(observer):CODE
LOWtests/test_observer.py152def test_context_manager_starts_observer():CODE
LOWtests/test_observer.py168def test_context_manager_with_already_started_observer():CODE
LOWtests/test_observer.py186def test_context_manager_stops_on_exit():CODE
LOWtests/test_observer.py202def test_context_manager_handles_exceptions():CODE
LOWtests/test_observer.py222def test_context_manager_with_scheduled_watches():CODE
LOWtests/test_fsevents.py72def test_coalesced_event_check(event, expectation):CODE
LOWtests/test_fsevents.py210def test_unschedule_removed_folder(observer: BaseObserver, p: P) -> None:CODE
LOWtests/test_fsevents.py232def test_converting_cfstring_to_pyunicode(p: P, start_watching: StartWatching, events_checker: EventsChecker) -> None:CODE
LOWtests/test_fsevents.py248def test_recursive_check_accepts_relative_paths(p: P) -> None:CODE
LOWtests/utils.py217 def _check_events_without_order(self, found_events: list[FileSystemEvent]) -> None:CODE
LOWtests/test_0_watchmedo.py78def test_shell_command_wait_for_completion(tmpdir, capfd):CODE
LOWtests/test_0_watchmedo.py90def test_shell_command_subprocess_termination_nowait(tmpdir):CODE
LOWtests/test_0_watchmedo.py101def test_shell_command_subprocess_termination_not_happening_on_file_opened_event(CODE
LOWtests/test_0_watchmedo.py115def test_auto_restart_not_happening_on_file_opened_event(tmpdir, capfd):CODE
LOWtests/test_0_watchmedo.py131def test_auto_restart_on_file_change(tmpdir, capfd):CODE
LOWtests/test_0_watchmedo.py154def test_auto_restart_on_file_change_debounce(tmpdir, capfd):CODE
LOWtests/test_0_watchmedo.py190def test_auto_restart_subprocess_termination(tmpdir, capfd, restart_on_command_exit):CODE
LOWtests/test_0_watchmedo.py209def test_auto_restart_arg_parsing_basic():CODE
LOWtests/test_0_watchmedo.py218def test_auto_restart_arg_parsing():CODE
LOWtests/test_0_watchmedo.py237def test_auto_restart_events_echoed(tmpdir, caplog):CODE
LOWtests/test_0_watchmedo.py254def test_logger_events_echoed(caplog):CODE
LOWtests/test_0_watchmedo.py269def test_shell_command_arg_parsing():CODE
LOWtests/test_skip_repeats_queue.py24def test_allow_nonconsecutive():CODE
LOWtests/test_skip_repeats_queue.py40def test_put_with_watchdog_events():CODE
LOWtests/test_skip_repeats_queue.py67def test_consecutives_allowed_across_empties():CODE
LOWtests/test_observers_api.py12def test_observer_constructor():CODE
LOWtests/test_events.py41def test_file_delete_event_is_directory():CODE
LOWtests/test_events.py56def test_file_modified_event_is_directory():CODE
LOWtests/test_events.py88def test_file_closed_no_write_event():CODE
LOWtests/test_events.py128def test_file_system_event_handler_dispatch():CODE
LOWtests/test_events.py227def test_generate_sub_moved_events_repeated_dirname():CODE
LOWtests/test_regex_matching_event_handler.py185def test_logging_event_handler_dispatch():CODE
LOWtests/test_inotify_watch_group.py78def test_move_internal_symlink_followed(p):CODE
LOWtests/test_inotify_watch_group.py117def test_delete_watched_directory(p):CODE
LOWtests/test_inotify_watch_group.py130def test_delete_watched_directory_symlink_followed(p):CODE
LOWtests/test_inotify_watch_group.py149def test_delete_watched_directory_symlink_followed_recursive(p):CODE
LOWtests/test_inotify_watch_group.py170def test_unmount_watched_directory_filesystem(p):CODE
LOWtests/test_inotify_watch_group.py200def test_watch_groups_are_independent(p):CODE
LOWtests/test_inotify_watch_group.py224 def assert_inotify_root_events(inotify_root: InotifyWatchGroup) -> None:CODE
LOWtests/test_emitter.py87def test_create_wrong_encoding(CODE
LOWtests/test_emitter.py267def test_separate_consecutive_moves(CODE
LOWtests/test_emitter.py307def test_fast_subdirectory_creation_deletion(CODE
LOWtests/test_emitter.py328def test_passing_unicode_should_give_unicode(p: P, event_queue: TestEventQueue, start_watching: StartWatching) -> None:CODE
LOWtests/test_emitter.py339def test_passing_bytes_should_give_bytes(p: P, event_queue: TestEventQueue, start_watching: StartWatching) -> None:CODE
12 more matches not shown…
Unused Imports48 hits · 48 pts
SeverityFileLineSnippetContext
LOWtests/test_inotify_c.py1CODE
LOWtests/conftest.py1CODE
LOWtests/test_pattern_matching_event_handler.py1CODE
LOWtests/test_kqueue.py1CODE
LOWtests/test_logging_event_handler.py1CODE
LOWtests/test_snapshot_diff.py1CODE
LOWtests/test_delayed_queue.py1CODE
LOWtests/test_observer.py1CODE
LOWtests/test_fsevents.py1CODE
LOWtests/shell.py8CODE
LOWtests/test_patterns.py1CODE
LOWtests/test_observers_winapi.py1CODE
LOWtests/utils.py1CODE
LOWtests/test_0_watchmedo.py1CODE
LOWtests/test_skip_repeats_queue.py1CODE
LOWtests/test_observers_polling.py1CODE
LOWtests/test_observers_api.py1CODE
LOWtests/test_events.py1CODE
LOWtests/test_regex_matching_event_handler.py1CODE
LOWtests/test_examples.py1CODE
LOWtests/test_inotify_watch_group.py1CODE
LOWtests/test_emitter.py1CODE
LOWdocs/source/examples/debounced.py1CODE
LOWdocs/source/examples/simple.py1CODE
LOWsrc/watchdog/watchmedo.py7CODE
LOWsrc/watchdog/version.py1CODE
LOWsrc/watchdog/events.py82CODE
LOWsrc/watchdog/utils/patterns.py8CODE
LOWsrc/watchdog/utils/__init__.py15CODE
LOWsrc/watchdog/utils/event_debouncer.py1CODE
LOWsrc/watchdog/utils/dirsnapshot.py32CODE
LOWsrc/watchdog/utils/delayed_queue.py6CODE
LOWsrc/watchdog/utils/platform.py1CODE
LOWsrc/watchdog/utils/process_watcher.py1CODE
LOWsrc/watchdog/utils/bricks.py20CODE
LOWsrc/watchdog/utils/echo.py26CODE
LOWsrc/watchdog/observers/fsevents.py8CODE
LOWsrc/watchdog/observers/inotify_move_event_grouper.py9CODE
LOWsrc/watchdog/observers/inotify.py69CODE
LOWsrc/watchdog/observers/__init__.py37CODE
LOWsrc/watchdog/observers/api.py1CODE
LOWsrc/watchdog/observers/winapi.py12CODE
LOWsrc/watchdog/observers/read_directory_changes.py1CODE
LOWsrc/watchdog/observers/kqueue.py58CODE
LOWsrc/watchdog/observers/inotify_c.py1CODE
LOWsrc/watchdog/observers/polling.py22CODE
LOWsrc/watchdog/observers/fsevents2.py8CODE
LOWsrc/watchdog/tricks/__init__.py26CODE
Cross-File Repetition6 hits · 30 pts
SeverityFileLineSnippetContext
HIGHtests/conftest.py0convenience function to join the temporary directory path with the provided arguments.STRING
HIGHtests/test_observers_winapi.py0convenience function to join the temporary directory path with the provided arguments.STRING
HIGHtests/test_observers_polling.py0convenience function to join the temporary directory path with the provided arguments.STRING
HIGHsrc/watchdog/observers/inotify.py0observer thread that schedules watching directories and dispatches calls to event handlers.STRING
HIGHsrc/watchdog/observers/read_directory_changes.py0observer thread that schedules watching directories and dispatches calls to event handlers.STRING
HIGHsrc/watchdog/observers/kqueue.py0observer thread that schedules watching directories and dispatches calls to event handlers.STRING
Deep Nesting23 hits · 23 pts
SeverityFileLineSnippetContext
LOWtests/test_inotify_c.py44CODE
LOWtests/utils.py217CODE
LOWtests/test_emitter.py346CODE
LOWtests/test_emitter.py387CODE
LOWsrc/watchdog/watchmedo.py269CODE
LOWsrc/watchdog/watchmedo.py463CODE
LOWsrc/watchdog/utils/backwards_compat.py24CODE
LOWsrc/watchdog/utils/backwards_compat.py96CODE
LOWsrc/watchdog/utils/event_debouncer.py49CODE
LOWsrc/watchdog/utils/dirsnapshot.py321CODE
LOWsrc/watchdog/observers/fsevents.py161CODE
LOWsrc/watchdog/observers/inotify.py210CODE
LOWsrc/watchdog/observers/inotify.py319CODE
LOWsrc/watchdog/observers/inotify.py442CODE
LOWsrc/watchdog/observers/inotify.py502CODE
LOWsrc/watchdog/observers/__init__.py53CODE
LOWsrc/watchdog/observers/read_directory_changes.py67CODE
LOWsrc/watchdog/observers/kqueue.py424CODE
LOWsrc/watchdog/observers/kqueue.py494CODE
LOWsrc/watchdog/observers/kqueue.py610CODE
LOWsrc/watchdog/observers/inotify_c.py376CODE
LOWsrc/watchdog/observers/fsevents2.py200CODE
LOWsrc/watchdog/tricks/__init__.py268CODE
Over-Commented Block15 hits · 15 pts
SeverityFileLineSnippetContext
LOWdocs/source/conf.py1# watchdog documentation build configuration file, created byCOMMENT
LOW.github/workflows/build-and-publish.yml1# Because this library provides extension modules for macOS, but not for otherCOMMENT
LOWsrc/pythoncapi_compat.h1// Header file providing new C API functions to old Python versions.COMMENT
LOWsrc/pythoncapi_compat.h21#include <Python.h>COMMENT
LOWsrc/pythoncapi_compat.h41# if (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L) \COMMENT
LOWsrc/pythoncapi_compat.h121# define Py_IsNone(x) Py_Is(x, Py_None)COMMENT
LOWsrc/pythoncapi_compat.h481COMMENT
LOWsrc/pythoncapi_compat.h541#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION)COMMENT
LOWsrc/pythoncapi_compat.h1221# define PyHASH_IMAG _PyHASH_IMAGCOMMENT
LOWsrc/pythoncapi_compat.h1921#if PY_VERSION_HEX < 0x030C00A3COMMENT
LOWsrc/pythoncapi_compat.h1941COMMENT
LOWsrc/watchdog_fsevents.c21#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13COMMENT
LOWsrc/watchdog/observers/fsevents.py181COMMENT
LOWsrc/watchdog/observers/inotify.py221 if event.is_moved_from:COMMENT
LOWsrc/watchdog/observers/kqueue.py441 # of created and deleted events for the path.COMMENT
Modern Structural Boilerplate11 hits · 11 pts
SeverityFileLineSnippetContext
LOWtests/test_inotify_c.py28logger = logging.getLogger(__name__)CODE
LOWtests/test_fsevents.py36logger = logging.getLogger(__name__)CODE
LOWtests/test_emitter.py33logger = logging.getLogger(__name__)CODE
LOWsrc/watchdog/utils/event_debouncer.py14logger = logging.getLogger(__name__)CODE
LOWsrc/watchdog/utils/process_watcher.py12logger = logging.getLogger(__name__)CODE
LOWsrc/watchdog/observers/inotify_move_event_grouper.py21logger = logging.getLogger(__name__)CODE
LOWsrc/watchdog/observers/inotify.py114logger = logging.getLogger(__name__)CODE
LOWsrc/watchdog/observers/__init__.py91__all__ = ["Observer"]CODE
LOWsrc/watchdog/observers/inotify_c.py22logger = logging.getLogger(__name__)CODE
LOWsrc/watchdog/observers/fsevents2.py65logger = logging.getLogger(__name__)CODE
LOWsrc/watchdog/tricks/__init__.py42logger = logging.getLogger(__name__)CODE
Excessive Try-Catch Wrapping8 hits · 10 pts
SeverityFileLineSnippetContext
MEDIUMsrc/watchdog/watchmedo.py799 print(f"Error: {exc.args[0]}", file=sys.stderr) # noqa:T201CODE
LOWsrc/watchdog/utils/process_watcher.py29 except Exception:CODE
LOWsrc/watchdog/observers/fsevents.py302 except Exception:CODE
LOWsrc/watchdog/observers/fsevents.py311 except Exception:CODE
LOWsrc/watchdog/observers/__init__.py62 except Exception:CODE
LOWsrc/watchdog/observers/__init__.py65 except Exception:CODE
LOWsrc/watchdog/observers/__init__.py75 except Exception:CODE
LOWsrc/watchdog/observers/api.py308 except Exception:CODE
Self-Referential Comments3 hits · 9 pts
SeverityFileLineSnippetContext
MEDIUMtests/test_snapshot_diff.py169 # Create a file and take a snapshot.COMMENT
MEDIUMtests/test_snapshot_diff.py206 # Create a file and declare a DirectorySnapshot and a EmptyDirectorySnapshot.COMMENT
MEDIUMdocs/source/conf.py4# This file is execfile()d with the current directory set to its containing dir.COMMENT
Redundant / Tautological Comments2 hits · 3 pts
SeverityFileLineSnippetContext
LOWsrc/watchdog/observers/fsevents.py228 # Check if we have a corresponding destination event in the watched path.COMMENT
LOWsrc/watchdog/observers/inotify_move_event_grouper.py73 # Check if move_from is in delayqueue alreadyCOMMENT
Overly Generic Function Names1 hit · 0 pts
SeverityFileLineSnippetContext
LOWsrc/watchdog/utils/echo.py21 def my_function(args):STRING