feat(core): finalize P2 & P3 hardening - Topology HD Map, Empathy Filter, and Git Hygiene

This commit is contained in:
2026-05-04 15:03:42 +02:00
parent 79e5784b93
commit 22216cbd2d
8 changed files with 64 additions and 20 deletions

5
.gitignore vendored
View File

@@ -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/

View File

@@ -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)

View File

@@ -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

View File

@@ -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."
)

View File

@@ -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)

View File

@@ -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."
)

View File

@@ -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

View 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