feat(core): finalize P2 & P3 hardening - Topology HD Map, Empathy Filter, and Git Hygiene
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -53,10 +53,11 @@ coverage.xml
|
||||
debug/
|
||||
|
||||
# Bytecode & Cache (Enforce at bottom to override whitelists)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
**/__pycache__/
|
||||
**/*.pyc
|
||||
**/*.pyo
|
||||
**/*.pyd
|
||||
.pytest_cache/
|
||||
.hypothesis/
|
||||
.coverage
|
||||
htmlcov/
|
||||
|
||||
@@ -34,8 +34,8 @@ class ResonanceEvaluatorPlugin(BehaviorPlugin):
|
||||
def execute(self, ctx: BehaviorContext) -> BehaviorResult:
|
||||
resonance = ctx.cognitive_stack.get("resonance")
|
||||
if not resonance:
|
||||
logger.warning("🧠 [Resonance] Engine missing. Defaulting to 1.0")
|
||||
res_score = 1.0
|
||||
logger.error("🧠 [Resonance] CRITICAL: Engine missing from cognitive stack. Defaulting to 0.5 (neutral).")
|
||||
res_score = 0.5
|
||||
else:
|
||||
post_data = ctx.post_data or {}
|
||||
res_score = resonance.calculate_resonance(post_data)
|
||||
|
||||
@@ -942,14 +942,11 @@ def _run_zero_latency_feed_loop(
|
||||
|
||||
dopamine = cognitive_stack.get("dopamine")
|
||||
darwin = cognitive_stack.get("darwin")
|
||||
cognitive_stack.get("resonance")
|
||||
ai = cognitive_stack.get("active_inference")
|
||||
growth = cognitive_stack.get("growth_brain")
|
||||
cognitive_stack.get("swarm")
|
||||
|
||||
# Track interaction outcomes for end-of-session learning
|
||||
session_outcomes = []
|
||||
session_outcomes = []
|
||||
shared_state = {"consecutive_marker_misses": 0, "consecutive_ads": 0, "session_outcomes": session_outcomes}
|
||||
|
||||
from GramAddict.core.session_state import SessionState
|
||||
|
||||
@@ -270,7 +270,7 @@ class ActionMemory:
|
||||
else:
|
||||
# VLM returned ambiguous response (JSON, mixed signals, etc.)
|
||||
# Don't treat as hard failure — fall through to structural delta verification
|
||||
logger.info(
|
||||
logger.debug(
|
||||
f"🧠 [ActionMemory] VLM response for '{intent}' was not YES/NO "
|
||||
f"(got: '{response[:80]}...'). Falling through to structural verification."
|
||||
)
|
||||
|
||||
@@ -399,11 +399,6 @@ class ScreenIdentity:
|
||||
|
||||
desc_text = " ".join(content_descs)
|
||||
|
||||
# Username on profile
|
||||
username_match = re.search(r"(\w+)'s (?:profile|story|unseen story)", desc_text)
|
||||
if username_match:
|
||||
context["username"] = username_match.group(1)
|
||||
|
||||
# Post/follower counts
|
||||
for d in content_descs:
|
||||
m = re.match(r"([\d,.]+K?M?)(\s*)(posts?|followers?|following)", d, re.IGNORECASE)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
import math
|
||||
import random
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
from colorama import Fore
|
||||
@@ -108,15 +109,11 @@ class ResonanceEngine:
|
||||
"""
|
||||
username = post_content.get("username", "Unknown")
|
||||
description = post_content.get("description", "")
|
||||
caption = post_content.get("caption", "")
|
||||
|
||||
logger.info(f"✨ [Resonance Oracle] Evaluating content from @{username}...", extra={"color": f"{Fore.MAGENTA}"})
|
||||
|
||||
# Build a rich text representation of the post
|
||||
|
||||
description = post_content.get("description", "")
|
||||
caption = post_content.get("caption", "")
|
||||
username = post_content.get("username", "")
|
||||
|
||||
content_text = " ".join(filter(None, [description, caption])).strip()
|
||||
|
||||
if not content_text or len(content_text) < 5:
|
||||
@@ -218,7 +215,7 @@ class ResonanceEngine:
|
||||
]
|
||||
|
||||
text_lower = text.lower()
|
||||
if any(f" {word} " in f" {text_lower} " for word in tragic_keywords):
|
||||
if any(re.search(rf"\b{re.escape(word)}\b", text_lower) for word in tragic_keywords):
|
||||
logger.warning(
|
||||
"🛡️ [Empathy Filter] Tragic/Sensitive content detected. Suppressing resonance to prevent blind liking."
|
||||
)
|
||||
|
||||
@@ -62,13 +62,25 @@ class ScreenTopology:
|
||||
"press back": ScreenType.HOME_FEED,
|
||||
},
|
||||
ScreenType.OTHER_PROFILE: {
|
||||
"press back": ScreenType.HOME_FEED,
|
||||
"tap home tab": ScreenType.HOME_FEED,
|
||||
"tap explore tab": ScreenType.EXPLORE_GRID,
|
||||
"tap reels tab": ScreenType.REELS_FEED,
|
||||
"tap profile tab": ScreenType.OWN_PROFILE,
|
||||
},
|
||||
ScreenType.POST_DETAIL: {
|
||||
"tap home tab": ScreenType.HOME_FEED,
|
||||
"tap explore tab": ScreenType.EXPLORE_GRID,
|
||||
"tap profile tab": ScreenType.OWN_PROFILE,
|
||||
"tap reels tab": ScreenType.REELS_FEED,
|
||||
"tap view all comments": ScreenType.COMMENTS,
|
||||
"press back": ScreenType.EXPLORE_GRID, # Default fallback if unknown source
|
||||
},
|
||||
ScreenType.COMMENTS: {
|
||||
"press back": ScreenType.POST_DETAIL,
|
||||
},
|
||||
ScreenType.SEARCH_RESULTS: {
|
||||
"tap home tab": ScreenType.HOME_FEED,
|
||||
"press back": ScreenType.EXPLORE_GRID,
|
||||
},
|
||||
ScreenType.UNKNOWN: {
|
||||
"tap home tab": ScreenType.HOME_FEED,
|
||||
@@ -94,6 +106,8 @@ class ScreenTopology:
|
||||
"view the user profile": ScreenType.OTHER_PROFILE,
|
||||
"view user profile": ScreenType.OTHER_PROFILE,
|
||||
"open user profile": ScreenType.OTHER_PROFILE,
|
||||
"open search": ScreenType.SEARCH_RESULTS,
|
||||
"view comments": ScreenType.COMMENTS,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
|
||||
40
tests/core/test_topology_completeness.py
Normal file
40
tests/core/test_topology_completeness.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
P2-9 & P2-10: ScreenTopology Completeness
|
||||
|
||||
TDD RED: These tests enforce that:
|
||||
1. COMMENTS and SEARCH_RESULTS screens are reachable in the graph.
|
||||
2. OTHER_PROFILE transitions are deterministic (no "press back" to HOME_FEED).
|
||||
3. The pathfinder can find routes to these critical screens.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from GramAddict.core.screen_topology import ScreenTopology
|
||||
from GramAddict.core.goap import ScreenType
|
||||
|
||||
class TestTopologyCompleteness:
|
||||
def test_comments_reachability(self):
|
||||
"""RED: Pathfinder should find a route FROM COMMENTS back to HOME_FEED."""
|
||||
# This requires COMMENTS to have a transition back to somewhere reachable
|
||||
route = ScreenTopology.find_route(ScreenType.COMMENTS, ScreenType.HOME_FEED)
|
||||
assert route is not None
|
||||
assert "press back" in [step[0] for step in route]
|
||||
|
||||
def test_search_results_reachability(self):
|
||||
"""RED: Pathfinder should find a route FROM SEARCH_RESULTS back to HOME_FEED."""
|
||||
route = ScreenTopology.find_route(ScreenType.SEARCH_RESULTS, ScreenType.HOME_FEED)
|
||||
assert route is not None
|
||||
|
||||
def test_other_profile_to_home_is_not_back(self):
|
||||
"""RED: Moving from OTHER_PROFILE to HOME_FEED should NOT use 'press back'."""
|
||||
route = ScreenTopology.find_route(ScreenType.OTHER_PROFILE, ScreenType.HOME_FEED)
|
||||
assert route is not None
|
||||
steps = [step[0] for step in route]
|
||||
# 'press back' is forbidden for this transition because it's non-deterministic
|
||||
assert "press back" not in steps
|
||||
assert "tap home tab" in steps
|
||||
|
||||
def test_goal_map_contains_missing_screens(self):
|
||||
"""RED: Goals like 'open search' should map to SEARCH_RESULTS."""
|
||||
# Note: SEARCH_RESULTS might be reached via 'tap explore tab' + 'tap search bar'
|
||||
# but the goal should still be valid.
|
||||
assert ScreenTopology.goal_to_target_screen("open search") == ScreenType.SEARCH_RESULTS
|
||||
Reference in New Issue
Block a user