"""Punktacja siły trafień — do rankingowania faset (zalążek LOG-21). v1 liczy siłę z sygnałów OBLICZALNYCH: - typ fasety (aspekt zwykle mocniejszy od znaku/domu), - rodzaj aspektu (koniunkcja/opozycja mocniejsze od sekstyla), - ciasnota orbu (im bliżej dokładności, tym mocniej). Wszystko konfigurowalne. HOOK NA PRZYSZŁOŚĆ: gdy w SIGNIFICATORS KEY zostaną wypełnione kolumny `countas*`/`level*`, można je tu domieszać per sygnifikator. """ from __future__ import annotations # bazowe wagi faset (łatwe do strojenia) FACET_BASE = {"sign": 5.0, "house": 5.0, "aspect": 6.0} # względna siła aspektów głównych ASPECT_WEIGHT = { "conjunction": 1.0, "opposition": 0.95, "square": 0.85, "trine": 0.85, "sextile": 0.65, } # aspekt aplikacyjny (A) jest silniejszy niż separacyjny (S) — notes3 APPLYING_BONUS = 1.15 def score_facet(facet: dict) -> float: """Siła fasety w skali ~0–12. Deterministyczna, konfigurowalna.""" base = FACET_BASE.get(facet.get("type"), 1.0) if facet.get("type") == "aspect": weight = ASPECT_WEIGHT.get(facet.get("aspect"), 0.7) orb = facet.get("orb") allowed = facet.get("allowed") or 10.0 tight = max(0.0, 1.0 - orb / allowed) if orb is not None and allowed else 0.0 score = base * weight * (1.0 + tight) if facet.get("applying"): score *= APPLYING_BONUS return round(score, 2) return round(base, 2)