Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions gitgalaxy/metrics/signal_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@ def calculate_risk_vector(
f_feature_names = func_ml_brain.get("FEATURE_NAMES", [])
f_weights = func_ml_brain.get("FEATURE_WEIGHTS", [1.0] * len(f_feature_names))
f_caps = func_ml_brain.get("CAP_VALUES", {})
enc_lang_weight = analysis_lens.FUNCTION_ENCAPSULATION_LANG_WEIGHT.get(lang_id.lower(), 1.0)
f_dna_sources = func_ml_brain.get("DNA_SOURCES", {})
f_names = func_ml_brain.get("cluster_names", [])
f_arch_key = next((k for k in func_ml_brain if k.startswith("ARCHETYPES_K")), None)
Expand Down Expand Up @@ -652,6 +653,8 @@ def calculate_risk_vector(
med = f_medians[i] if i < len(f_medians) else 0.0
iqr = f_iqrs[i] if i < len(f_iqrs) and f_iqrs[i] > 0 else 1.0
w = f_weights[i] if i < len(f_weights) else 1.0
if fname == "log_density_def_encapsulation":
w *= enc_lang_weight
scaled_vec.append(((v - med) / iqr) * w)

best_idx, best_dist = -1, None
Expand Down
6 changes: 6 additions & 0 deletions gitgalaxy/standards/analysis_lens.py
Original file line number Diff line number Diff line change
Expand Up @@ -1737,6 +1737,12 @@ def inactive_vectors(scan_config: dict[str, Any] | None = None) -> set[str]:
# clip raw densities by CAP_VALUES, log1p, RobustScale by MEDIANS/IQRS, multiply by
# FEATURE_WEIGHTS, then nearest centroid -> cluster_names[idx]. signal_processor.py
# builds this vector from each function's hit_vector via DNA_SOURCES.
# #5897: languages whose encapsulation rule counts spelling (lowercase = unexported), so the
# signal is hot on every function and decides the archetype instead of describing it. The
# function classifier multiplies the encapsulation feature of these languages' functions by
# the factor, after scaling (a feature weight, applied on top of FEATURE_WEIGHTS).
FUNCTION_ENCAPSULATION_LANG_WEIGHT = {"go": 0.3}

GENERAL_FUNCTION_INFERENCE_MODEL = {
"SCALER_MEDIANS": [
2.303,
Expand Down
31 changes: 31 additions & 0 deletions tests/core_engine/test_signal_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -1843,6 +1843,37 @@ def test_function_archetype_matching_dimensions_uses_plain_cluster_name(processo
assert [f["archetype"] for f in meta["functions"]] == ["Tiny Helper", "Huge Router"]


@pytest.mark.parametrize(
"lang_id,expected",
[("go", "Plain"), ("Go", "Plain"), ("python", "Encapsulated"), ("c", "Encapsulated")],
)
def test_function_archetype_down_weights_encapsulation_for_spelling_languages(
processor, monkeypatch, lang_id, expected
):
"""#5897: Go's encapsulation counts lowercase spelling, so its density must not decide the
archetype; the same hit density still does for a language whose rule is a real visibility marker."""
from gitgalaxy.metrics import signal_processor as sp_mod

model = {
"FEATURE_NAMES": ["log_density_def_encapsulation"],
"FEATURE_WEIGHTS": [1.0],
"CAP_VALUES": {},
"DNA_SOURCES": {},
"SCALER_MEDIANS": [0.0],
"SCALER_IQRS": [1.0],
"cluster_names": ["Plain", "Encapsulated"],
"ARCHETYPES_K2": {"0: Plain": [0.0], "1: Encapsulated": [3.43]},
}
monkeypatch.setattr(sp_mod.analysis_lens, "GENERAL_FUNCTION_INFERENCE_MODEL", model)
functions = [{"name": "f", "loc": 10, "branch": 1, "args": 0, "hit_vector": {"def_encapsulation": 3}}]
meta, sig = create_synthetic_star(processor, "enc", 10, functions=functions)
meta["lang_id"] = lang_id

processor.calculate_risk_vector(meta, sig)

assert meta["functions"][0]["archetype"] == expected


def test_file_archetype_is_unclassified_placeholder(processor):
"""File-level archetypes are classified later in record_keeper; the signal
processor only emits the Unclassified placeholder."""
Expand Down
114 changes: 57 additions & 57 deletions tests/golden_master_audit/12_scan_output_snapshots/gpu_json.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading