AI Slop Code RIsk Monitor

feder-cr/invisible_playwright_mcp

Playwright MCP server undetected by anti-bots and captchas: AI agent browses the web on anti-detect stealth Firefox, Python, undetected browser automation, scraping, computer use.

37.9 High pattern signal View on GitHub

Maintenance and Governance Review

This report summarizes scanner evidence for feder-cr/invisible_playwright_mcp, a Python project with 2,746 GitHub stars. SynthScan examined 64,383 lines of code across 326 source files, recording 1450 pattern matches distributed across 13 syntactic categories. The legacy adjusted pattern signal is 37.9 (High 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.

37.9
Adjusted Signal
37.9
Raw Pattern Score
100%
Time Factor
2026-10-11
Last Push
2.7K
Stars
Python
Language
64.4K
Lines of Code
326
Files
1.4K
Pattern Hits
2026-10-12
Scan Date
0.56
HC Hit Rate

Risk Review · v3

Use each vector to guide manual verification of the underlying findings.

Cognitive Ownership Risk 56.3/100 · HIGH

Can maintainers explain intent, assumptions, and trade-offs? 1052 finding(s).

Hallucinated Dependency & Supply Chain Risk 56.4/100 · HIGH

Are imports declared and package/API names verified? 299 finding(s).

Agent Over-Engineering Ratio 60.9/100 · HIGH

Are wrappers, guards, and repeated structures necessary? 1004 finding(s).

PR Review Velocity Impact 85.9/100 · CRITICAL

Which changes need focused human review? 1450 finding(s).

What These Metrics Mean

Adjusted Signal
Legacy pattern score normalized per 1,000 scanned lines and multiplied by the repository-level time factor. It is not an estimate of AI authorship.
Raw Pattern Score
Sum of severity- and context-weighted pattern findings before applying the time factor.
Time Factor
A coarse multiplier based on repository last-push metadata. It does not identify when individual code was written.
Pattern Hits
Count of configured pattern findings. Review each location and surrounding code before acting.
HC Hit Rate
High- and critical-severity findings per scanned file. Severity is a configured detector weight, not proof of a vulnerability or authorship.
Lines / Files
Scan coverage denominators used by the legacy normalized score.

Pattern-Signal History

Run additional scans to build a history of the legacy pattern signal. Score changes are not a measure of AI adoption or code quality.

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

Severity Breakdown

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.

CRITICAL 0HIGH 184MEDIUM 75LOW 1191

Directory Score Breakdown

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.

Pattern Findings

The scanner identified 1450 distinct pattern matches across 13 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.

Cross-Language Confusion176 hits · 956 pts
SeverityFileLineSnippetContext
HIGHtests/test_the_browser_workspace.py286 assert "const watched = () => stage.pinned || stage.focus;" in code, (CODE
HIGH⚡tests/test_a_screen_says_what_it_is_showing.py38 this.attrs = {}; this.hidden = false; this.title = ''; this._text = null;CODE
HIGH⚡tests/test_a_screen_says_what_it_is_showing.py46 appendChild(n){ this.kids.push(n); this._text = null; return n; }CODE
HIGH⚡tests/test_a_screen_says_what_it_is_showing.py46 appendChild(n){ this.kids.push(n); this._text = null; return n; }CODE
HIGH⚡tests/test_a_screen_says_what_it_is_showing.py54 return null; };CODE
HIGH⚡tests/test_a_screen_says_what_it_is_showing.py60 if(c) e.className = c; if(x != null) e.textContent = x; return e; };CODE
HIGH⚡tests/test_a_screen_says_what_it_is_showing.py61const stage = {fleet: [], focus: 'b-two', pinned: null, grid: 1, turn: 0};CODE
HIGH⚡tests/test_a_screen_says_what_it_is_showing.py62const watched = () => stage.pinned || stage.focus;CODE
HIGHtests/test_a_screen_says_what_it_is_showing.py125 out.push({w, h, arn: Number(box.style.getPropertyValue('--arn')),CODE
HIGHtests/test_a_screen_says_what_it_is_showing.py168 kids: veil.kids.map(k => k.className || k.tag)};CODE
HIGHtests/test_a_screen_says_what_it_is_showing.py311 veilId: veil ? veil.id : null}));CODE
HIGHtests/test_a_screen_says_what_it_is_showing.py345 out[id] = dot ? dot.title : null;CODE
HIGH⚡tests/test_web_service.py323 "let turnsEnded = 0, busyNow = false, queued = null, vanished = false;",CODE
HIGH⚡tests/test_web_service.py327 "function setQueued(t){ queued = t || null; }",CODE
HIGH⚡tests/test_web_service.py327 "function setQueued(t){ queued = t || null; }",CODE
HIGH⚡tests/test_web_service.py328 "function orphan(kind, text){ said.push([kind, text]); }",CODE
HIGH⚡tests/test_web_service.py330 "async function door(path, init){ posted.push(JSON.parse(init.body).text);",CODE
HIGHtests/test_web_service.py1083 `setQueued(null)` - so somebody who had typed a follow-up while the agentSTRING
HIGH⚡tests/test_every_control_says_what_it_does.py113 " listeners:[], addEventListener(k, fn){ this.listeners.push([k, fn]); },",CODE
HIGH⚡tests/test_every_control_says_what_it_does.py117 "globalThis.orphan = (k, t) => said.push(t);",CODE
HIGH⚡tests/test_every_control_says_what_it_does.py118 "globalThis.ask = (path) => { asked.push(path); };",CODE
HIGH⚡tests/test_every_control_says_what_it_does.py119 "globalThis.queued = null;",CODE
HIGH⚡tests/test_every_control_says_what_it_does.py211 "let handler = null, sent = [];",CODE
HIGH⚡tests/test_every_control_says_what_it_does.py214 " dispatchEvent(e){ this.events.push(e.type); }, focus(){ this.focused = true; }};",CODE
HIGH⚡tests/test_every_control_says_what_it_does.py216 "globalThis.send = (t) => sent.push(t);",CODE
HIGH⚡tests/test_every_control_says_what_it_does.py219 " closest: sel => sel === '.eg' ? eg : null};",CODE
HIGH⚡tests/test_every_control_says_what_it_does.py221 "const other = {closest: () => null};",CODE
HIGH⚡tests/test_every_control_says_what_it_does.py249 " appendChild(k){ this.kids.push(k); }, append(...k){ this.kids.push(...k); },",CODE
HIGH⚡tests/test_every_control_says_what_it_does.py258 "let answer = null;",CODE
HIGH⚡tests/test_every_control_says_what_it_does.py265 " out.down = box.kids.map(k => k.t || k.cls);",CODE
HIGH⚡tests/test_every_control_says_what_it_does.py267 " out.empty = box.kids.map(k => k.t || k.cls);",CODE
HIGHtests/test_every_control_says_what_it_does.py70 "globalThis.busyNow = false; globalThis.queued = null; paint(); seen.idle = go.dataset.mode;",CODE
HIGHtests/test_every_control_says_what_it_does.py321 "let jump = null, said = [];",CODE
HIGHtests/test_every_control_says_what_it_does.py322 "const btn = {hidden:false, set textContent(v){ said.push(v); },",CODE
HIGHtests/test_ui_drive.py188 window.clicked.push(index + 1);CODE
HIGHtests/test_ui_drive.py728 "() => { return document.querySelector('#late') !== null; }",CODE
HIGHtests/test_ui_drive.py753 " return ids.filter(function (id) { return document.getElementById(id) !== null; }).length; }"CODE
HIGH⚡tests/test_the_answer_pane_draws_markdown.py45 constructor(tag){ this.tag = tag; this.kids = []; this.className = ''; this._text = null; }CODE
HIGH⚡tests/test_the_answer_pane_draws_markdown.py51 if(this._text != null){ this.kids.push(new Txt(this._text)); this._text = null; }CODE
HIGH⚡tests/test_the_answer_pane_draws_markdown.py51 if(this._text != null){ this.kids.push(new Txt(this._text)); this._text = null; }CODE
HIGH⚡tests/test_the_answer_pane_draws_markdown.py52 this.kids.push(n); return n;CODE
HIGH⚡tests/test_the_answer_pane_draws_markdown.py59 get(){ return undefined; },CODE
HIGH⚡tests/test_the_answer_pane_draws_markdown.py62 createElement: t => { MADE.push(t); return new Node(t); },CODE
HIGHtests/test_the_transcript_follows_the_agent.py84const $ = id => id === 'jump' ? jump : null;CODE
HIGHtests/test_the_transcript_follows_the_agent.py86let turn = { kids: [], appendChild(n){ this.kids.push(n); } };CODE
HIGHtests/test_the_old_name_hands_over_its_data.py281 " getItem(k){ return k in store ? store[k] : null; },",CODE
HIGHtests/test_the_old_name_hands_over_its_data.py311 " getItem(k){ return k in store ? store[k] : null; },",CODE
HIGHtests/test_the_stage_of_screens.py43const watched = () => stage.pinned || stage.focus;CODE
HIGHtests/test_the_stage_of_screens.py79 shots.push({w, h, bw, bh, cut, drawn: Math.round(drawn), above,CODE
HIGHtests/test_the_stage_of_screens.py175 " answers.push(stage.grid);"CODE
HIGHtests/test_the_stage_of_screens.py277 "const stage = {fleet: %s, focus: 'main', pinned: null, grid: 2, turn: 0};\n"CODE
HIGHtests/test_the_stage_of_screens.py325 "const watched = () => stage.pinned || stage.focus;\n"CODE
HIGH⚡tests/test_the_stage_of_screens.py337 "\nprocess.stdout.write(JSON.stringify({big: box.dataset.big || null,"CODE
HIGH⚡tests/test_the_stage_of_screens.py337 "\nprocess.stdout.write(JSON.stringify({big: box.dataset.big || null,"CODE
HIGHtests/test_the_split_between_the_panes.py38 getItem: k => (k in KEPT ? KEPT[k] : null),CODE
HIGH⚡tests/test_the_session_column.py957 "let asked = [], drawn = 0, made = null, stopped = 0;",CODE
HIGH⚡tests/test_the_session_column.py960 "globalThis.ask = async (path, body) => { asked.push(body); ",CODE
HIGH⚡tests/test_the_session_column.py966 "const btn = {dataset:{}, replaced: null, replaceWith(n){ this.replaced = n; }};",CODE
HIGH⚡tests/test_the_session_column.py967 "let onkey = null;",CODE
HIGHtests/test_the_session_column.py581 assert "STORE + 'queued.' + (who || here)" in code, (CODE
116 more matches not shown…
Hyper-Verbose Identifiers905 hits · 907 pts
SeverityFileLineSnippetContext
LOWtests/test_engine.py46def test_a_download_in_flight_is_described_with_its_progress_and_runs_once():CODE
LOWtests/test_engine.py64def test_settle_answers_as_soon_as_the_download_says_what_it_is():CODE
LOWtests/test_engine.py80def test_a_given_binary_is_ready_at_once_and_never_downloaded():CODE
LOWtests/test_engine.py91def test_a_failed_download_is_said_with_its_reason_and_can_be_retried():CODE
LOWtests/test_engine.py110def test_an_unknown_total_is_described_in_bytes_so_far():CODE
LOWtests/test_engine.py128def test_abandon_stops_a_download_whose_loop_swallows_exceptions():CODE
LOWtests/test_engine.py155def test_run_in_the_calling_thread_drives_the_listener_phase_by_phase():CODE
LOWtests/test_engine.py173def test_describe_before_anything_started_asks_to_call_again():CODE
LOWtests/test_engine.py179def test_the_first_instant_of_a_download_reads_as_starting_not_as_zero():CODE
LOWtests/test_the_browser_workspace.py123async def test_the_workspace_is_read_from_the_server_like_any_other_client():CODE
LOWtests/test_the_browser_workspace.py140async def test_the_workspace_asks_the_one_question_that_starts_nothing():CODE
LOWtests/test_the_browser_workspace.py178async def test_an_unreadable_answer_says_so_instead_of_drawing_an_empty_room():CODE
LOWtests/test_the_browser_workspace.py204async def test_a_pane_asks_for_its_own_browser_and_not_for_the_focused_one():CODE
LOWtests/test_the_browser_workspace.py229async def test_the_live_pane_still_asks_for_the_focused_browser_when_none_is_named():CODE
LOWtests/test_the_browser_workspace.py243async def test_the_page_cannot_open_close_or_redirect_a_browser():CODE
LOWtests/test_the_browser_workspace.py265async def test_looking_at_a_pane_tells_the_agent_nothing():CODE
LOWtests/test_the_browser_workspace.py293def test_the_workspace_has_no_strip_and_no_pump_of_its_own():CODE
LOWtests/test_the_browser_workspace.py331def test_the_page_declares_no_identifier_twice():CODE
LOWtests/test_the_browser_workspace.py373def test_no_top_level_declaration_uses_a_name_declared_later():CODE
LOWtests/test_the_browser_workspace.py429def test_every_handler_the_page_wires_up_exists():CODE
LOWtests/test_the_browser_workspace.py464def test_the_answer_measure_is_inside_the_range_every_source_agrees_on():CODE
LOWtests/conftest.py211def _the_server_remembers_nothing_from_the_last_test():CODE
LOWtests/test_readme_offers_both.py89def test_both_ways_in_are_offered():CODE
LOWtests/test_readme_offers_both.py120def test_the_offer_comes_within_the_first_screen():CODE
LOWtests/test_readme_offers_both.py140def test_the_check_fails_on_the_pages_as_they_used_to_be():CODE
LOWtests/test_readme_offers_both.py166def test_a_comment_inside_a_fence_is_not_a_heading():CODE
LOWtests/test_readme_offers_both.py198def test_the_two_ways_are_offered_as_one_choice():CODE
LOWtests/test_readme_offers_both.py213def test_the_offer_says_what_each_one_costs_the_reader():CODE
LOWtests/test_readme_offers_both.py231def test_no_tool_name_that_does_not_exist():CODE
LOWtests/test_readme_offers_both.py248def test_no_hand_written_count_of_tools():CODE
LOWtests/test_one_place_reads_a_saved_file.py32def test_both_halves_read_through_the_one_reader(tmp_path, monkeypatch):CODE
LOWtests/test_one_place_reads_a_saved_file.py53def test_both_halves_delete_through_the_one_eraser(tmp_path, monkeypatch):CODE
LOWtests/test_one_place_reads_a_saved_file.py76def test_erasing_something_that_is_not_there_is_not_a_failure(tmp_path, monkeypatch):CODE
LOWtests/test_one_place_reads_a_saved_file.py90def test_a_file_that_will_not_parse_reads_as_nothing_saved(tmp_path, monkeypatch):CODE
LOWtests/test_one_place_reads_a_saved_file.py113def test_the_saved_session_is_json_an_outside_reader_can_use(tmp_path, monkeypatch):CODE
LOW⚡tests/test_the_suite_reads_no_real_session.py50def test_importing_a_test_module_cannot_reach_the_real_directory():CODE
LOW⚡tests/test_the_suite_reads_no_real_session.py58def test_and_neither_can_a_test_body():CODE
LOW⚡tests/test_the_suite_reads_no_real_session.py65def test_the_real_directory_is_named_after_the_package():CODE
LOWtests/test_the_suite_reads_no_real_session.py92def test_the_server_starts_each_test_holding_nothing():CODE
LOWtests/test_the_suite_reads_no_real_session.py108def test_the_conftest_imports_nothing_the_light_jobs_do_not_have():CODE
LOWtests/test_the_suite_reads_no_real_session.py145def test_a_run_that_did_not_ask_for_an_engine_cannot_reach_one():CODE
LOWtests/test_the_suite_reads_no_real_session.py220def test_the_guard_arms_exactly_when_the_engine_tests_are_deselected():CODE
LOWtests/test_the_suite_reads_no_real_session.py256def test_only_one_place_knows_where_the_interface_is_stopped():CODE
LOWtests/test_the_suite_reads_no_real_session.py309def test_the_brake_module_still_carries_all_three_defences():CODE
LOW⚡tests/test_agent.py67def test_answer_of_falls_back_for_non_text_content():CODE
LOW⚡tests/test_agent.py77def test_mcp_tools_to_openai_shape():CODE
LOW⚡tests/test_agent.py83async def test_run_task_drives_tools_then_returns_final_answer():CODE
LOWtests/test_the_interface_reaches_a_real_server.py88async def test_the_idle_pane_is_answered_by_a_server_that_really_refused(live):CODE
LOWtests/test_the_interface_reaches_a_real_server.py133async def test_the_workspace_is_answered_by_the_server_and_not_by_the_interface(live):CODE
LOWtests/test_the_interface_reaches_a_real_server.py177async def test_the_client_really_is_a_separate_process(live):CODE
LOWtests/test_real_cli.py21async def test_the_loop_reads_a_data_url_heading():CODE
LOWtests/test_llm.py5def test_key_arg_wins_then_env_then_error():CODE
LOWtests/test_llm.py12def test_model_arg_env_default():CODE
LOWtests/test_a_screen_says_what_it_is_showing.py108def test_the_frame_takes_the_shape_of_the_window_it_shows():CODE
LOWtests/test_a_screen_says_what_it_is_showing.py144def test_the_four_states_are_four_different_pictures():STRING
LOWtests/test_a_screen_says_what_it_is_showing.py191def test_a_screen_says_how_old_its_picture_is():STRING
LOWtests/test_a_screen_says_what_it_is_showing.py227def test_a_screen_is_built_as_a_frame_with_its_name_on_it():STRING
LOWtests/test_a_screen_says_what_it_is_showing.py254def test_an_empty_stage_says_what_to_do_about_being_empty():STRING
LOWtests/test_a_screen_says_what_it_is_showing.py292def test_a_screen_is_named_by_its_action_and_described_by_its_state():STRING
LOWtests/test_a_screen_says_what_it_is_showing.py322def test_the_dot_marks_the_browser_the_agent_is_actually_working_in():STRING
845 more matches not shown…
Decorative Section Separators56 hits · 231 pts
SeverityFileLineSnippetContext
MEDIUM⚡tests/test_cli_surface.py99# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_cli_surface.py101# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_cli_surface.py186# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_cli_surface.py188# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_cli_surface.py316# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_cli_surface.py318# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_cli_surface.py352# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_cli_surface.py354# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_web_service.py88# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_web_service.py90# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_web_service.py198# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_web_service.py200# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_web_service.py404# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_web_service.py406# --------------------------------------------------------------------------COMMENT
MEDIUMtests/test_web_service.py521# --------------------------------------------------------------------------COMMENT
MEDIUMtests/test_web_service.py523# --------------------------------------------------------------------------COMMENT
MEDIUMtests/test_web_service.py1051# --------------------------------------------------------------------------COMMENT
MEDIUMtests/test_web_service.py1053# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_openrouter_only.py165# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_openrouter_only.py167# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_openrouter_only.py259# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_openrouter_only.py261# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_openrouter_only.py316# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_openrouter_only.py318# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_openrouter_only.py359# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_openrouter_only.py361# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_openrouter_only.py399# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_openrouter_only.py406# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_agent_loop.py228# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_agent_loop.py230# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_agent_loop.py379# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_agent_loop.py381# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_agent_loop.py436# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_agent_loop.py438# --------------------------------------------------------------------------COMMENT
MEDIUMtests/test_agent_loop.py74# --------------------------------------------------------------------------COMMENT
MEDIUMtests/test_agent_loop.py76# --------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_key_isolation.py54# ---------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_key_isolation.py56# ---------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_key_isolation.py105# ---------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_key_isolation.py107# ---------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_key_isolation.py149# ── what the mutation test asked for ────────────────────────────────────────COMMENT
MEDIUM⚡tests/test_key_isolation.py227# ---------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_key_isolation.py229# ---------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_key_isolation.py309# ---------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_key_isolation.py311# ---------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_key_isolation.py491# ---------------------------------------------------------------------------COMMENT
MEDIUM⚡tests/test_key_isolation.py493# ---------------------------------------------------------------------------COMMENT
MEDIUMtests/test_key_isolation.py341# ---------------------------------------------------------------------------COMMENT
MEDIUMtests/test_key_isolation.py343# ---------------------------------------------------------------------------COMMENT
MEDIUMtests/mcp_server/test_no_interaction_by_script.py231# ── the other half: what the model can SEE ──────────────────────────────────COMMENT
MEDIUM⚡tests/mcp_server/test_who_is_browsing.py39# ── nothing said ────────────────────────────────────────────────────────────COMMENT
MEDIUM⚡tests/mcp_server/test_who_is_browsing.py60# ── a seed, no profile ──────────────────────────────────────────────────────COMMENT
MEDIUM⚡tests/mcp_server/test_who_is_browsing.py88# ── a profile ───────────────────────────────────────────────────────────────COMMENT
MEDIUM.github/workflows/publish-wiki.yml1# ─────────────────────────────────────────────────────────────────────────────COMMENT
MEDIUMsrc/invisible_playwright_mcp/mcp/actions.py959# ── files, picked the way a person picks them ──────────────────────────────COMMENT
MEDIUMsrc/invisible_playwright_mcp/mcp/actions.py1360# ── evaluate, and the one thing it must not be used for ─────────────────────COMMENT
Unused Imports122 hits · 114 pts
SeverityFileLineSnippetContext
LOWtests/test_engine.py7CODE
LOWtests/test_the_browser_workspace.py14CODE
LOWtests/conftest.py41CODE
LOWtests/test_readme_offers_both.py21CODE
LOWtests/test_one_place_reads_a_saved_file.py24CODE
LOWtests/test_the_suite_reads_no_real_session.py25CODE
LOWtests/test_the_interface_reaches_a_real_server.py42CODE
LOWtests/_sessions.py21CODE
LOWtests/test_a_screen_says_what_it_is_showing.py17CODE
LOW…test_the_extension_archive_holds_only_the_extension.py10CODE
LOWtests/test_a_failed_selector_says_what_to_do.py25CODE
LOWtests/test_cli_surface.py14CODE
LOWtests/test_cli_surface.py23CODE
LOWtests/test_publishing_surfaces.py51CODE
LOWtests/test_the_transcript_is_what_was_said.py20CODE
LOWtests/_cli_brake.py28CODE
LOWtests/test_no_tracked_file_carries_a_control_byte.py21CODE
LOW…s/test_the_product_surface_is_what_the_product_uses.py68CODE
LOWtests/test_one_conversation_one_server.py28CODE
LOWtests/_loop.py18CODE
LOWtests/test_web_service.py13CODE
LOWtests/test_every_control_says_what_it_does.py16CODE
LOWtests/test_a_workflow_runs_on_something_that_happens.py32CODE
LOWtests/test_openrouter_only.py23CODE
LOWtests/test_engine_first.py13CODE
LOWtests/test_ui_drive.py34CODE
LOWtests/test_one_reader_of_a_tool_result.py32CODE
LOWtests/test_the_answer_pane_draws_markdown.py25CODE
LOWtests/test_the_gate_says_which_tree_it_judged.py30CODE
LOWtests/test_the_prompt_says_each_thing_once.py21CODE
LOWtests/test_the_wiki_samples_name_real_fields.py22CODE
LOWtests/test_a_rule_is_written_where_it_is_applied.py21CODE
LOWtests/test_the_floor_carries_what_the_tools_need.py22CODE
LOWtests/test_the_page_is_assembled_from_its_files.py9CODE
LOWtests/test_the_contrast_floors_are_computed.py29CODE
LOWtests/test_the_bundle_holds_only_the_server.py11CODE
LOWtests/_page.py15CODE
LOWtests/test_agent_loop.py44CODE
LOWtests/test_the_transcript_follows_the_agent.py47CODE
LOWtests/test_every_tool_reads_as_english.py18CODE
LOWtests/test_the_old_name_hands_over_its_data.py22CODE
LOWtests/test_env_file.py23CODE
LOWtests/test_the_codex_plugin_really_installs.py23CODE
LOWtests/test_the_stage_of_screens.py26CODE
LOWtests/test_what_is_imported_is_declared.py28CODE
LOWtests/test_the_page_can_be_read.py16CODE
LOWtests/test_release_pages.py47CODE
LOWtests/test_the_version_describes_the_code.py25CODE
LOWtests/test_the_split_between_the_panes.py16CODE
LOWtests/test_the_suite_declares_asyncio_once.py18CODE
LOWtests/test_the_session_column.py23CODE
LOWtests/test_the_event_stream_wire_format.py21CODE
LOWtests/test_the_plugin_really_installs.py49CODE
LOWtests/test_the_page_meets_the_craft_floor.py13CODE
LOWtests/test_key_isolation.py27CODE
LOWtests/test_version_is_not_taken.py49CODE
LOWtests/test_the_page_tells_the_truth.py8CODE
LOWtests/test_a_reconnection_keeps_what_you_typed.py21CODE
LOWtests/mcp_server/test_addressing.py10CODE
LOWtests/mcp_server/test_no_interaction_by_script.py27CODE
62 more matches not shown…
Over-Commented Block108 hits · 98 pts
SeverityFileLineSnippetContext
LOWpyproject.toml21 "Programming Language :: Python :: 3.12",COMMENT
LOWpyproject.toml41 # url, and both are read off what page.goto() answers. Until 0.13.2 thatCOMMENT
LOWpyproject.toml61 # downloaded into the package's redirected AppData and could not beCOMMENT
LOWpyproject.toml81 #COMMENT
LOWpyproject.toml101 # resize border off the screen and two borders wider than the work area,COMMENT
LOWpyproject.toml121 # faster and needs no second package for CSS selection (lxml wantsCOMMENT
LOWpyproject.toml141 # major this cannot use, `import invisible_playwright_mcp` fails for everybody with aCOMMENT
LOWpyproject.toml161# Italian word list to check the tool descriptions. An import that relies on aCOMMENT
LOWpyproject.toml201testpaths = ["tests"]COMMENT
LOWtests/test_readme_offers_both.py21from __future__ import annotationsCOMMENT
LOWtests/test_publishing_surfaces.py81#: No `.cursor-plugin/plugin.json` since 2026-09-13 night: Cursor's own docs sayCOMMENT
LOWtests/test_publishing_surfaces.py101#: is held identical to the README's by scripts/check_content.py, which scansCOMMENT
LOW…s/test_the_product_surface_is_what_the_product_uses.py181 if isinstance(owner, ast.Name) and owner.id in aliases:COMMENT
LOWtests/test_web_service.py421 assert paths == {"/",COMMENT
LOWtests/test_ui_drive.py241 "done.html": DONE_HTML,COMMENT
LOWtests/test_ui_drive.py441 os.environ,COMMENT
LOWtests/test_ui_drive.py461 # already been paid.COMMENT
LOWtests/test_the_transcript_follows_the_agent.py201 """COMMENT
LOWtests/test_release_pages.py61#: last version that belongs to it: (name, after, through).COMMENT
LOWtests/test_release_pages.py81#: deletion is declared, like the boundary, and checked in the one direction theCOMMENT
LOWtests/test_release_pages.py101COMMENT
LOWtests/test_the_session_column.py121 assert a is b is cCOMMENT
LOWtests/test_the_plugin_really_installs.py61COMMENT
LOWtests/test_key_isolation.py141 """Known-bad is the current code: the same secret under OPENAI_API_KEY isCOMMENT
LOWtests/test_version_is_not_taken.py61COMMENT
LOWtests/mcp_server/test_open_first.py501 assert rows[1]["urls"] == []COMMENT
LOWtests/mcp_server/test_stdio_e2e.py41 sdk = _installed("mcp")COMMENT
LOWtests/mcp_server/test_server_list.py21 # Added in 0.15.0 with the rest of the multi-browser work: a sessionCOMMENT
LOWtests/mcp_server/test_server_list.py41 # navigate` opens the first page by itself.COMMENT
LOWscripts/check_content.py61import tomllibCOMMENT
LOWscripts/check_content.py101PNG_OK = {b"IHDR", b"PLTE", b"IDAT", b"IEND", b"tRNS", b"gAMA", b"cHRM",COMMENT
LOWscripts/check_content.py121#: was skipped, and the gate printed `clean`. The four mutations in `selftest`COMMENT
LOWscripts/check_content.py381#: corrected by hand, and the only reason anybody looked was that a new pageCOMMENT
LOWscripts/check_content.py401#:COMMENT
LOW.github/workflows/publish.yml1name: publishCOMMENT
LOW.github/workflows/publish.yml201COMMENT
LOW.github/workflows/publish-wiki.yml1# ─────────────────────────────────────────────────────────────────────────────COMMENT
LOW.github/workflows/publish-wiki.yml21# and 0.65.0 moved. The wiki was showing the previous month's numbers to anybodyCOMMENT
LOW.github/workflows/ci.yml101 run: |COMMENT
LOW.github/workflows/ci.yml201 python scripts/pack_bundle.py --smithery --output /tmp/bundleCOMMENT
LOWsrc/invisible_playwright_mcp/link.py61 #COMMENT
LOWsrc/invisible_playwright_mcp/link.py261COMMENT
LOWsrc/invisible_playwright_mcp/sessions.py61 # ATTRIBUTE TO OVERWRITE. It was `self._open_link = self._spawn_link`,COMMENT
LOWsrc/invisible_playwright_mcp/sessions.py81 #: conversations at the same instant. That is rare - a page opening, aCOMMENT
LOWsrc/invisible_playwright_mcp/env.py41#: "1" when the process is spawned by a host that opens and closes its browserCOMMENT
LOWsrc/invisible_playwright_mcp/chat.py21#: package - with a comment saying the two had to agree and a test assertingCOMMENT
LOWsrc/invisible_playwright_mcp/chat.py41#: real saved file, not by a test: the developer's own `default.json` heldCOMMENT
LOWsrc/invisible_playwright_mcp/chat.py261 # asking somebody to name a conversation before having it isCOMMENT
LOWsrc/invisible_playwright_mcp/chat.py281 # `err` with the single word `stopped`, so a deliberate andCOMMENT
LOWsrc/invisible_playwright_mcp/cli.py161 serving = ctx.invoked_subcommand is NoneCOMMENT
LOWsrc/invisible_playwright_mcp/cli.py181 # that was the whole visible evidence.COMMENT
LOWsrc/invisible_playwright_mcp/cli.py241 # IT. Both said the same thing - the flag beats the variable, an empty oneCOMMENT
LOWsrc/invisible_playwright_mcp/agent.py41 "emoji: not as a status marker in front of a line, not as a bullet, not for "COMMENT
LOWsrc/invisible_playwright_mcp/agent.py281 if self.tool_defs is None:COMMENT
LOWsrc/invisible_playwright_mcp/agent.py301 # and unlike the ceiling it can also stop a run on turn three.COMMENT
LOWsrc/invisible_playwright_mcp/agent.py341 # Recoverable: telling the model its arguments were unreadableCOMMENT
LOWsrc/invisible_playwright_mcp/agent.py381# `Conversation`, kept because about twenty-five tests drove the loop throughCOMMENT
LOWsrc/invisible_playwright_mcp/routes.py201 service = await which(request)COMMENT
LOWsrc/invisible_playwright_mcp/routes.py221 # be two accounts of one rule, free to disagree.COMMENT
LOWsrc/invisible_playwright_mcp/routes.py241 # carries "1" and "0": a page older than this server keepsCOMMENT
48 more matches not shown…
Empty Error Handlers8 hits · 40 pts
SeverityFileLineSnippetContext
HIGHtests/test_engine.py141except Exception:CODE
HIGHtests/conftest.py270except OSError:CODE
HIGHtests/conftest.py261except OSError:CODE
HIGHtests/conftest.py266except OSError:CODE
HIGHtests/test_web_service.py770except (asyncio.TimeoutError, StopAsyncIteration):CODE
HIGHtests/test_ui_drive.py371except RuntimeError:CODE
HIGHtests/mcp_server/test_watch.py299except RuntimeError:CODE
HIGHsrc/invisible_playwright_mcp/cli.py299except KeyboardInterrupt:CODE
Modern AI Meta-Vocabulary11 hits · 27 pts
SeverityFileLineSnippetContext
MEDIUMdocs/model-context-protocol-vs-api-vs-rag.md75## MCP vs RAGCOMMENT
MEDIUMdocs/agentic-browser-open-source.md8# Open-source agentic browsersCOMMENT
MEDIUMdocs/agentic-browser-open-source.md132- [Top 5 agentic browsers in 2026](https://seraphicsecurity.com/learn/ai-browser/top-5-agentic-browsers-in-2026-capabiliCODE
MEDIUMdocs/is-openai-operator-still-available.md150- [OpenAI help: ChatGPT agent](https://help.openai.com/en/articles/11752874-chatgpt-agent) and [OpenAI help: Evolving AtCODE
MEDIUMdocs/best-ai-browser-agent.md166- [Wikipedia: OpenAI Operator](https://en.wikipedia.org/wiki/OpenAI_Operator), retrieved 2026-09-03, and [OpenAI help: ECODE
MEDIUMdocs/what-is-an-agentic-browser.md8# What is an agentic browser?COMMENT
MEDIUMdocs/what-is-an-agentic-browser.md44## The four things any agentic browser has to solveCOMMENT
MEDIUMdocs/what-is-an-agentic-browser.md139- [Top 5 agentic browsers in 2026: capabilities and security risks](https://seraphicsecurity.com/learn/ai-browser/top-5-CODE
MEDIUMdocs/what-is-an-agentic-browser.md140- [What is an agentic browser](https://www.sigmabrowser.com/blog/what-is-an-agentic-browser-best-agentic-browsers-in-202CODE
MEDIUMdocs/openai-operator-alternatives.md177- [OpenAI help: ChatGPT agent](https://help.openai.com/en/articles/11752874-chatgpt-agent) and [OpenAI help: Evolving AtCODE
MEDIUMsrc/invisible_playwright_mcp/agent.py267 # size IS the current occupancy of the context window; adding them upCOMMENT
Excessive Try-Catch Wrapping31 hits · 27 pts
SeverityFileLineSnippetContext
LOWtests/test_engine.py141 except Exception:CODE
LOWtests/test_version_is_not_taken.py165 except Exception:CODE
LOWtests/mcp_server/test_click_diagnosis.py77 except Exception:CODE
LOWtests/mcp_server/test_a_gone_browser_is_said.py92 except Exception as raised:CODE
LOWtests/mcp_server/test_a_host_that_opens_the_browser.py39except Exception as exc:CODE
LOWtests/mcp_server/test_read_text_in_a_browser.py90 except Exception as exc: # noqa: BLE001 - the test reads itCODE
LOWsrc/invisible_playwright_mcp/link.py258 except Exception:CODE
LOWsrc/invisible_playwright_mcp/engine.py170 except Exception as exc:CODE
LOWsrc/invisible_playwright_mcp/chat.py288 except Exception as exc:CODE
LOWsrc/invisible_playwright_mcp/quiet.py40 except Exception:CODE
LOWsrc/invisible_playwright_mcp/storage.py181 except Exception:CODE
LOWsrc/invisible_playwright_mcp/agent.py370 except Exception as exc:CODE
LOWsrc/invisible_playwright_mcp/chats.py78 except Exception:CODE
LOWsrc/invisible_playwright_mcp/chats.py83 except Exception:CODE
LOWsrc/invisible_playwright_mcp/routes.py338 except Exception as exc:CODE
LOWsrc/invisible_playwright_mcp/routes.py382 except Exception as exc:CODE
LOWsrc/invisible_playwright_mcp/mcp/clean.py715 except Exception as exc:CODE
LOWsrc/invisible_playwright_mcp/mcp/clean.py274 except Exception:STRING
LOWsrc/invisible_playwright_mcp/mcp/clean.py359 except Exception as exc:STRING
LOWsrc/invisible_playwright_mcp/mcp/session.py99 except Exception:CODE
LOWsrc/invisible_playwright_mcp/mcp/session.py231 except Exception as refused:CODE
MEDIUMsrc/invisible_playwright_mcp/mcp/actions.py197def order_of(selector):CODE
MEDIUMsrc/invisible_playwright_mcp/mcp/actions.py933def choose():CODE
LOWsrc/invisible_playwright_mcp/mcp/actions.py701 except Exception as exc:CODE
LOWsrc/invisible_playwright_mcp/mcp/actions.py755 except Exception as exc:CODE
LOWsrc/invisible_playwright_mcp/mcp/actions.py758 except Exception:CODE
LOWsrc/invisible_playwright_mcp/mcp/actions.py936 except Exception as exc:CODE
LOWsrc/invisible_playwright_mcp/mcp/actions.py200 except Exception: # noqa: BLE001 - the selector stays out, not the snapshotSTRING
LOWsrc/invisible_playwright_mcp/mcp/work.py386 except Exception as exc:CODE
LOWsrc/invisible_playwright_mcp/mcp/work.py699 except Exception:CODE
LOWsrc/invisible_playwright_mcp/mcp/work.py742 except Exception:CODE
Deep Nesting20 hits · 16 pts
SeverityFileLineSnippetContext
LOWtests/conftest.py66CODE
LOWtests/conftest.py239CODE
LOW…s/test_the_product_surface_is_what_the_product_uses.py81CODE
LOW…s/test_the_product_surface_is_what_the_product_uses.py97CODE
LOW…s/test_the_product_surface_is_what_the_product_uses.py145CODE
LOW…s/test_the_product_surface_is_what_the_product_uses.py201CODE
LOWtests/test_a_rule_is_written_where_it_is_applied.py76CODE
LOWtests/test_agent_loop.py751CODE
LOWtests/test_what_is_imported_is_declared.py83CODE
LOWtests/test_what_is_imported_is_declared.py115CODE
LOWtests/test_the_page_tells_the_truth.py796CODE
LOWtests/mcp_server/test_every_tool_says_what_it_does.py100CODE
LOWscripts/check_content.py155CODE
LOWscripts/check_content.py238CODE
LOWscripts/check_content.py265CODE
LOWscripts/check_content.py526CODE
LOWscripts/sync_article_pixels.py124CODE
LOWscripts/build_wiki.py38CODE
LOWsrc/invisible_playwright_mcp/mcp/clean.py395CODE
LOWsrc/invisible_playwright_mcp/mcp/actions.py1164CODE
AI Slop Vocabulary6 hits · 16 pts
SeverityFileLineSnippetContext
MEDIUMtests/test_the_answer_pane_draws_markdown.py405 # as the script being unparseable rather than as the harness being unable toCOMMENT
MEDIUMtests/_page.py19#: Everything from the opening tag on, which is what a harness executes.COMMENT
MEDIUMtests/_page.py30#: across from the retired key. First in the script by construction, so a harnessCOMMENT
MEDIUMtests/test_the_split_between_the_panes.py78 # as the splitter being broken rather than the harness being short a line.COMMENT
MEDIUMtests/test_the_page_tells_the_truth.py1326 #: how the harness first reported a defect that was its own.STRING
MEDIUMtests/test_a_reconnection_keeps_what_you_typed.py112 # harness that defined the prefix itself would keep passing after the pageCOMMENT
Modern Structural Boilerplate4 hits · 4 pts
SeverityFileLineSnippetContext
LOWsrc/invisible_playwright_mcp/_version.py154__all__ = ["__version__", "__install_record_version__", "versions",CODE
LOWsrc/invisible_playwright_mcp/__init__.py7__all__ = ["__version__", "__install_record_version__"]CODE
LOWsrc/invisible_playwright_mcp/mcp/clean.py44__all__ = ["clean_page", "CleanError", "VISIBLE_HTML_JS"]CODE
LOWsrc/invisible_playwright_mcp/mcp/__init__.py46__all__ = ["__version__", "DEFAULT_BROWSER_ID", "SUPPORT_BROWSER_ID", "NOT_OPEN", "OPENED", "GONE"]CODE
Overly Generic Function Names2 hits · 2 pts
SeverityFileLineSnippetContext
LOW⚡…s/test_the_product_surface_is_what_the_product_uses.py369 product = {"agent.py": "def run_task(mcp, task):\n return task\n"}CODE
LOWtests/_loop.py23async def run_task(mcp, task: str, *, client, model: str,CODE
Fake / Example Data1 hit · 0 pts
SeverityFileLineSnippetContext
LOWsrc/invisible_playwright_mcp/mcp/clean.py206 "role", "type", "href", "value", "placeholder", "title", "alt", "action",STRING