chore: FSD stabilization, strict TDD enforcement, and unlearn mechanism

- implemented self-healing unlearn for Qdrant false positives
- centralized testing logic in conftest
- documented core rules, ai standards, and goap philosophy
- purged old dev scratchpads
This commit is contained in:
2026-04-24 13:28:32 +02:00
parent 75009d91a2
commit 30724d3c03
196 changed files with 8519 additions and 1595 deletions

View File

View File

@@ -0,0 +1,208 @@
"""
Property-Based Tests: Hypothesis-driven invariant verification.
These tests verify UNIVERSAL PROPERTIES that must hold for ANY input,
not just specific examples. Think of them as mathematical proofs of correctness.
Tesla validates that steering never exceeds max torque for ANY speed —
we validate that scroll never exceeds screen bounds for ANY device size.
"""
import pytest
import re
from hypothesis import given, strategies as st, settings, assume
from tests.chaos import VALID_FEED_XML
# ──────────────────────────────────────────────────
# XML Parsing Properties
# ──────────────────────────────────────────────────
@pytest.mark.property
class TestXMLParsingProperties:
"""Universal properties of the XML extraction pipeline."""
@given(
text=st.text(min_size=0, max_size=200),
desc=st.text(min_size=0, max_size=200),
)
@settings(max_examples=100)
def test_extracted_nodes_always_have_valid_coordinates(self, text, desc):
"""PROPERTY: Any extracted node must have integer x, y >= 0."""
from unittest.mock import MagicMock, patch
# Escape XML special chars
safe_text = text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace('"', "&quot;").replace("'", "&apos;")
safe_desc = desc.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace('"', "&quot;").replace("'", "&apos;")
xml = (
f'<hierarchy rotation="0">'
f'<node index="0" text="{safe_text}" '
f'resource-id="com.instagram.android:id/test_button" '
f'class="android.widget.Button" '
f'package="com.instagram.android" '
f'content-desc="{safe_desc}" '
f'clickable="true" '
f'bounds="[100,200][300,400]" />'
f'</hierarchy>'
)
with patch("GramAddict.core.qdrant_memory.QdrantBase.__init__", return_value=None), \
patch("GramAddict.core.qdrant_memory.QdrantBase.is_connected", new_callable=lambda: property(lambda self: False)):
from GramAddict.core.telepathic_engine import TelepathicEngine
TelepathicEngine._instance = None
engine = TelepathicEngine.__new__(TelepathicEngine)
engine.ui_memory = MagicMock()
engine.ui_memory.is_connected = False
engine.positive_memory = MagicMock()
engine.positive_memory.is_connected = False
engine._edge_model = None
engine._edge_tokenizer = None
try:
nodes = engine._extract_semantic_nodes(xml)
except Exception:
# If the generated text breaks XML parsing, that's OK —
# the parser should return empty list, not crash
nodes = []
for node in nodes:
assert isinstance(node["x"], int)
assert isinstance(node["y"], int)
assert node["x"] >= 0
assert node["y"] >= 0
TelepathicEngine._instance = None
@given(
left=st.integers(min_value=0, max_value=1080),
top=st.integers(min_value=0, max_value=2400),
width=st.integers(min_value=1, max_value=500),
height=st.integers(min_value=1, max_value=500),
)
@settings(max_examples=200)
def test_center_calculation_always_within_bounds(self, left, top, width, height):
"""PROPERTY: Calculated center must lie within the bounding rectangle."""
right = min(left + width, 2160)
bottom = min(top + height, 3200)
center_x = (left + right) // 2
center_y = (top + bottom) // 2
assert left <= center_x <= right
assert top <= center_y <= bottom
# ──────────────────────────────────────────────────
# SAE Compression Properties
# ──────────────────────────────────────────────────
@pytest.mark.property
class TestSAECompressionProperties:
"""Universal properties of XML compression."""
@given(
n_nodes=st.integers(min_value=0, max_value=200),
)
@settings(max_examples=30, deadline=None)
def test_compression_output_bounded(self, n_nodes):
"""PROPERTY: Compressed output must ALWAYS be <= 3000 characters."""
from unittest.mock import MagicMock
from GramAddict.core.situational_awareness import SituationalAwarenessEngine
SituationalAwarenessEngine.reset()
device = MagicMock()
device.deviceV2 = MagicMock()
device.deviceV2.info = {"screenOn": True}
sae = SituationalAwarenessEngine(device)
# Generate XML with n_nodes
parts = ['<hierarchy rotation="0">']
for i in range(n_nodes):
parts.append(
f'<node index="{i}" text="item_{i}" '
f'resource-id="com.instagram.android:id/element_{i}" '
f'class="android.widget.TextView" '
f'package="com.instagram.android" '
f'clickable="true" bounds="[0,{i*50}][100,{i*50+40}]" />'
)
parts.append('</hierarchy>')
xml = "".join(parts)
result = sae._compress_xml(xml)
assert len(result) <= 3000
SituationalAwarenessEngine.reset()
@given(
text1=st.text(alphabet="abcdefghijklmnopqrstuvwxyz", min_size=5, max_size=50),
text2=st.text(alphabet="abcdefghijklmnopqrstuvwxyz", min_size=5, max_size=50),
)
@settings(max_examples=50)
def test_different_inputs_produce_different_hashes(self, text1, text2):
"""PROPERTY: Distinct inputs should (almost always) produce distinct hashes."""
assume(text1 != text2)
from unittest.mock import MagicMock
from GramAddict.core.situational_awareness import SituationalAwarenessEngine
SituationalAwarenessEngine.reset()
device = MagicMock()
device.deviceV2 = MagicMock()
device.deviceV2.info = {"screenOn": True}
sae = SituationalAwarenessEngine(device)
hash1 = sae._compute_situation_hash(text1)
hash2 = sae._compute_situation_hash(text2)
assert hash1 != hash2
SituationalAwarenessEngine.reset()
# ──────────────────────────────────────────────────
# Active Inference Properties
# ──────────────────────────────────────────────────
@pytest.mark.property
class TestActiveInferenceProperties:
"""Universal properties of the Active Inference engine."""
@given(
predicted=st.floats(min_value=0.0, max_value=1.0),
observed=st.floats(min_value=0.0, max_value=1.0),
)
@settings(max_examples=100)
def test_free_energy_always_non_negative(self, predicted, observed):
"""PROPERTY: Free energy must NEVER go negative."""
from GramAddict.core.active_inference import ActiveInferenceEngine
ai = ActiveInferenceEngine("test_user")
result = ai.calculate_surprise(predicted, observed)
assert result >= 0.0
@given(
predicted=st.floats(min_value=0.0, max_value=1.0),
observed=st.floats(min_value=0.0, max_value=1.0),
)
@settings(max_examples=100)
def test_policy_always_valid(self, predicted, observed):
"""PROPERTY: Policy must always be one of the valid states."""
from GramAddict.core.active_inference import ActiveInferenceEngine
ai = ActiveInferenceEngine("test_user")
ai.calculate_surprise(predicted, observed)
assert ai.policy in ("STABLE", "CAUTIOUS", "DORMANT")
@given(
modifier_count=st.integers(min_value=1, max_value=50),
)
@settings(max_examples=20)
def test_sleep_modifier_always_bounded(self, modifier_count):
"""PROPERTY: Sleep modifier must always be in [1.0, 5.0] range."""
from GramAddict.core.active_inference import ActiveInferenceEngine
ai = ActiveInferenceEngine("test_user")
for _ in range(modifier_count):
ai.calculate_surprise(1.0, 0.0) # Max surprise
mod = ai.get_sleep_modifier()
assert 1.0 <= mod <= 5.0