BullshitBench measures whether AI models challenge nonsensical prompts instead of confidently answering them, created by Peter Gostev.
This report summarizes scanner evidence for petergpt/bullshit-benchmark, a Python project with 1,904 GitHub stars. SynthScan examined 129,406 lines of code across 96 source files, recording 296 pattern matches distributed across 7 syntactic categories. The legacy adjusted pattern signal is 2.2 (Low 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.
Payload schema: 1.0.0 · Engine: 2.0.0 · Scoring: heuristic-density-v1 · Scan date: 2026-10-31.
Can maintainers explain intent, assumptions, and trade-offs? 261 finding(s).
Are imports declared and package/API names verified? 20 finding(s).
Are wrappers, guards, and repeated structures necessary? 235 finding(s).
Which changes need focused human review? 296 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
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 296 distinct pattern matches across 7 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_refusal_outcomes.py | 29 | def test_empty_collection_exhausts_three_attempts_and_retains_diagnostics(self): | CODE |
| LOW | tests/test_refusal_outcomes.py | 57 | def test_substantive_collection_after_empty_retry_remains_valid(self): | CODE |
| LOW | tests/test_refusal_outcomes.py | 70 | def test_empty_native_refusal_collection_remains_unscored_outcome(self): | CODE |
| LOW | tests/test_refusal_outcomes.py | 82 | def test_grade_rejects_empty_outputs_without_judge_call(self): | CODE |
| LOW | tests/test_refusal_outcomes.py | 102 | def test_fable_minimal_normalizes_to_native_low(self) -> None: | CODE |
| LOW | tests/test_refusal_outcomes.py | 124 | def test_stored_fable_minimal_row_displays_as_low(self) -> None: | CODE |
| LOW | tests/test_refusal_outcomes.py | 141 | def test_native_refusal_is_classified(self) -> None: | CODE |
| LOW | tests/test_refusal_outcomes.py | 159 | def test_plain_empty_response_is_not_assumed_to_be_refusal(self) -> None: | CODE |
| LOW | tests/test_refusal_outcomes.py | 175 | def test_substantive_text_overrides_native_refusal_marker(self) -> None: | CODE |
| LOW | tests/test_refusal_outcomes.py | 198 | def test_persisted_outcome_survives_slimming_response_text(self) -> None: | CODE |
| LOW | tests/test_refusal_outcomes.py | 211 | def test_explicit_refusal_boolean_has_priority_over_other_markers(self) -> None: | CODE |
| LOW | tests/test_refusal_outcomes.py | 227 | def test_missing_text_is_not_an_empty_answer(self) -> None: | CODE |
| LOW | tests/test_refusal_outcomes.py | 238 | def test_fresh_payload_detects_refusal_before_storing_outcome(self) -> None: | CODE |
| LOW | tests/test_refusal_outcomes.py | 258 | def test_summary_excludes_refusal_from_scores_and_reliability(self) -> None: | CODE |
| LOW | tests/test_refusal_outcomes.py | 313 | def test_grade_skips_provider_refusal(self) -> None: | CODE |
| LOW | tests/test_refusal_outcomes.py | 350 | def test_user_directed_empty_refusal_preserves_provenance_without_native_marker(self): | CODE |
| LOW⚡ | tests/test_published_dataset.py | 232 | def test_oversize_jsonl_record_leaves_originals_untouched(self): | CODE |
| LOW⚡ | tests/test_published_dataset.py | 240 | def test_oversize_gzip_record_leaves_originals_untouched(self): | CODE |
| LOW⚡ | tests/test_published_dataset.py | 250 | def test_compact_summary_can_exceed_uncompressed_limit_when_encoded_small(self): | CODE |
| LOW⚡ | tests/test_published_dataset.py | 460 | def test_cross_asset_id_mismatch_rejected_before_install(self): | CODE |
| LOW⚡ | tests/test_published_dataset.py | 469 | def test_valid_json_truncation_of_small_packed_asset_cannot_be_blessed(self): | CODE |
| LOW⚡ | tests/test_published_dataset.py | 479 | def test_stale_monolithic_shadows_never_override_declared_shards(self): | CODE |
| LOW⚡ | tests/test_published_dataset.py | 489 | def test_orphaned_parts_without_manifest_are_not_a_new_dataset(self): | CODE |
| LOW | tests/test_published_dataset.py | 137 | def test_legacy_read_does_not_parse_or_translate_text(self): | CODE |
| LOW | tests/test_published_dataset.py | 145 | def test_dataset_absence_and_incomplete_legacy_are_distinct(self): | CODE |
| LOW | tests/test_published_dataset.py | 156 | def test_jsonl_roundtrip_preserves_every_byte_and_key(self): | CODE |
| LOW | tests/test_published_dataset.py | 172 | def test_gzip_shards_preserve_numeric_spelling_and_array_interiors(self): | CODE |
| LOW | tests/test_published_dataset.py | 189 | def test_small_assets_use_immutable_paths_with_deterministic_gzip(self): | CODE |
| LOW | tests/test_published_dataset.py | 205 | def test_gzip_is_deterministic_across_fresh_publications(self): | CODE |
| LOW | tests/test_published_dataset.py | 214 | def test_every_part_obeys_limit_counts_hashes_and_sources(self): | CODE |
| LOW | tests/test_published_dataset.py | 262 | def test_empty_assets_roundtrip_and_tiny_cap_fails_safely(self): | CODE |
| LOW | tests/test_published_dataset.py | 271 | def test_missing_part_fails_all_public_read_gates(self): | CODE |
| LOW | tests/test_published_dataset.py | 284 | def test_corrupt_part_same_size_fails_checksum(self): | CODE |
| LOW | tests/test_published_dataset.py | 294 | def test_corrupt_manifest_counts_hashes_and_formats_fail(self): | CODE |
| LOW | tests/test_published_dataset.py | 316 | def test_actual_row_count_is_checked_not_only_manifest_totals(self): | CODE |
| LOW | tests/test_published_dataset.py | 326 | def test_unknown_or_malformed_storage_version_fails_closed(self): | CODE |
| LOW | tests/test_published_dataset.py | 342 | def test_traversal_absolute_url_encoded_and_reordered_paths_fail(self): | CODE |
| LOW | tests/test_published_dataset.py | 358 | def test_part_file_and_directory_symlinks_are_rejected(self): | CODE |
| LOW | tests/test_published_dataset.py | 376 | def test_invalid_gzip_rejected_even_with_updated_encoded_checksum(self): | CODE |
| LOW | tests/test_published_dataset.py | 388 | def test_repeat_and_limit_migrations_do_not_lose_data(self): | CODE |
| LOW | tests/test_published_dataset.py | 406 | def test_new_records_only_change_final_existing_jsonl_shard(self): | CODE |
| LOW | tests/test_published_dataset.py | 424 | def test_duplicate_sample_ids_fail_before_replacement(self): | CODE |
| LOW | tests/test_published_dataset.py | 433 | def test_missing_empty_and_nonstring_sample_ids_are_rejected(self): | CODE |
| LOW | tests/test_published_dataset.py | 444 | def test_duplicate_ids_across_stored_parts_are_rejected(self): | CODE |
| LOW | tests/test_published_dataset.py | 501 | def test_orphaned_parts_with_all_monolithic_shadows_still_require_manifest(self): | CODE |
| LOW | tests/test_published_dataset.py | 518 | def test_failure_before_manifest_activation_keeps_old_dataset_readable(self): | CODE |
| LOW | tests/test_published_dataset.py | 538 | def test_reader_holding_previous_manifest_can_read_during_and_after_install(self): | CODE |
| LOW | tests/test_published_dataset.py | 558 | def test_legacy_cross_asset_id_mismatch_fails_verification(self): | CODE |
| LOW | tests/test_published_dataset.py | 585 | def test_details_group_by_question_preserving_every_record_and_canonical_byte(self): | CODE |
| LOW | tests/test_published_dataset.py | 610 | def test_question_partition_metadata_must_match_summary(self): | CODE |
| LOW | tests/test_published_dataset.py | 621 | def test_missing_summary_question_id_and_disagreeing_detail_question_fail(self): | CODE |
| LOW | tests/test_published_dataset.py | 632 | def test_unchanged_question_groups_reuse_existing_content_files(self): | CODE |
| LOW | tests/test_published_dataset.py | 653 | def test_existence_check_does_not_decode_or_hash_entire_asset_again(self): | CODE |
| LOW | tests/test_published_dataset.py | 671 | def test_cli_cat_exact_bytes_and_corruption_goes_to_stderr(self): | CODE |
| LOW | tests/test_published_dataset.py | 685 | def test_model_launch_jsonl_reader_matches_legacy_with_unicode_separator(self): | CODE |
| LOW | tests/test_published_dataset.py | 695 | def test_model_launch_inventory_matches_legacy_and_rejects_missing_shards(self): | CODE |
| LOW | tests/test_published_dataset.py | 712 | def test_forge_aggregate_reader_matches_legacy_full_schema(self): | CODE |
| LOW | tests/test_repair_published_judges.py | 104 | def test_verified_same_judge_repair_preserves_answers_other_judges_and_metadata(self): | CODE |
| LOW | tests/test_repair_published_judges.py | 129 | def test_summary_only_historical_error_keeps_aggregate_bytes_but_excludes_partial_score(self): | CODE |
| LOW⚡ | tests/test_repair_published_judges.py | 144 | def test_valid_scores_cannot_be_replaced(self): | CODE |
| 160 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_publication.py | 155 | CODE | |
| LOW | tests/test_judge_failures.py | 299 | CODE | |
| LOW | scripts/model_launch_pipeline.py | 292 | CODE | |
| LOW | scripts/model_launch_pipeline.py | 761 | CODE | |
| LOW | scripts/repair_published_judges.py | 226 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 1229 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 1602 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 2353 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 2640 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 2680 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 2868 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 3123 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 3727 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 3872 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 4355 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 4917 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 5466 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 5606 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 5773 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 5842 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 5898 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 6125 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 6252 | CODE | |
| LOW | scripts/push_bullshitbench_to_forge.py | 142 | CODE | |
| LOW | scripts/validate_configs.py | 46 | CODE | |
| LOW | scripts/validate_configs.py | 94 | CODE | |
| LOW | scripts/published_dataset.py | 157 | CODE | |
| LOW | scripts/published_dataset.py | 303 | CODE | |
| LOW | scripts/published_dataset.py | 639 | CODE | |
| LOW | scripts/published_dataset.py | 723 | CODE | |
| LOW | scripts/published_dataset.py | 783 | CODE | |
| LOW | scripts/publication.py | 89 | CODE | |
| LOW | scripts/publication.py | 245 | CODE | |
| LOW | scripts/publication.py | 507 | CODE | |
| LOW | scripts/publication.py | 645 | CODE | |
| LOW | scripts/build_pages.py | 132 | CODE | |
| LOW | scripts/build_questions_v2_from_draft.py | 103 | CODE | |
| LOW | scripts/build_questions_v2_from_draft.py | 244 | CODE | |
| LOW | scripts/apply_judge_fallback.py | 46 | CODE | |
| LOW | scripts/apply_judge_fallback.py | 67 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | scripts/repair_published_judges.py | 263 | except ValueError: | CODE |
| HIGH | scripts/openrouter_benchmark.py | 1439 | except ValueError: | CODE |
| HIGH | scripts/openrouter_benchmark.py | 3765 | except json.JSONDecodeError: | CODE |
| HIGH | scripts/openrouter_benchmark.py | 4709 | except StopIteration: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_publication.py | 2 | CODE | |
| LOW | tests/test_publication.py | 15 | CODE | |
| LOW | scripts/model_launch_pipeline.py | 8 | CODE | |
| LOW | scripts/check_openrouter_new_text_models.py | 4 | CODE | |
| LOW | scripts/check_openrouter_new_text_models.py | 12 | CODE | |
| LOW | scripts/repair_published_judges.py | 9 | CODE | |
| LOW | scripts/annotate_star_history_milestone.py | 2 | CODE | |
| LOW | scripts/render_star_milestone_chart.py | 2 | CODE | |
| LOW | scripts/render_star_milestone_chart.py | 12 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 14 | CODE | |
| LOW | scripts/openrouter_benchmark.py | 22 | CODE | |
| LOW | scripts/push_bullshitbench_to_forge.py | 4 | CODE | |
| LOW | scripts/push_bullshitbench_to_forge.py | 17 | CODE | |
| LOW | scripts/validate_configs.py | 4 | CODE | |
| LOW | scripts/published_dataset.py | 20 | CODE | |
| LOW | scripts/publication.py | 3 | CODE | |
| LOW | scripts/build_pages.py | 8 | CODE | |
| LOW | scripts/build_questions_v2_from_draft.py | 8 | CODE | |
| LOW | scripts/apply_judge_fallback.py | 8 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | scripts/publish_latest_to_viewer.sh | 503 | except Exception: | CODE |
| LOW | scripts/publish_latest_to_viewer.sh | 712 | except Exception: | CODE |
| LOW | scripts/openrouter_benchmark.py | 2471 | except Exception as exc: # pylint: disable=broad-except | CODE |
| LOW | scripts/openrouter_benchmark.py | 2628 | except Exception as exc: # pylint: disable=broad-except | CODE |
| LOW | scripts/openrouter_benchmark.py | 3104 | except Exception as exc: # pylint: disable=broad-except | CODE |
| LOW | scripts/openrouter_benchmark.py | 3490 | except Exception as exc: # pylint: disable=broad-except | CODE |
| LOW | scripts/openrouter_benchmark.py | 4116 | except Exception as parse_exc: # pylint: disable=broad-except | CODE |
| LOW | scripts/openrouter_benchmark.py | 4141 | except Exception as exc: # pylint: disable=broad-except | CODE |
| LOW | scripts/openrouter_benchmark.py | 4622 | except Exception as exc: # pylint: disable=broad-except | CODE |
| LOW | scripts/openrouter_benchmark.py | 4872 | except Exception: | CODE |
| LOW | scripts/openrouter_benchmark.py | 5299 | except Exception as exc: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH⚡ | tests/test_pipeline_consumers.py | 204 | path.write_text('{"consensus_score": null}\n{"sample_id":', encoding="utf-8") | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | scripts/build_questions_v2_from_draft.py | 259 | # Check if legacy or new format | COMMENT |