The lektor static file content management system
This report presents the forensic synthetic code analysis of lektor/lektor, a Python project with 3,946 GitHub stars. SynthScan v2.0 examined 47,253 lines of code across 369 source files, recording 371 pattern matches distributed across 15 syntactic categories. The overall adjusted score of 9.4 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).
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.
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.
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.
The scanner identified 371 distinct pattern matches across 15 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.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | frontend/js/widgets.tsx | 119 | export function getWidgetComponentWithFallback( | CODE |
| LOW | frontend/js/shortcut-keys.ts | 132 | export function installShortcutKeyListener(keymap: ShortcutKeyMap) { | CODE |
| LOW | frontend/js/shortcut-keys.ts | 160 | export function deserializeShortcutKeyMap(obj: unknown): ShortcutKeyMap { | CODE |
| LOW | frontend/js/widgets/SingleLineTextInputWidget.tsx | 7 | export function SingleLineTextInputWidget( | CODE |
| LOW | tests/test_videotools.py | 51 | def test_get_ffmpeg_quality_bad_range(in_quality): | CODE |
| LOW | tests/test_videotools.py | 64 | def test_dimensions_aspect_ratio(dim, ar): | CODE |
| LOW | tests/test_videotools.py | 76 | def test_dimensions_fit_within(source, target, upscale, rescale): | CODE |
| LOW | tests/test_videotools.py | 127 | def test_dimensions_invalid_resize(): | CODE |
| LOW | tests/test_reporter.py | 24 | def test_describe_build_func_describes_partial(): | CODE |
| LOW | tests/test_reporter.py | 37 | def test_describe_build_func_deals_with_garbage(): | CODE |
| LOW | tests/test_utils.py | 220 | def test_url_builder_dot_handling(): | CODE |
| LOW | tests/test_utils.py | 267 | def test_make_relative_url_relative_source_absolute_target(): | CODE |
| LOW | tests/test_utils.py | 285 | def test_atomic_open_exception(tmp_path): | CODE |
| LOW | tests/test_utils.py | 308 | def test_atomic_open_respects_umask(tmp_path, umask): | CODE |
| LOW | tests/test_utils.py | 316 | def test_atomic_open_raises_on_bad_mode(tmp_path, mode): | CODE |
| LOW | tests/test_utils.py | 333 | def test_create_temp_respects_umask(tmp_path, mode, umask): | CODE |
| LOW | tests/test_utils.py | 406 | def test_deprecated_classmethod(): | CODE |
| LOW | tests/test_utils.py | 423 | def test_deprecated_raises_type_error(): | CODE |
| LOW | tests/test_utils.py | 428 | def test_deprecated_stacklevel(): | CODE |
| LOW | tests/test_utils.py | 456 | def test_untrusted_to_os_path(db_path, expected): | CODE |
| LOW | tests/test_issue_410.py | 41 | def test_build_childless_page(scratch_builder): | CODE |
| LOW | tests/test_pagination.py | 46 | def test_unpaginated_children(pad): | CODE |
| LOW | tests/test_pagination.py | 82 | def test_pagination_attributes(pad): | CODE |
| LOW | tests/test_pagination.py | 103 | def test_url_matching_for_pagination(pad): | CODE |
| LOW | tests/test_pagination.py | 125 | def test_pagination_url_paths(pad): | CODE |
| LOW | tests/test_pagination.py | 141 | def test_unpaginated_children_other_alt(pad): | CODE |
| LOW | tests/test_pagination.py | 177 | def test_url_matching_for_alt_pagination(pad): | CODE |
| LOW | tests/test_pagination.py | 190 | def test_pagination_items_filter(pad): | CODE |
| LOW | tests/test_pagination.py | 211 | def test_virtual_path_behavior(pad): | CODE |
| LOW | tests/conftest.py | 261 | def child_sources_test_project_builder(tmp_path, data_path, save_sys_path): | CODE |
| LOW | tests/test_unicode.py | 22 | def test_unicode_project_folder(pad, builder): | CODE |
| LOW | tests/test_unicode.py | 28 | def test_unicode_attachment_filename(pad, builder): | CODE |
| LOW | tests/test_packages.py | 153 | def test_update_cache_installs_requirements( | CODE |
| LOW | tests/test_packages.py | 165 | def test_update_cache_skips_install_if_up_to_date( | CODE |
| LOW | tests/test_packages.py | 178 | def test_update_cache_removes_package_cache_if_no_requirements(tmp_path: Path) -> None: | CODE |
| LOW | tests/test_packages.py | 186 | def test_load_packages_add_package_cache_to_sys_path(env: Environment) -> None: | CODE |
| LOW | tests/test_packages.py | 197 | def test_load_packages_reinstall_wipes_cache( | CODE |
| LOW | tests/test_assets.py | 60 | def test_asset_source_filename(asset, pad, asset_path): | CODE |
| LOW | tests/test_assets.py | 87 | def test_asset_url_content_path(asset, expected): | CODE |
| LOW | tests/test_assets.py | 117 | def test_asset_children_no_children_if_dir_unreadable(asset): | CODE |
| LOW | tests/test_assets.py | 150 | def test_asset_get_child_from_url_param_deprecated(asset): | CODE |
| LOW | tests/test_assets.py | 202 | def test_directory_merges_subdirectories(asset_root, asset_paths): | CODE |
| LOW | tests/test_assets.py | 214 | def test_directory_file_shadows_directory(asset_root, asset_paths): | CODE |
| LOW | tests/test_assets.py | 228 | def test_directory_directory_conflicts_with_file(asset_root, asset_paths): | CODE |
| LOW | tests/test_tree.py | 89 | def test_tree_item_can_be_deleted(tree, path, expect): | CODE |
| LOW | tests/test_tree.py | 103 | def test_tree_item_is_visible(tree, path, expect): | CODE |
| LOW | tests/test_tree.py | 116 | def test_tree_item_is_attachment(tree, path, is_attachment, attachment_type): | CODE |
| LOW | tests/test_tree.py | 130 | def test_tree_item_can_have_children(tree, path, expect): | CODE |
| LOW | tests/test_tree.py | 164 | def test_tree_implied_child_datamodel(tree, path, expect): | CODE |
| LOW | tests/test_tree.py | 215 | def test_tree_item_get_children(tree, path, offset, limit, order_by, expect): | CODE |
| LOW | tests/test_tree.py | 264 | def test_tree_item_iter_subpages(tree, path, order_by, expect): | CODE |
| LOW | tests/test_tree.py | 284 | def test_tree_item_iter_attachments(tree, path, expect): | CODE |
| LOW | tests/test_tree.py | 297 | def test_tree_item_get_order_by(tree, path, order_by, expect): | CODE |
| LOW | tests/test_tree.py | 359 | def test_alt_is_primary_overlay(tree, alt, expect): | CODE |
| LOW⚡ | tests/test_quickstart.py | 32 | def test_default_author_from_pwd(mocker): | CODE |
| LOW⚡ | tests/test_quickstart.py | 40 | def test_default_author_from_username(mocker): | CODE |
| LOW⚡ | tests/test_quickstart.py | 48 | def test_default_author_email(git_config_file): | CODE |
| LOW | tests/test_quickstart.py | 61 | def test_default_author_email_no_default(monkeypatch): | CODE |
| LOW | tests/test_db.py | 31 | def test_project_implied_model(pad): | CODE |
| LOW | tests/test_db.py | 37 | def test_child_query_visibility_setting(pad): | CODE |
| 181 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | tests/conftest.py | 281 | reporter.push() | CODE |
| HIGH | tests/test_prev_next_sibling.py | 55 | reporter.push() | CODE |
| HIGH | lektor/reporter.py | 41 | _reporter_stack.push(self) | CODE |
| HIGH | lektor/reporter.py | 48 | self.push() | CODE |
| HIGH | lektor/builder.py | 960 | ctx.push() | CODE |
| HIGH | lektor/context.py | 136 | _ctx_stack.push(self) | CODE |
| HIGH | lektor/context.py | 143 | self.push() | CODE |
| HIGH⚡ | lektor/types/base.py | 10 | def get_undefined_info(undefined): | CODE |
| HIGH⚡ | lektor/types/base.py | 11 | if isinstance(undefined, Undefined): | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_pluginsystem.py | 3 | CODE | |
| LOW | tests/test_watcher.py | 1 | CODE | |
| LOW | tests/imagetools/test_exif.py | 1 | CODE | |
| LOW | tests/imagetools/test_thumbnail.py | 1 | CODE | |
| LOW | tests/imagetools/test_image_info.py | 1 | CODE | |
| LOW | tests/admin/test_serve.py | 1 | CODE | |
| LOW | lektor/devserver.py | 1 | CODE | |
| LOW | lektor/db.py | 2 | CODE | |
| LOW | lektor/cli_utils.py | 2 | CODE | |
| LOW | lektor/compat.py | 1 | CODE | |
| LOW | lektor/packages.py | 1 | CODE | |
| LOW | lektor/pluginsystem.py | 1 | CODE | |
| LOW | lektor/builder.py | 1 | CODE | |
| LOW | lektor/utils.py | 1 | CODE | |
| LOW | lektor/assets.py | 1 | CODE | |
| LOW | lektor/watcher.py | 1 | CODE | |
| LOW | lektor/publisher.py | 1 | CODE | |
| LOW | lektor/sourceobj.py | 1 | CODE | |
| LOW | lektor/project.py | 1 | CODE | |
| LOW | lektor/imagetools/image_info.py | 3 | CODE | |
| LOW | lektor/imagetools/thumbnail.py | 3 | CODE | |
| LOW | lektor/imagetools/__init__.py | 1 | CODE | |
| LOW | lektor/imagetools/__init__.py | 6 | CODE | |
| LOW | lektor/imagetools/__init__.py | 8 | CODE | |
| LOW | lektor/imagetools/__init__.py | 9 | CODE | |
| LOW | lektor/imagetools/__init__.py | 10 | CODE | |
| LOW | lektor/imagetools/__init__.py | 11 | CODE | |
| LOW | lektor/imagetools/exif.py | 3 | CODE | |
| LOW | lektor/imagetools/_compat.py | 3 | CODE | |
| LOW | lektor/types/__init__.py | 1 | CODE | |
| LOW | lektor/types/__init__.py | 2 | CODE | |
| LOW | lektor/types/__init__.py | 3 | CODE | |
| LOW | lektor/types/__init__.py | 4 | CODE | |
| LOW | lektor/markdown/controller.py | 23 | CODE | |
| LOW | lektor/markdown/mistune2.py | 3 | CODE | |
| LOW | lektor/markdown/__init__.py | 22 | CODE | |
| LOW | lektor/admin/webui.py | 1 | CODE | |
| LOW | lektor/admin/__init__.py | 1 | CODE | |
| LOW | lektor/admin/context.py | 1 | CODE | |
| LOW | lektor/admin/modules/serve.py | 1 | CODE | |
| LOW | lektor/admin/modules/livereload.py | 1 | CODE | |
| LOW | lektor/environment/__init__.py | 1 | CODE | |
| LOW | lektor/environment/__init__.py | 21 | CODE | |
| LOW | lektor/environment/__init__.py | 22 | CODE | |
| LOW | lektor/environment/__init__.py | 23 | CODE | |
| LOW | lektor/environment/__init__.py | 24 | CODE | |
| LOW | lektor/environment/__init__.py | 25 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_buildfailures.py | 33 | except Exception: | CODE |
| LOW⚡ | tests/test_buildfailures.py | 56 | except Exception: | CODE |
| LOW | tests/test_buildfailures.py | 88 | except Exception: | CODE |
| MEDIUM | tests/test_buildfailures.py | 53 | def test_failure_controller(failure_controller): | CODE |
| LOW | tests/admin/test_serve.py | 274 | except Exception: | CODE |
| LOW | lektor/devserver.py | 72 | except Exception: | CODE |
| LOW | lektor/datamodel.py | 329 | except Exception: | CODE |
| LOW | lektor/datamodel.py | 349 | except Exception as exc: | CODE |
| LOW | lektor/utils.py | 631 | except Exception: | CODE |
| LOW | lektor/publisher.py | 382 | except Exception as e: | CODE |
| LOW | lektor/publisher.py | 395 | except Exception as e: | CODE |
| LOW | lektor/publisher.py | 406 | except Exception as e: | CODE |
| LOW⚡ | lektor/publisher.py | 484 | except Exception as e: | CODE |
| LOW⚡ | lektor/publisher.py | 488 | except Exception as e: | CODE |
| LOW⚡ | lektor/publisher.py | 496 | except Exception as e: | CODE |
| LOW⚡ | lektor/publisher.py | 504 | except Exception as e: | CODE |
| MEDIUM | lektor/publisher.py | 477 | def rename_file(self, src, dst): | CODE |
| LOW | lektor/types/primitives.py | 110 | except Exception: | CODE |
| LOW | lektor/types/multi.py | 87 | except Exception: | CODE |
| LOW⚡ | lektor/types/base.py | 14 | except Exception as e: | CODE |
| LOW | lektor/environment/__init__.py | 114 | except Exception as exc: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_tree.py | 18 | CODE | |
| LOW | lektor/db.py | 598 | CODE | |
| LOW | lektor/db.py | 1134 | CODE | |
| LOW | lektor/db.py | 1302 | CODE | |
| LOW | lektor/db.py | 1358 | CODE | |
| LOW | lektor/db.py | 1455 | CODE | |
| LOW | lektor/db.py | 1493 | CODE | |
| LOW | lektor/reporter.py | 342 | CODE | |
| LOW | lektor/builder.py | 546 | CODE | |
| LOW | lektor/builder.py | 1177 | CODE | |
| LOW | lektor/builder.py | 1285 | CODE | |
| LOW | lektor/metaformat.py | 18 | CODE | |
| LOW | lektor/cli.py | 94 | CODE | |
| LOW | lektor/utils.py | 239 | CODE | |
| LOW | lektor/utils.py | 366 | CODE | |
| LOW | lektor/assets.py | 133 | CODE | |
| LOW | lektor/publisher.py | 549 | CODE | |
| LOW | lektor/sourceobj.py | 106 | CODE | |
| LOW | lektor/quickstart.py | 113 | CODE | |
| LOW | lektor/types/multi.py | 78 | CODE | |
| LOW | lektor/types/flow.py | 17 | CODE | |
| LOW | lektor/environment/__init__.py | 162 | CODE | |
| LOW | lektor/environment/__init__.py | 196 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/test_pluginsystem.py | 195 | # Create a plugin with no associated distribution. | COMMENT |
| MEDIUM⚡ | tests/test_buildfailures.py | 76 | # Create a directory in the location that FailureController wants | COMMENT |
| MEDIUM | lektor/builder.py | 678 | """This class represents a build artifact.""" | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | frontend/js/widgets/MultiLineTextInputWidget.tsx | 51 | * @return True if we are on a touch device | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | lektor/db.py | 1076 | # child_config.order_by, but for now, just return None. | COMMENT |
| LOW | lektor/db.py | 1549 | # The alternative system is not configured, just return | COMMENT |
| LOW | lektor/db.py | 1743 | # not allowed but one was passed, we just return `None`. | COMMENT |
| MEDIUM | lektor/publisher.py | 102 | """A wrapper around subprocess.Popen to facilitate streaming output via generator. | STRING |
| LOW | lektor/imagetools/thumbnail.py | 450 | # resize anything, we just return it. This is not ideal but it's | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tox.ini | 41 | # WARNING: Skipping page https://pypi.org/simple/coverage/ because the GET request | COMMENT |
| LOW | tests/test_themes.py | 101 | # only exist in themes-project assets will be loaded from there | COMMENT |
| LOW | lektor/db.py | 2061 | """ | COMMENT |
| LOW | lektor/build_programs.py | 201 | child_sources = [] | COMMENT |
| LOW | lektor/imagetools/thumbnail.py | 281 | # XXX: The old imagemagick code (which ran `convert` with `-strip -colorspace sRGB`) | COMMENT |
| LOW | lektor/imagetools/thumbnail.py | 341 | # | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | lektor/compat.py | 16 | __all__ = ["werkzeug_urls_URL"] | CODE |
| LOW | lektor/publisher.py | 714 | def set_ssh_credentials(self, credentials: Mapping[str, str]) -> None: | CODE |
| LOW | lektor/publisher.py | 725 | def set_https_credentials(self, credentials: Mapping[str, str]) -> None: | CODE |
| LOW | lektor/imagetools/__init__.py | 14 | __all__ = [ | CODE |
| LOW | lektor/imagetools/_compat.py | 15 | __all__ = ["ExifTags", "Transpose", "UnidentifiedImageError"] | CODE |
| LOW | lektor/admin/__init__.py | 4 | __all__ = ["WebAdmin"] | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | lektor/datamodel.py | 99 | # Check if we have a cached version | COMMENT |
| LOW | lektor/videotools.py | 84 | # Check if we should rescale at all | COMMENT |
| LOW | lektor/videotools.py | 120 | # Check if we should rescale at all | COMMENT |
| LOW | lektor/videotools.py | 153 | # Check if we should rescale at all | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/test_devcli.py | 116 | def test_function(): | STRING |
| LOW | lektor/db.py | 1516 | def process_data(self, data, datamodel, pad): | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | lektor/builder.py | 358 | # If we do have an already existing artifact, we need to check if | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_devcli.py | 39 | email = "jrh@example.org" | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | lektor/datamodel.py | 232 | CODE |