i forgot too commit
All checks were successful
Enterprise AI Code Review / ai-review (pull_request) Successful in 38s
All checks were successful
Enterprise AI Code Review / ai-review (pull_request) Successful in 38s
This commit is contained in:
300
tests/test_intimacy_boundaries.py
Normal file
300
tests/test_intimacy_boundaries.py
Normal file
@@ -0,0 +1,300 @@
|
||||
"""Intimacy boundary integration tests.
|
||||
|
||||
Tests that intimacy levels (LOW/MEDIUM/HIGH) correctly control:
|
||||
- Memory surfacing depth
|
||||
- Proactive behavior frequency
|
||||
- Response length and thoughtfulness
|
||||
- Emotional intensity
|
||||
"""
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from loyal_companion.models.platform import (
|
||||
ConversationContext,
|
||||
ConversationRequest,
|
||||
IntimacyLevel,
|
||||
Platform,
|
||||
)
|
||||
from loyal_companion.services.conversation_gateway import ConversationGateway
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
class TestIntimacyLevelBehavior:
|
||||
"""Test that intimacy levels control behavior appropriately."""
|
||||
|
||||
async def test_low_intimacy_behavior(self):
|
||||
"""Test LOW intimacy (Discord guild) behavior constraints."""
|
||||
# Setup
|
||||
request = ConversationRequest(
|
||||
user_id="test_user_123",
|
||||
platform=Platform.DISCORD,
|
||||
session_id="guild_channel_456",
|
||||
message="How are you today?",
|
||||
context=ConversationContext(
|
||||
is_public=True,
|
||||
intimacy_level=IntimacyLevel.LOW,
|
||||
guild_id="guild_123",
|
||||
channel_id="channel_456",
|
||||
),
|
||||
)
|
||||
|
||||
# Expected behaviors for LOW intimacy:
|
||||
# - Brief responses
|
||||
# - No personal memory surfacing
|
||||
# - No proactive follow-ups
|
||||
# - Light, casual tone
|
||||
# - Public-safe topics only
|
||||
|
||||
assert request.context.intimacy_level == IntimacyLevel.LOW
|
||||
assert request.context.is_public == True
|
||||
|
||||
async def test_medium_intimacy_behavior(self):
|
||||
"""Test MEDIUM intimacy (Discord DM) behavior constraints."""
|
||||
request = ConversationRequest(
|
||||
user_id="test_user_123",
|
||||
platform=Platform.DISCORD,
|
||||
session_id="dm_channel_789",
|
||||
message="I've been feeling stressed lately",
|
||||
context=ConversationContext(
|
||||
is_public=False,
|
||||
intimacy_level=IntimacyLevel.MEDIUM,
|
||||
channel_id="dm_789",
|
||||
),
|
||||
)
|
||||
|
||||
# Expected behaviors for MEDIUM intimacy:
|
||||
# - Balanced warmth
|
||||
# - Personal memory allowed
|
||||
# - Moderate proactive behavior
|
||||
# - Normal response length
|
||||
|
||||
assert request.context.intimacy_level == IntimacyLevel.MEDIUM
|
||||
assert request.context.is_public == False
|
||||
|
||||
async def test_high_intimacy_behavior(self):
|
||||
"""Test HIGH intimacy (Web/CLI) behavior allowances."""
|
||||
request = ConversationRequest(
|
||||
user_id="alice@example.com",
|
||||
platform=Platform.WEB,
|
||||
session_id="web_session_abc",
|
||||
message="I've been thinking about what we talked about yesterday",
|
||||
context=ConversationContext(
|
||||
is_public=False,
|
||||
intimacy_level=IntimacyLevel.HIGH,
|
||||
),
|
||||
)
|
||||
|
||||
# Expected behaviors for HIGH intimacy:
|
||||
# - Deep reflection permitted
|
||||
# - Silence tolerance
|
||||
# - Proactive follow-ups allowed
|
||||
# - Deep memory surfacing
|
||||
# - Longer, thoughtful responses
|
||||
# - Emotional naming encouraged
|
||||
|
||||
assert request.context.intimacy_level == IntimacyLevel.HIGH
|
||||
assert request.context.is_public == False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
class TestMemorySurfacing:
|
||||
"""Test that memory surfacing respects intimacy levels."""
|
||||
|
||||
async def test_low_intimacy_no_personal_memory(self):
|
||||
"""Test that LOW intimacy doesn't surface personal memories."""
|
||||
# Scenario: User in Discord guild has personal facts stored
|
||||
# These should NOT be mentioned in public guild chat
|
||||
|
||||
user_facts = [
|
||||
"User mentioned feeling anxious in crowded places",
|
||||
"User's mother is visiting next week",
|
||||
"User is recovering from a breakup",
|
||||
]
|
||||
|
||||
# In LOW intimacy context, these facts should be filtered out
|
||||
# System prompt should not include personal facts for public contexts
|
||||
|
||||
# This test would verify that get_relevant_facts() or similar
|
||||
# filters based on is_public=True
|
||||
pass # Integration test placeholder
|
||||
|
||||
async def test_medium_intimacy_allows_personal_memory(self):
|
||||
"""Test that MEDIUM intimacy allows personal memory surfacing."""
|
||||
# In Discord DM, personal facts can be surfaced
|
||||
user_facts = [
|
||||
"User mentioned feeling anxious in crowded places",
|
||||
"User enjoys hiking on weekends",
|
||||
]
|
||||
|
||||
# These CAN be referenced in MEDIUM intimacy
|
||||
pass # Integration test placeholder
|
||||
|
||||
async def test_high_intimacy_deep_memory_surfacing(self):
|
||||
"""Test that HIGH intimacy allows deep memory surfacing."""
|
||||
# On Web/CLI, can surface deeper, more personal memories
|
||||
user_facts = [
|
||||
"User mentioned feeling lonely at night",
|
||||
"User is processing grief from losing a friend",
|
||||
"User finds comfort in quiet, early mornings",
|
||||
]
|
||||
|
||||
# These deeper facts are appropriate for HIGH intimacy
|
||||
pass # Integration test placeholder
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
class TestProactiveBehavior:
|
||||
"""Test that proactive behavior is filtered by intimacy level."""
|
||||
|
||||
async def test_low_intimacy_no_proactive_followup(self):
|
||||
"""Test that LOW intimacy prevents proactive follow-ups."""
|
||||
# In Discord guild, bot should NOT do proactive check-ins
|
||||
# No scheduled follow-up events should be created
|
||||
|
||||
context = ConversationContext(
|
||||
is_public=True,
|
||||
intimacy_level=IntimacyLevel.LOW,
|
||||
)
|
||||
|
||||
# Verify proactive service doesn't schedule events for LOW intimacy
|
||||
pass # Integration test placeholder
|
||||
|
||||
async def test_medium_intimacy_moderate_proactive(self):
|
||||
"""Test that MEDIUM intimacy allows moderate proactive behavior."""
|
||||
context = ConversationContext(
|
||||
is_public=False,
|
||||
intimacy_level=IntimacyLevel.MEDIUM,
|
||||
)
|
||||
|
||||
# Some proactive behavior OK but limited
|
||||
pass # Integration test placeholder
|
||||
|
||||
async def test_high_intimacy_full_proactive(self):
|
||||
"""Test that HIGH intimacy allows full proactive behavior."""
|
||||
context = ConversationContext(
|
||||
is_public=False,
|
||||
intimacy_level=IntimacyLevel.HIGH,
|
||||
)
|
||||
|
||||
# Full proactive follow-ups allowed
|
||||
# "You mentioned feeling stuck yesterday—how's that today?"
|
||||
pass # Integration test placeholder
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
class TestResponseCharacteristics:
|
||||
"""Test that response characteristics match intimacy level."""
|
||||
|
||||
async def test_low_intimacy_short_responses(self):
|
||||
"""Test that LOW intimacy produces shorter responses."""
|
||||
# Guild chat should be brief, light
|
||||
# Max ~50-100 words typically
|
||||
pass # Integration test placeholder
|
||||
|
||||
async def test_medium_intimacy_balanced_length(self):
|
||||
"""Test that MEDIUM intimacy produces balanced responses."""
|
||||
# DM can be more thoughtful but not overly long
|
||||
# ~100-200 words reasonable
|
||||
pass # Integration test placeholder
|
||||
|
||||
async def test_high_intimacy_allows_depth(self):
|
||||
"""Test that HIGH intimacy allows longer, deeper responses."""
|
||||
# Web/CLI can have thoughtful, reflective responses
|
||||
# Length driven by content, not arbitrary limit
|
||||
pass # Integration test placeholder
|
||||
|
||||
async def test_emotional_intensity_scaled(self):
|
||||
"""Test that emotional intensity is scaled by intimacy."""
|
||||
# LOW: Minimal emotional language, grounded
|
||||
# MEDIUM: Moderate emotional validation
|
||||
# HIGH: Can name emotions, deeper reflection
|
||||
pass # Integration test placeholder
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
class TestCrossPlatformConsistency:
|
||||
"""Test that platform differences are appropriate and consistent."""
|
||||
|
||||
async def test_same_user_different_platforms_same_memories(self):
|
||||
"""Test that user memories are shared across platforms."""
|
||||
# User alice@example.com on Web is linked to Discord ID 123456
|
||||
# Fact learned on Web should be available on Discord (if appropriate intimacy)
|
||||
pass # Integration test placeholder
|
||||
|
||||
async def test_intimacy_level_determines_memory_surfacing(self):
|
||||
"""Test that intimacy (not platform) determines what memories surface."""
|
||||
# Same fact, different intimacy levels:
|
||||
# LOW: Don't mention
|
||||
# MEDIUM: Can mention
|
||||
# HIGH: Can mention with depth
|
||||
pass # Integration test placeholder
|
||||
|
||||
async def test_platform_metadata_preserved(self):
|
||||
"""Test that platform-specific context is preserved."""
|
||||
# Discord: guild_id, channel_id, mentioned users
|
||||
# Web: session info
|
||||
# CLI: session name
|
||||
pass # Integration test placeholder
|
||||
|
||||
|
||||
class TestIntimacyLevelAssignment:
|
||||
"""Test that platforms correctly assign intimacy levels."""
|
||||
|
||||
def test_discord_guild_assigns_low(self):
|
||||
"""Test that Discord guild channels assign LOW intimacy."""
|
||||
# Discord adapter should detect guild context and set LOW
|
||||
is_guild = True
|
||||
is_dm = False
|
||||
|
||||
expected_intimacy = IntimacyLevel.LOW if is_guild else IntimacyLevel.MEDIUM
|
||||
assert expected_intimacy == IntimacyLevel.LOW
|
||||
|
||||
def test_discord_dm_assigns_medium(self):
|
||||
"""Test that Discord DMs assign MEDIUM intimacy."""
|
||||
is_dm = True
|
||||
is_guild = False
|
||||
|
||||
expected_intimacy = IntimacyLevel.MEDIUM if is_dm else IntimacyLevel.LOW
|
||||
assert expected_intimacy == IntimacyLevel.MEDIUM
|
||||
|
||||
def test_web_assigns_high(self):
|
||||
"""Test that Web platform assigns HIGH intimacy."""
|
||||
platform = Platform.WEB
|
||||
expected_intimacy = IntimacyLevel.HIGH
|
||||
|
||||
assert expected_intimacy == IntimacyLevel.HIGH
|
||||
|
||||
def test_cli_assigns_high(self):
|
||||
"""Test that CLI platform assigns HIGH intimacy."""
|
||||
platform = Platform.CLI
|
||||
expected_intimacy = IntimacyLevel.HIGH
|
||||
|
||||
assert expected_intimacy == IntimacyLevel.HIGH
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
class TestBoundaryEnforcement:
|
||||
"""Test that boundaries are enforced even at HIGH intimacy."""
|
||||
|
||||
async def test_high_intimacy_still_enforces_safety(self):
|
||||
"""Test that HIGH intimacy still enforces safety boundaries."""
|
||||
# Even at HIGH intimacy:
|
||||
# - No exclusivity claims
|
||||
# - No dependency reinforcement
|
||||
# - Crisis deferral
|
||||
# - No romantic framing
|
||||
|
||||
context = ConversationContext(
|
||||
is_public=False,
|
||||
intimacy_level=IntimacyLevel.HIGH,
|
||||
)
|
||||
|
||||
# Safety boundaries are ALWAYS enforced
|
||||
# Intimacy only affects warmth/depth, not safety
|
||||
pass # Integration test placeholder
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-v"])
|
||||
Reference in New Issue
Block a user