feat: wire event relevance gate

This commit is contained in:
2026-04-09 10:58:58 -04:00
parent 629785d548
commit 45b57b4d13
+16 -8
View File
@@ -102,7 +102,7 @@ class EventManager:
self._churnSuppressed: bool = cthulhu_state.pauseAtspiChurn
self._prioritizedContextToken: Optional[str] = cthulhu_state.prioritizedDesktopContextToken
self._relevanceBurstWindow: float = 0.15
self._relevanceBurstHistory: Dict[Tuple[str, str], float] = {}
self._relevanceBurstHistory: Dict[Tuple[str, str, str], float] = {}
cthulhu_state.device = None
self._keyHandlingActive: bool = False
@@ -238,14 +238,14 @@ class EventManager:
return self._isLiveOrNotificationEvent(event)
def _isLiveOrNotificationObject(self, obj: Any) -> bool:
if obj is None:
if obj is None or isinstance(obj, (str, bytes, int, float, bool)):
return False
try:
if AXUtilities.is_notification(obj) or AXUtilities.is_alert(obj):
return True
except Exception:
return False
pass
try:
liveAttr = AXObject.get_attribute(obj, 'live')
@@ -329,14 +329,11 @@ class EventManager:
return None
def _classifyRelevance(self, event: Atspi.Event, app: Atspi.Accessible) -> str:
if self._is_obsolete_by_context(event):
return self.RELEVANCE_DROP
if self._shouldPreserveForRelevanceGate(event):
return self.RELEVANCE_KEEP
if event.type.startswith("object:state-changed:focused"):
return self.RELEVANCE_KEEP if event.detail1 else self.RELEVANCE_DROP
return self.RELEVANCE_KEEP
role = self._eventRoleForRelevance(event)
eventGroup = self._relevanceEventGroup(event, role)
@@ -374,7 +371,12 @@ class EventManager:
return False
appName = self._appNameForRelevance(app) or "unknown-app"
burstKey = (appName, eventGroup)
try:
contextKey = self._context_token_for_event(event)
except Exception:
contextKey = None
contextKey = contextKey or f"source:{id(event.source)}"
burstKey = (appName, eventGroup, contextKey)
now = time.monotonic()
lastSeen = self._relevanceBurstHistory.get(burstKey)
self._relevanceBurstHistory[burstKey] = now
@@ -468,6 +470,12 @@ class EventManager:
else:
return _ignore_with_reason("inactive-app", "event not from active app")
relevance = self._classifyRelevance(event, app)
if relevance == self.RELEVANCE_DROP:
return _ignore_with_reason("event-relevance-drop", "event is background churn")
if relevance == self.RELEVANCE_COLLAPSE:
return _ignore_with_reason("event-relevance-collapse", "event was collapsed by relevance gate")
if self._isSteamBurstChurnEvent(event, app):
return _ignore_with_reason("steam-burst-churn", "event is low-value Steam churn")