From 6a395b9c0d994b199da61e9c1fc42d8dd178d99e Mon Sep 17 00:00:00 2001 From: Andreas Solleder Date: Tue, 1 Sep 2026 16:12:23 +0200 Subject: [PATCH 1/2] feat(collector): ignore priv/static by default Built asset bundles under priv/static are generated output, and their minified lines skew line-length, readability and duplication metrics for the whole codebase. --- lib/codeqa/engine/collector.ex | 3 ++- test/codeqa/collector_test.exs | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/codeqa/engine/collector.ex b/lib/codeqa/engine/collector.ex index 8fc1e4c..95b9a37 100644 --- a/lib/codeqa/engine/collector.ex +++ b/lib/codeqa/engine/collector.ex @@ -10,7 +10,8 @@ defmodule CodeQA.Engine.Collector do .next coverage ]) - @default_ignore_patterns ~w[**/*.md **/*.mdx] + # priv/static holds build output, so its bundles skew line-length and duplication metrics. + @default_ignore_patterns ~w[**/*.md **/*.mdx priv/static/** **/priv/static/**] @spec source_extensions() :: MapSet.t() def source_extensions, diff --git a/test/codeqa/collector_test.exs b/test/codeqa/collector_test.exs index 69ed2fb..7c78751 100644 --- a/test/codeqa/collector_test.exs +++ b/test/codeqa/collector_test.exs @@ -161,6 +161,19 @@ defmodule CodeQA.CollectorTest do refute Map.has_key?(files, "test/app_test.exs") end + test "excludes built assets under priv/static by default", %{tmp_dir: tmp_dir} do + File.mkdir_p!(Path.join(tmp_dir, "priv/static/assets")) + File.mkdir_p!(Path.join(tmp_dir, "apps/web/priv/static/assets")) + File.write!(Path.join(tmp_dir, "priv/static/assets/app.js"), "var a=1") + File.write!(Path.join(tmp_dir, "apps/web/priv/static/assets/app.js"), "var a=1") + + files = Collector.collect_files(tmp_dir) + + assert Map.has_key?(files, "lib/app.ex") + refute Map.has_key?(files, "priv/static/assets/app.js") + refute Map.has_key?(files, "apps/web/priv/static/assets/app.js") + end + test "respects ignore_paths from .codeqa.yml", %{tmp_dir: tmp_dir} do File.mkdir_p!(Path.join(tmp_dir, "generated")) File.write!(Path.join(tmp_dir, "generated/schema.ex"), "defmodule Schema do\nend") From c8dab2ee6fd7379fa7c2c3bd0d16c64f6b0667e5 Mon Sep 17 00:00:00 2001 From: Andreas Solleder Date: Tue, 1 Sep 2026 17:04:13 +0200 Subject: [PATCH 2/2] fix(top-blocks): lower severity gates so real findings surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nach der Baseline-Subtraktion liegen Block-Deltas dicht am File-Floor, wodurch die alten Gates (0.50/0.25/0.10) praktisch jeden echten Befund als medium einstuften — und medium wird verworfen. Ergebnis war ein Actionables-Report, der auch im eigenen Repo dauerhaft 0 blocks flagged meldete. --- lib/codeqa/health_report/top_blocks.ex | 8 ++++-- test/codeqa/health_report/top_blocks_test.exs | 28 +++++++++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/codeqa/health_report/top_blocks.ex b/lib/codeqa/health_report/top_blocks.ex index 7ada4a8..e7bd2c0 100644 --- a/lib/codeqa/health_report/top_blocks.ex +++ b/lib/codeqa/health_report/top_blocks.ex @@ -5,9 +5,11 @@ defmodule CodeQA.HealthReport.TopBlocks do alias CodeQA.CombinedMetrics.Scorer @min_tokens 10 - @severity_critical 0.50 - @severity_high 0.25 - @severity_medium 0.10 + # Block deltas sit near the file baseline after the floor subtraction, so the + # old 0.50/0.25/0.10 gates classified every real finding as medium and dropped it. + @severity_critical 0.25 + @severity_high 0.10 + @severity_medium 0.04 @gap_floor 0.01 @top_n 10 @default_min_lines 3 diff --git a/test/codeqa/health_report/top_blocks_test.exs b/test/codeqa/health_report/top_blocks_test.exs index 67974fd..45091b0 100644 --- a/test/codeqa/health_report/top_blocks_test.exs +++ b/test/codeqa/health_report/top_blocks_test.exs @@ -63,27 +63,27 @@ defmodule CodeQA.HealthReport.TopBlocksTest do do: %{{"function_design", "cyclomatic_complexity_under_10"} => cosine} describe "severity classification" do - test ":critical when severity_ratio > 0.50" do - # gap = max(0.01, 1.0 - 0.0) = 1.0, ratio = 0.60 / 1.0 = 0.60 > 0.50 - [block] = TopBlocks.build(make_results([make_node(0.60)]), [], lookup()) + test ":critical when severity_ratio > 0.25" do + # gap = max(0.01, 1.0 - 0.0) = 1.0, ratio = 0.30 / 1.0 = 0.30 > 0.25 + [block] = TopBlocks.build(make_results([make_node(0.30)]), [], lookup()) assert hd(block.potentials).severity == :critical end - test ":high when severity_ratio > 0.25 and <= 0.50" do - # ratio = 0.30 / 1.0 = 0.30 - [block] = TopBlocks.build(make_results([make_node(0.30)]), [], lookup()) + test ":high when severity_ratio > 0.10 and <= 0.25" do + # ratio = 0.15 / 1.0 = 0.15 + [block] = TopBlocks.build(make_results([make_node(0.15)]), [], lookup()) assert hd(block.potentials).severity == :high end - test ":medium when severity_ratio > 0.10 and <= 0.25" do - # ratio = 0.15 / 1.0 = 0.15 - [block] = TopBlocks.build(make_results([make_node(0.15)]), [], lookup()) + test ":medium when severity_ratio > 0.04 and <= 0.10" do + # ratio = 0.05 / 1.0 = 0.05 + [block] = TopBlocks.build(make_results([make_node(0.05)]), [], lookup()) assert hd(block.potentials).severity == :medium end - test "filtered when severity_ratio <= 0.10" do - # ratio = 0.05 / 1.0 = 0.05 — block should not appear - assert TopBlocks.build(make_results([make_node(0.05)]), [], lookup()) == [] + test "filtered when severity_ratio <= 0.04" do + # ratio = 0.02 / 1.0 = 0.02 — block should not appear + assert TopBlocks.build(make_results([make_node(0.02)]), [], lookup()) == [] end test "gap floor prevents division by zero when codebase_cosine = 1.0" do @@ -94,8 +94,8 @@ defmodule CodeQA.HealthReport.TopBlocksTest do test "gap handles negative codebase_cosine" do # codebase_cosine = -0.5, gap = max(0.01, 1.0 - (-0.5)) = 1.5 - # ratio = 0.60 / 1.5 = 0.40 → :high - [block] = TopBlocks.build(make_results([make_node(0.60)]), [], lookup(-0.5)) + # ratio = 0.30 / 1.5 = 0.20 → :high + [block] = TopBlocks.build(make_results([make_node(0.30)]), [], lookup(-0.5)) assert hd(block.potentials).severity == :high end