Skip to content

fix(health-report): cosine-Behaviors erzeugen JS/Phoenix-False-Positives (no_dead_code, boolean ?-suffix) #65

Description

@aspala

Korrektur (2026-06-10): Eine frühere Version dieses Issues behauptete einen Filter-Bug ("Allowlist _languages wird im Task-Filter ignoriert"). Das war falsch — die Allowlist greift korrekt (s.u.). Es bleibt ein reiner Modell-Mismatch.

Problem

health-report --view actions (bzw. both) gegen ein Phoenix-Repo mit JS-Assets erzeugt Handlungsempfehlungen, die größtenteils False Positives sind. Lauf gegen position-db (full-repo, kein --base-ref): 7 Tasks, davon ~6 unbrauchbar.

Kein Sprach-Filter-Bug

Verifiziert: die _languages-Allowlist wird an zwei Stellen korrekt angewandt:

  • lib/codeqa/combined_metrics/sample_runner.ex:446behavior_language_applies?/3 beim cosine-Scoring (der Pfad, den RefactoringPotentials über diagnose_aggregate nutzt).
  • lib/codeqa/block_impact_analyzer.ex:97filter_behaviors_by_languages/2 filtert vorab project-weit. compute reicht language: node_ctx.language durch (block_impact_analyzer.ex:323).

refactoring_potentials.ex:138 (language_excluded?/3, nur _excludes_languages) ist ein redundanter Zweitfilter, kein Leck.

Alle 7 FP-Tasks lagen innerhalb ihrer erlaubten Sprachen:

Behavior YAML lang-gate FP-File erlaubt?
naming_conventions/function_name_matches_return_type _languages: [elixir] .ex
function_design/boolean_function_has_question_mark _languages: [elixir, javascript, python, ruby] .ex + .js
code_smells/no_dead_code_after_return _excludes_languages: [elixir] .js

Echte Ursache: sample-basierte Behaviors generalisieren schlecht

Die Behaviors sind keine AST-/Regex-Checks, sondern cosine-similarity-Klassifizierer auf gelernten Scalars (lib/codeqa/combined_metrics/scorer.ex:22-29, cosine_vector.ex). Trainings-Samples unter priv/combined_metrics/samples/<category>/<behavior>/ sind überwiegend .ex.

  • no_dead_code_after_return: deutet idiomatische JS early-return-Guards (if (!x) return) als "dead code after return". 4 von 7 Tasks.
  • boolean_function_has_question_mark: feuert auf einen JS-Lifecycle-Hook (updated()) und auf ein Elixir-defmodule mit @type-Defs — beides keine boolean-Predicates.
  • function_name_matches_return_type (critical): trifft Assign-Keys (has_children, is_expanded), keine Funktionsnamen.

Gemeinsamer Nenner: rein statistisch, nicht AST-aware → kann Map-Keys/Lifecycle-Hooks/Guards nicht von echten Funktionen unterscheiden.

Reproduktion

codeqa health-report <phoenix-repo-mit-js> --detail full --top 5

(ohne --base-ref, damit Blocks über das ganze Repo laufen)

Fix-Richtungen

  1. no_dead_code_after_return von cosine auf echte AST-/Regex-Prüfung umstellen — early-return-Guard ≠ unreachable. (Eigenes Follow-up, substantielle Arbeit.)
  2. JS-Samples für die JS-fähigen Behaviors ergänzen (no_dead_code_after_return, boolean_function_has_question_mark).
  3. Konfidenz-Floor / cosine-Schwelle anheben, damit grenzwertige Profile keine Tasks erzeugen.
  4. Behaviors, die echte AST-Struktur brauchen (Funktion vs. Map-Key vs. Lifecycle-Hook), grundsätzlich nicht als cosine-Klassifizierer modellieren.

Konkret generierte False-Positive-Tasks (Lauf gegen position-db)

# Sev File Behavior Warum FP
1 critical price_list_components.ex:238 function_name_matches_return_type trifft Assign-Keys, keine Funktion
2 high registry_mass.ex:1 boolean_function_has_question_mark defmodule mit @type, kein Predicate
3-5,7 high assets/js/*.js no_dead_code_after_return early-return-Guards, kein dead code
6 high formula_builder_hidden_input.js boolean_function_has_question_mark JS-Lifecycle-Hook, kein boolean

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingjavascriptPull requests that update javascript code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions