Skip to content

Commit a2c41ed

Browse files
committed
fix: ruff format violations in 6 files
1 parent b1b6b7d commit a2c41ed

6 files changed

Lines changed: 178 additions & 111 deletions

File tree

src/brain/scoring_phases.py

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,50 @@ def _apply_modifiers(score: float, phase: str, rule_name: str, goap_hint: str) -
4545
return score
4646

4747

48+
def _is_rule_blocked(
49+
brain: Brain,
50+
r: RuleDef,
51+
now: float,
52+
rule_eval: dict,
53+
diag_results: list,
54+
rule_times: dict,
55+
) -> bool:
56+
"""Check cooldown and circuit breaker. Returns True if rule should be skipped.
57+
58+
Shared by Phases 2/3/4 to avoid duplicating eligibility logic.
59+
"""
60+
if r.name in brain._cooldowns and now < brain._cooldowns[r.name]:
61+
remaining = brain._cooldowns[r.name] - now
62+
rule_eval[r.name] = f"cooldown({remaining:.0f}s)"
63+
diag_results.append(f"{r.name}=CD")
64+
rule_times[r.name] = 0.0
65+
return True
66+
breaker = brain._breakers.get(r.name)
67+
if breaker and not breaker.allow():
68+
rule_eval[r.name] = "OPEN"
69+
diag_results.append(f"{r.name}=OPEN")
70+
rule_times[r.name] = 0.0
71+
return True
72+
return False
73+
74+
75+
def _safe_score(fn: object, *args: object) -> float:
76+
"""Call a scoring function, returning 0.0 on any exception.
77+
78+
Logs at WARNING so failures are visible but don't crash the tick.
79+
"""
80+
try:
81+
result: float = fn(*args) # type: ignore[operator]
82+
return result
83+
except Exception:
84+
log.warning(
85+
"[DECISION] Score function %s raised, defaulting to 0.0",
86+
getattr(fn, "__name__", fn),
87+
exc_info=True,
88+
)
89+
return 0.0
90+
91+
4892
def compute_divergence(brain: Brain, state: GameState, now: float, binary_winner: str) -> None:
4993
"""Phase 1: compute scores for all rules, log when score-based
5094
selection would differ from binary selection."""
@@ -56,10 +100,11 @@ def compute_divergence(brain: Brain, state: GameState, now: float, binary_winner
56100
if r.name in brain._cooldowns and now < brain._cooldowns[r.name]:
57101
scores[r.name] = -1.0 # on cooldown
58102
continue
59-
try:
60-
s = r.score_fn(state)
61-
except Exception:
62-
s = 0.0
103+
breaker = brain._breakers.get(r.name)
104+
if breaker and not breaker.allow():
105+
scores[r.name] = -2.0 # circuit-broken
106+
continue
107+
s = _safe_score(r.score_fn, state)
63108
scores[r.name] = s
64109
if s > best_score:
65110
best_score = s
@@ -89,11 +134,7 @@ def select_by_tier(
89134
tier_groups: dict[int, list[RuleDef]] = defaultdict(list)
90135

91136
for r in brain._rules:
92-
if r.name in brain._cooldowns and now < brain._cooldowns[r.name]:
93-
remaining = brain._cooldowns[r.name] - now
94-
rule_eval[r.name] = f"cooldown({remaining:.0f}s)"
95-
diag_results.append(f"{r.name}=CD")
96-
rule_times[r.name] = 0.0
137+
if _is_rule_blocked(brain, r, now, rule_eval, diag_results, rule_times):
97138
continue
98139
tier_groups[r.tier].append(r)
99140

@@ -103,7 +144,7 @@ def select_by_tier(
103144
scored: list[tuple[float, RuleDef]] = []
104145
for r in tier_groups[tier]:
105146
t0 = time.perf_counter()
106-
s = _apply_modifiers(r.score_fn(state), phase, r.name, goap_hint)
147+
s = _apply_modifiers(_safe_score(r.score_fn, state), phase, r.name, goap_hint)
107148
rule_times[r.name] = (time.perf_counter() - t0) * 1000
108149
rule_eval[r.name] = f"{s:.2f}" if s > 0 else "0"
109150
diag_results.append(f"{r.name}={s:.2f}")
@@ -128,14 +169,10 @@ def select_weighted(
128169
phase, goap_hint = _resolve_phase_context(brain)
129170

130171
for r in brain._rules:
131-
if r.name in brain._cooldowns and now < brain._cooldowns[r.name]:
132-
remaining = brain._cooldowns[r.name] - now
133-
rule_eval[r.name] = f"cooldown({remaining:.0f}s)"
134-
diag_results.append(f"{r.name}=CD")
135-
rule_times[r.name] = 0.0
172+
if _is_rule_blocked(brain, r, now, rule_eval, diag_results, rule_times):
136173
continue
137174
t0 = time.perf_counter()
138-
s = _apply_modifiers(r.score_fn(state), phase, r.name, goap_hint)
175+
s = _apply_modifiers(_safe_score(r.score_fn, state), phase, r.name, goap_hint)
139176
rule_times[r.name] = (time.perf_counter() - t0) * 1000
140177
weighted = r.weight * s
141178
rule_eval[r.name] = f"{weighted:.1f}" if s > 0 else "0"
@@ -173,18 +210,14 @@ def select_with_considerations(
173210
phase, goap_hint = _resolve_phase_context(brain)
174211

175212
for r in brain._rules:
176-
if r.name in brain._cooldowns and now < brain._cooldowns[r.name]:
177-
remaining = brain._cooldowns[r.name] - now
178-
rule_eval[r.name] = f"cooldown({remaining:.0f}s)"
179-
diag_results.append(f"{r.name}=CD")
180-
rule_times[r.name] = 0.0
213+
if _is_rule_blocked(brain, r, now, rule_eval, diag_results, rule_times):
181214
continue
182215
t0 = time.perf_counter()
183216
# Phase 4: prefer considerations over score_fn when defined
184217
if r.considerations and brain._ctx:
185-
raw = score_from_considerations(r.considerations, state, brain._ctx)
218+
raw = _safe_score(score_from_considerations, r.considerations, state, brain._ctx)
186219
else:
187-
raw = r.score_fn(state)
220+
raw = _safe_score(r.score_fn, state)
188221
s = _apply_modifiers(raw, phase, r.name, goap_hint)
189222
rule_times[r.name] = (time.perf_counter() - t0) * 1000
190223
weighted = r.weight * s

0 commit comments

Comments
 (0)