The modern API client that lives in your terminal.
This report summarizes scanner evidence for darrenburns/posting, a Python project with 12,499 GitHub stars. SynthScan examined 25,891 lines of code across 166 source files, recording 373 pattern matches distributed across 14 syntactic categories. The legacy adjusted pattern signal is 16.3 (Elevated pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Can maintainers explain intent, assumptions, and trade-offs? 268 finding(s).
Are imports declared and package/API names verified? 44 finding(s).
Are wrappers, guards, and repeated structures necessary? 294 finding(s).
Which changes need focused human review? 373 finding(s).
Run additional scans to build a history of the legacy pattern signal. Score changes are not a measure of AI adoption or code quality.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 373 distinct pattern matches across 14 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. 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 configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_request_model.py | 4 | def test_apply_template_absorbs_url_query_params(): | CODE |
| LOW | tests/test_request_model.py | 11 | def test_apply_template_fills_empty_table_value_from_url(): | CODE |
| LOW | tests/test_request_model.py | 22 | def test_apply_template_resolves_variables_in_url_query(): | CODE |
| LOW⚡ | tests/test_request_model.py | 34 | def test_query_variables_keep_reserved_characters_in_one_value(): | CODE |
| LOW⚡ | tests/test_request_model.py | 41 | def test_variable_containing_entire_url_preserves_repeated_query(): | CODE |
| LOW⚡ | tests/test_request_model.py | 51 | def test_percent_encoded_dollar_is_literal_not_a_variable(): | CODE |
| LOW | tests/test_request_search.py | 23 | def test_request_search_matches_visible_text(tmp_path, monkeypatch, query, expected): | CODE |
| LOW | tests/test_history_ui.py | 108 | def test_replay_restores_request(self, spacing, snap_compare): | CODE |
| LOW | tests/test_history_ui.py | 141 | def test_send_then_replay_and_send_again(self, snap_compare): | CODE |
| LOW | tests/test_history_ui.py | 178 | def test_clear_confirmation_and_delete(self, snap_compare): | CODE |
| LOW | tests/test_history_ui.py | 201 | def test_persisted_history_on_startup(self, tmp_path, snap_compare): | CODE |
| LOW | tests/test_history_ui.py | 260 | def test_narrow_right_sidebar(self, snap_compare): | CODE |
| LOW | tests/test_history_ui.py | 281 | def test_storage_failure_keeps_live_response(self, snap_compare): | CODE |
| LOW | tests/test_history_ui.py | 304 | def test_deleted_elsewhere_does_not_replay(self, snap_compare): | CODE |
| LOW | tests/test_history_ui.py | 323 | def test_jump_mode_and_keyboard_navigation(self, spacing, snap_compare): | CODE |
| LOW | tests/test_history_ui.py | 364 | def test_send_captures_configuration_before_scripts_and_inflight_edits( | CODE |
| LOW | tests/test_history_ui.py | 459 | def test_restore_body_clears_previous_content(self, body, kind): | CODE |
| LOW | tests/test_history_ui.py | 489 | def test_history_load_integrates_with_query_sync(self, query_in_url): | CODE |
| LOW | tests/test_history_ui.py | 544 | def test_legacy_entry_keeps_editor_and_explains_limitation(self, snap_compare): | CODE |
| LOW | tests/test_history_ui.py | 565 | def test_restore_detaches_previously_open_collection_request(self): | CODE |
| LOW | tests/test_history_ui.py | 594 | def test_missing_script_restores_then_reports_error_on_resend(self): | CODE |
| LOW | tests/test_session_variables.py | 7 | def test_undo_preserves_script_value(value): | CODE |
| LOW | tests/test_session_variables.py | 18 | def test_add_revert_and_repeated_undo_redo(): | CODE |
| LOW | tests/test_session_variables.py | 36 | def test_new_edit_invalidates_redo_and_history_is_bounded(): | CODE |
| LOW | tests/test_clipboard.py | 16 | def test_copy_uses_native_clipboard_when_available(monkeypatch) -> None: | CODE |
| LOW | tests/test_clipboard.py | 30 | def test_copy_falls_back_to_textual_clipboard(monkeypatch) -> None: | CODE |
| LOW⚡ | tests/test_variables_modal.py | 4 | def test_sensitive_names_are_recognised() -> None: | CODE |
| LOW⚡ | tests/test_variables_modal.py | 13 | def test_secrets_are_masked_by_default() -> None: | CODE |
| LOW⚡ | tests/test_variables_modal.py | 21 | def test_masking_does_not_leak_secret_length() -> None: | CODE |
| LOW⚡ | tests/test_variables_modal.py | 27 | def test_secrets_shown_when_revealed() -> None: | CODE |
| LOW⚡ | tests/test_variables_modal.py | 34 | def test_source_distinguishes_session_from_env_file() -> None: | CODE |
| LOW⚡ | tests/test_variables_modal.py | 44 | def test_filter_matches_on_name_case_insensitively() -> None: | CODE |
| LOW⚡ | tests/test_variables_modal.py | 52 | def test_rows_are_sorted_by_name() -> None: | CODE |
| LOW⚡ | tests/test_variables_modal.py | 57 | def test_non_string_values_are_rendered() -> None: | CODE |
| LOW | tests/test_query_sync.py | 47 | def test_query_sync_preserves_duplicates(query_app, second_value): | CODE |
| LOW | tests/test_query_sync.py | 60 | def test_query_sync_loads_saved_url(query_app, params): | CODE |
| LOW | tests/test_query_sync.py | 74 | def test_query_sync_preserves_disabled_duplicate_on_url_edit(query_app, second_value): | CODE |
| LOW | tests/test_query_sync.py | 94 | def test_query_sync_does_not_rewrite_while_typing(query_app): | CODE |
| LOW | tests/test_query_sync.py | 107 | def test_query_sync_follows_table_edits(query_app): | CODE |
| LOW | tests/test_query_sync.py | 156 | def test_query_sync_survives_save_reload(query_app, tmp_path): | CODE |
| LOW | tests/test_query_sync.py | 178 | def test_query_sync_preserves_variables_and_reserved_characters(query_app): | CODE |
| LOW | tests/test_body_completion_options.py | 16 | def test_body_completion_follows_substitution_option(body_type, snap_compare, tmp_path): | CODE |
| LOW | tests/test_environment_palette.py | 61 | def test_switch_environment_restarts_watcher(tmp_path): | CODE |
| LOW | tests/test_files.py | 44 | def test_is_valid_filename_with_none(): | CODE |
| LOW | tests/test_files.py | 57 | def test_is_valid_filename_os_specific(os_specific_filename, expected): | CODE |
| LOW | tests/test_ssl.py | 146 | def assert_client_certificate(response): | CODE |
| LOW | tests/test_ssl.py | 159 | def test_client_certificate_with_custom_ca( | CODE |
| LOW | tests/test_ssl.py | 179 | def test_custom_ca_without_client_certificate(tmp_path, certificates, tls_server): | CODE |
| LOW | tests/test_ssl.py | 185 | def test_client_certificate_with_verification_disabled(tmp_path, certificates, tls_server): | CODE |
| LOW | tests/test_ssl.py | 197 | def test_client_certificate_with_environment_ca( | CODE |
| LOW | tests/test_ssl.py | 210 | def test_untrusted_server_is_rejected(tmp_path, tls_server, monkeypatch): | CODE |
| LOW | tests/test_ssl.py | 218 | def test_encrypted_combined_certificate_with_environment_ca( | CODE |
| LOW | tests/test_ssl.py | 233 | def test_custom_ca_still_checks_hostname(tmp_path, certificates, tls_server): | CODE |
| LOW | tests/test_variables_editor.py | 27 | def test_add_first_variable_and_replace_duplicate_name(app): | CODE |
| LOW | tests/test_variables_editor.py | 60 | def test_secret_edit_cancel_copy_and_save_use_real_value(app): | CODE |
| LOW | tests/test_variables_editor.py | 93 | def test_invalid_name_keeps_the_draft_without_adding_a_row(app): | CODE |
| LOW | tests/test_variables_editor.py | 107 | def test_reload_updates_filtered_table_and_keeps_an_edit_draft(app): | CODE |
| LOW | tests/test_variables_editor.py | 132 | def test_undo_preserves_type_and_survives_reopening(app): | CODE |
| LOW | tests/test_variables_editor.py | 148 | def test_revert_uses_the_current_environment_file(app, tmp_path): | CODE |
| LOW | tests/test_variables_editor.py | 168 | def test_switching_rows_keeps_the_new_row_in_edit_mode(app): | CODE |
| 170 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | src/posting/app.py | 965 | except NoMatches: | CODE |
| HIGH | src/posting/app.py | 1413 | except NoMatches: | CODE |
| HIGH | src/posting/app.py | 659 | except NoMatches: | CODE |
| HIGH | src/posting/app.py | 667 | except Exception: | CODE |
| HIGH | src/posting/__main__.py | 28 | except OSError: | CODE |
| HIGH | src/posting/__main__.py | 39 | except OSError: | CODE |
| HIGH | src/posting/widgets/datatable.py | 216 | except CellDoesNotExist: | CODE |
| HIGH | src/posting/widgets/datatable.py | 224 | except CellDoesNotExist: | CODE |
| HIGH | src/posting/widgets/response/response_area.py | 119 | except json.JSONDecodeError: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/posting/variables.py | 1 | CODE | |
| LOW | src/posting/method_styles.py | 10 | CODE | |
| LOW | src/posting/__init__.py | 3 | CODE | |
| LOW | src/posting/__init__.py | 10 | CODE | |
| LOW | src/posting/__init__.py | 10 | CODE | |
| LOW | src/posting/__init__.py | 10 | CODE | |
| LOW | src/posting/__init__.py | 10 | CODE | |
| LOW | src/posting/__init__.py | 10 | CODE | |
| LOW | src/posting/__init__.py | 10 | CODE | |
| LOW | src/posting/__init__.py | 10 | CODE | |
| LOW | src/posting/__init__.py | 10 | CODE | |
| LOW | src/posting/__init__.py | 10 | CODE | |
| LOW | src/posting/__init__.py | 21 | CODE | |
| LOW | src/posting/yaml.py | 1 | CODE | |
| LOW | src/posting/yaml.py | 1 | CODE | |
| LOW | src/posting/yaml.py | 5 | CODE | |
| LOW | src/posting/yaml.py | 7 | CODE | |
| LOW | src/posting/tuple_to_multidict.py | 1 | CODE | |
| LOW | src/posting/environments.py | 9 | CODE | |
| LOW | src/posting/collection.py | 1 | CODE | |
| LOW | src/posting/scripts.py | 1 | CODE | |
| LOW | src/posting/save_request.py | 1 | CODE | |
| LOW | src/posting/commands.py | 12 | CODE | |
| LOW | src/posting/widgets/load_env_file_dialog.py | 3 | CODE | |
| LOW | src/posting/widgets/load_env_file_dialog.py | 22 | CODE | |
| LOW | src/posting/widgets/datatable.py | 12 | CODE | |
| LOW | src/posting/widgets/variables_editor.py | 1 | CODE | |
| LOW | src/posting/widgets/collection/new_request_modal.py | 18 | CODE | |
| LOW | src/posting/widgets/response/script_output.py | 9 | CODE | |
| LOW | src/posting/widgets/request/request_auth.py | 7 | CODE | |
| LOW | src/posting/widgets/request/request_editor.py | 2 | CODE | |
| LOW | src/posting/widgets/request/request_editor.py | 3 | CODE | |
| LOW | src/posting/widgets/request/request_editor.py | 4 | CODE | |
| LOW | src/posting/widgets/request/request_editor.py | 19 | CODE | |
| LOW | src/posting/widgets/request/request_editor.py | 21 | CODE | |
| LOW | src/posting/widgets/request/request_editor.py | 26 | CODE | |
| LOW | src/posting/importing/open_api.py | 1 | CODE | |
| LOW | src/posting/importing/postman.py | 1 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | src/posting/themes.py | 335 | except Exception as e: | CODE |
| LOW⚡ | src/posting/themes.py | 345 | except Exception as e: | CODE |
| LOW⚡ | src/posting/themes.py | 350 | except Exception: | CODE |
| LOW | src/posting/user_host.py | 14 | except Exception: | CODE |
| MEDIUM | src/posting/user_host.py | 9 | def get_user_host_string() -> Text: | CODE |
| LOW | src/posting/collection.py | 542 | except Exception as e: | CODE |
| MEDIUM | src/posting/app.py | 370 | def send_request(self) -> None: | CODE |
| LOW | src/posting/app.py | 315 | except Exception as e: | CODE |
| LOW | src/posting/app.py | 353 | except Exception as e: | CODE |
| LOW | src/posting/app.py | 415 | except Exception: | CODE |
| LOW | src/posting/app.py | 462 | except Exception: | CODE |
| LOW | src/posting/app.py | 496 | except Exception: | CODE |
| LOW | src/posting/app.py | 525 | except Exception as e: | CODE |
| LOW | src/posting/app.py | 667 | except Exception: | CODE |
| LOW | src/posting/app.py | 704 | except Exception: | CODE |
| LOW | src/posting/app.py | 1081 | except Exception: | CODE |
| LOW | src/posting/app.py | 1491 | except Exception as e: | CODE |
| LOW | src/posting/app.py | 1499 | except Exception as e: | CODE |
| LOW | src/posting/app.py | 1601 | except Exception: | CODE |
| LOW | src/posting/app.py | 1631 | except Exception as exc: | CODE |
| LOW | src/posting/app.py | 1674 | except Exception as exc: | CODE |
| LOW | src/posting/urls.py | 37 | except Exception: | CODE |
| LOW | src/posting/urls.py | 65 | except Exception: | CODE |
| LOW | src/posting/urls.py | 101 | except Exception: | CODE |
| LOW | src/posting/urls.py | 113 | except Exception: | CODE |
| LOW | src/posting/__main__.py | 161 | except Exception: | CODE |
| MEDIUM | src/posting/__main__.py | 162 | console.print("An error occurred during the import process.", style="red") | CODE |
| LOW | src/posting/history.py | 96 | except Exception: | CODE |
| LOW | src/posting/widgets/collection/browser.py | 422 | except Exception as e: | CODE |
| LOW | src/posting/widgets/collection/browser.py | 526 | except Exception: | CODE |
| LOW | src/posting/importing/curl.py | 233 | except Exception: | CODE |
| LOW | src/posting/importing/curl.py | 254 | except Exception: | CODE |
| LOW | src/posting/importing/curl.py | 262 | except Exception: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/posting/variables.py | 73 | def update_variables(new_variables: dict[str, object]) -> None: | CODE |
| LOW | src/posting/__init__.py | 24 | __all__ = [ | CODE |
| LOW | src/posting/yaml.py | 23 | __all__ = ["load", "dump", "Loader", "Dumper"] | CODE |
| LOW | src/posting/highlighters.py | 79 | def set_path_params(self, params: dict[str, str]) -> None: | CODE |
| LOW | src/posting/scripts.py | 59 | def set_variable(self, name: str, value: object) -> None: | CODE |
| LOW | src/posting/widgets/text_area.py | 116 | def update_language(self, event: Select.Changed) -> None: | CODE |
| LOW | src/posting/widgets/text_area.py | 124 | def update_soft_wrap(self, event: Checkbox.Changed) -> None: | CODE |
| LOW⚡ | src/posting/widgets/text_area.py | 635 | def update_selection(self, event: TextArea.SelectionChanged) -> None: | CODE |
| LOW⚡ | src/posting/widgets/text_area.py | 639 | def update_visual_mode(self, event: ReadOnlyTextArea.VisualModeToggled) -> None: | CODE |
| LOW⚡ | src/posting/widgets/text_area.py | 643 | def update_language(self, event: TextAreaFooter.LanguageChanged) -> None: | CODE |
| LOW⚡ | src/posting/widgets/text_area.py | 647 | def update_soft_wrap(self, event: TextAreaFooter.SoftWrapChanged) -> None: | CODE |
| LOW | src/posting/widgets/collection/browser.py | 645 | def update_currently_open_node(self, request_model: RequestModel) -> None: | CODE |
| LOW | src/posting/widgets/collection/history.py | 159 | def update_detail(self) -> None: | STRING |
| LOW⚡ | src/posting/widgets/response/script_output.py | 50 | def set_setup_status(self, status: ScriptStatus) -> None: | STRING |
| LOW⚡ | src/posting/widgets/response/script_output.py | 55 | def set_request_status(self, status: ScriptStatus) -> None: | CODE |
| LOW⚡ | src/posting/widgets/response/script_output.py | 60 | def set_response_status(self, status: ScriptStatus) -> None: | CODE |
| LOW⚡ | src/posting/widgets/response/script_output.py | 65 | def set_label_status(self, label_id: str, status: ScriptStatus) -> None: | CODE |
| LOW | src/posting/widgets/request/request_auth.py | 47 | def set_values(self, username: str, password: str) -> None: | STRING |
| LOW | src/posting/widgets/request/request_auth.py | 101 | def set_values(self, token: str) -> None: | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_text_area_completion.py | 26 | CODE | |
| LOW | tests/test_text_area_completion.py | 29 | CODE | |
| LOW | src/posting/themes.py | 314 | CODE | |
| LOW | src/posting/help_screen.py | 127 | CODE | |
| LOW | src/posting/collection.py | 218 | CODE | |
| LOW | src/posting/collection.py | 500 | CODE | |
| LOW | src/posting/app.py | 287 | CODE | |
| LOW | src/posting/app.py | 635 | CODE | |
| LOW | src/posting/app.py | 745 | CODE | |
| LOW | src/posting/app.py | 1172 | CODE | |
| LOW | src/posting/app.py | 1474 | CODE | |
| LOW | src/posting/app.py | 1180 | CODE | |
| LOW | src/posting/__main__.py | 108 | CODE | |
| LOW | src/posting/history.py | 55 | CODE | |
| LOW | src/posting/widgets/key_value.py | 87 | CODE | |
| LOW | src/posting/widgets/text_area.py | 264 | CODE | |
| LOW | src/posting/widgets/response/response_trace.py | 50 | CODE | |
| LOW | src/posting/widgets/response/script_output.py | 65 | CODE | |
| LOW | src/posting/widgets/response/response_area.py | 179 | CODE | |
| LOW | src/posting/importing/curl.py | 27 | CODE | |
| LOW | src/posting/importing/curl.py | 196 | CODE | |
| LOW | src/posting/importing/open_api.py | 382 | CODE | |
| LOW | src/posting/importing/open_api.py | 360 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | src/posting/variables.py | 135 | Extract the variable name from a variable reference. Args: variable_text: The text containing the vari | STRING |
| HIGH | src/posting/scripts.py | 124 | Execute a Python script from the given path and extract a specified function. Uses caching to prevent multiple | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/test_curl_export.py | 38 | body=RequestBody(content='{"name": "John Doe", "email": "john@example.com"}'), | CODE |
| LOW⚡ | tests/test_curl_export.py | 41 | expected = 'curl \\\n -X POST \\\n -d \'{"name": "John Doe", "email": "john@example.com"}\' \\\n \'https://exampl | CODE |
| LOW | tests/test_curl_export.py | 163 | FormItem(name="name", value="John Doe"), | CODE |
| LOW | tests/test_curl_export.py | 206 | body=RequestBody(content='{"name": "John Doe", "email": "john@example.com"}'), | CODE |
| LOW | …-collections/jsonplaceholder/users/create.posting.yaml | 8 | "name": "John Doe", | CODE |
| LOW | docs/guide/index.md | 141 | "name": "John Doe", | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/posting/files.py | 11 | # Check if the filename is empty or None | COMMENT |
| LOW | src/posting/files.py | 19 | # Check if the filename is too long (255 characters is a common limit) | COMMENT |
| LOW | src/posting/scripts.py | 143 | # Check if the script is within the collection root | COMMENT |
| LOW | src/posting/widgets/collection/browser.py | 522 | # Check if the scheme and netloc are present | COMMENT |
| LOW | src/posting/widgets/collection/new_request_modal.py | 278 | # Check if a request with the same name already exists in the collection. | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | src/posting/__main__.py | 149 | # Create the environment file in the collection directory. | COMMENT |
| MEDIUM | src/posting/importing/curl.py | 47 | # Define the arguments to parse | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/posting/widgets/confirmation.py | 39 | CODE | |
| LOW | src/posting/widgets/variable_autocomplete.py | 19 | CODE | |
| LOW | src/posting/widgets/text_area.py | 422 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | …e-importable-collections/Fixer.postman_collection.json | 5 | "description": "Powered by 15+ exchange rate data sources, the Fixer API is capable of delivering real-time exchange r | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | …e-importable-collections/Fixer.postman_collection.json | 5 | "description": "Powered by 15+ exchange rate data sources, the Fixer API is capable of delivering real-time exchange r | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/posting/widgets/confirmation.py | 83 | # It's enough to just call focus_next here as there are only two buttons. | STRING |