fix(guard+memory): radical overhaul of close friends detection & circuit breaker
CLOSE FRIENDS GUARD:
- Replaced broken text-only detection ('enge freunde'/'close friend')
with STRUCTURAL resource-id marker detection:
* friendly_bubbles_component (feed posts)
* profile_header_close_friend (profile view)
* close_friends_badge (Reels)
* close_friends_star (green star)
- Kept legacy text fallback for edge cases
- TDD: 5 tests including meta-test enforcing structural detection
CONTEXT MEMORY CIRCUIT BREAKER:
- Old system: single failure permanently blocks action (confidence < 0.2 = dead)
- New system: time-based decay — failures older than 1 hour are auto-forgiven
and the poisoned entry is DELETED, allowing re-exploration
- This prevents catastrophic self-sabotage where the bot blocks its own
core actions (tap like, tap follow, tap comment) permanently
- Purged 14 poisoned entries from live Qdrant that were blocking ALL
fundamental interactions
- TDD: 2 meta-tests enforcing time-decay and no permanent blocking
Full suite: 106/107 passed (1 infra flake)
This commit is contained in:
@@ -35,7 +35,21 @@ class CloseFriendsGuardPlugin(BehaviorPlugin):
|
||||
return False
|
||||
|
||||
xml = ctx.context_xml if ctx.context_xml else ctx.device.dump_hierarchy()
|
||||
return "enge freunde" in xml.lower() or "close friend" in xml.lower()
|
||||
xml_lower = xml.lower()
|
||||
|
||||
# Structural resource-id markers (language-agnostic, O(1) detection)
|
||||
structural_markers = (
|
||||
"friendly_bubbles_component", # Close friend post in feed
|
||||
"profile_header_close_friend", # Close friend badge on profile
|
||||
"close_friends_badge", # Close friend badge in Reels
|
||||
"close_friends_star", # Green star indicator
|
||||
)
|
||||
for marker in structural_markers:
|
||||
if marker in xml_lower:
|
||||
return True
|
||||
|
||||
# Legacy text fallback for edge cases
|
||||
return "enge freunde" in xml_lower or "close friend" in xml_lower
|
||||
|
||||
def execute(self, ctx: BehaviorContext) -> BehaviorResult:
|
||||
logger.info("💚 [CloseFriendsGuard] Close friends post detected. Skipping...")
|
||||
|
||||
@@ -1499,13 +1499,17 @@ class ContextMemoryDB(QdrantBase):
|
||||
|
||||
def is_allowed(self, intent: str, screen_type: str) -> bool:
|
||||
"""
|
||||
Exploration vs Exploitation:
|
||||
If we don't know (no entry or neutral confidence), allow it!
|
||||
Only block if we have learned it fails consistently (< 0.2).
|
||||
Exploration vs Exploitation with time-based decay:
|
||||
- If we don't know (no entry), allow it (exploration).
|
||||
- Only block if we have RECENTLY learned it fails (< 0.2 confidence AND < 1 hour old).
|
||||
- Old failures decay: entries older than 1 hour are auto-forgiven and deleted,
|
||||
preventing permanent poisoning of the action space.
|
||||
"""
|
||||
if not self.is_connected:
|
||||
return True # Fail-open for exploration
|
||||
|
||||
DECAY_THRESHOLD_SECONDS = 3600 # 1 hour: old failures are forgiven
|
||||
|
||||
key = self._get_key(intent, screen_type)
|
||||
try:
|
||||
point_id = self.generate_uuid(key)
|
||||
@@ -1513,11 +1517,25 @@ class ContextMemoryDB(QdrantBase):
|
||||
collection_name=self.collection_name, ids=[point_id], with_payload=True, with_vectors=False
|
||||
)
|
||||
if points:
|
||||
conf = points[0].payload.get("confidence", 0.5)
|
||||
payload = points[0].payload
|
||||
conf = payload.get("confidence", 0.5)
|
||||
updated_at = payload.get("updated_at", 0)
|
||||
age_seconds = time.time() - updated_at
|
||||
|
||||
# Time-based decay: old failures are forgiven
|
||||
if conf < 0.2 and age_seconds > DECAY_THRESHOLD_SECONDS:
|
||||
logger.info(
|
||||
f"🔄 [ContextMemory] Forgave old failure for '{intent}' on '{screen_type}' "
|
||||
f"(age: {age_seconds/60:.0f}min, confidence: {conf:.2f}). Allowing re-exploration."
|
||||
)
|
||||
# Delete the stale entry so the bot can re-learn
|
||||
self.delete_point(key)
|
||||
return True
|
||||
|
||||
if conf < 0.2:
|
||||
logger.warning(
|
||||
f"🛡️ [ContextMemory] Circuit Breaker: Blocked '{intent}' on '{screen_type}' "
|
||||
f"(learned confidence {conf:.2f} < 0.2)"
|
||||
f"(learned confidence {conf:.2f} < 0.2, age: {age_seconds/60:.0f}min)"
|
||||
)
|
||||
return False
|
||||
except Exception:
|
||||
|
||||
Reference in New Issue
Block a user