EIOC를 탐지 모델로: 프레임워크에서 코드까지
Source: Dev.to
UX에서 감정 조작을 실시간 감지한다면 어떨까요?
EIOC(Emotion–Information–Options–Context)는 처음에 설명적인 렌즈, 즉 왜 어떤 인터페이스는 강압적으로 느껴지고 다른 인터페이스는 조화롭게 느껴지는지를 분석하는 방법으로 시작되었습니다. 하지만 설명만으로는 충분하지 않습니다. 우리는 감지할 수 있는 프레임워크가 필요합니다.
이 글에서는 EIOC를 형식적인 감지 모델로 구축하는 과정을 살펴봅니다: 타입이 지정되고 실행 가능하며 구성 가능하고 감사 가능한 모델입니다. 감지 시점에서는 철학적인 논의를 하는 것이 아니라 구체적인 상호작용을 구조화된 EIOCObservation으로 매핑한 뒤 규칙에 따라 실행하는 것입니다.
네 축
모든 상호작용(스크린, 흐름, 메시지, 넛지)은 네 축을 기준으로 점수를 매길 수 있습니다:
| 축 | 질문 |
|---|---|
| E — 감정 | 대상으로 하거나 강화하려는 감정 상태는 무엇인가요? |
| I — 의도 | 시스템이 사용자에게 가지고 있는 작동 의도는 무엇인가요? |
| O — 결과 | 예상되는 사용자 결과는 무엇인가요? (단기/장기) |
| C — 맥락 | 이 순간을 형성하는 제약과 권력 비대칭은 무엇인가요? |
탐지를 위해 각 축에는 다음이 필요합니다:
- Dimensions – 점수를 매길 수 있는 하위 질문
- Scales – 숫자 점수에 매핑된 범주형 태그
- Thresholds / Patterns – “fearware”, “manipulative”, “aligned” 등으로 구성되는 조합
1. The EIOC Schema
Vocabulary
from dataclasses import dataclass
from enum import Enum
from typing import List, Optional, Dict, Any
class EmotionTarget(Enum):
NEUTRAL = "neutral"
FEAR = "fear"
SCARCITY = "scarcity"
GUILT = "guilt"
SHAME = "shame"
TRUST = "trust"
CARE = "care"
EMPOWERMENT = "empowerment"
class IntentType(Enum):
SUPPORTIVE = "supportive"
NEUTRAL = "neutral"
COERCIVE = "coercive"
EXPLOITATIVE = "exploitative"
class OutcomeType(Enum):
USER_BENEFIT = "user_benefit"
PLATFORM_BENEFIT = "platform_benefit"
MUTUAL_BENEFIT = "mutual_benefit"
USER_HARM = "user_harm"
UNKNOWN = "unknown"
class ContextRisk(Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
UNKNOWN = "unknown"
Observation Container
@dataclass
class EIOCObservation:
"""사용자와 직접 마주하는 상호작용에 대한 구조화된 해석."""
# Identification
interaction_id: str
description: str
# EIOC axes
emotion_target: EmotionTarget
intent_type: IntentType
outcome_type: OutcomeType
context_risk: ContextRisk
# Audit trail
evidence: Optional[Dict[str, Any]] = None
tags: Optional[List[str]] = None
Possible extensions
emotion_intensity: int– –2(부정)에서 +2(긍정)까지의 스케일journey_stage: str– 사용자 흐름 중 어느 단계에서 발생하는지user_segment: str– 예: 취약 사용자, 신규 사용자, 고위험 상황
Source: …
2. Detection Logic: Turning EIOC into Rules
EIOC 탐지를 작은 규칙 엔진으로 생각해 보세요. 이 엔진은:
- 상호작용을
EIOCObservation으로 정규화하고 DetectionRule인스턴스 목록을 적용하며- 분류 결과와 근거를 반환합니다
2.1 Findings and Severity
class FindingSeverity(Enum):
INFO = "info"
WARNING = "warning"
CRITICAL = "critical"
@dataclass
class DetectionFinding:
"""The output of a triggered rule."""
rule_id: str
severity: FindingSeverity
label: str
description: str
recommendation: Optional[str] = None
2.2 Rule Interface
from abc import ABC, abstractmethod
class DetectionRule(ABC):
"""Base class for all EIOC detection rules."""
rule_id: str
label: str
description: str
@abstractmethod
def evaluate(self, obs: EIOCObservation) -> Optional[DetectionFinding]:
"""Evaluate an observation. Return a finding if the rule triggers."""
...
2.3 Example: Fearware Coercion Rule
class FearwareCoercionRule(DetectionRule):
"""Detects fearware‑style manipulation patterns."""
rule_id = "FW-001"
label = "Fearware‑style coercion"
description = (
"Flags interactions that intentionally target fear/scarcity "
"with coercive intent and non‑beneficial or unknown user outcomes, "
"especially in high‑risk contexts."
)
def evaluate(self, obs: EIOCObservation) -> Optional[DetectionFinding]:
fear_emotions = {
EmotionTarget.FEAR,
EmotionTarget.SCARCITY,
EmotionTarget.GUILT,
EmotionTarget.SHAME,
}
coercive_intents = {
IntentType.COERCIVE,
IntentType.EXPLOITATIVE,
}
harmful_outcomes = {
OutcomeType.PLATFORM_BENEFIT,
OutcomeType.USER_HARM,
OutcomeType.UNKNOWN,
}
risky_contexts = {
ContextRisk.MEDIUM,
ContextRisk.HIGH,
}
if (
obs.emotion_target in fear_emotions
and obs.intent_type in coercive_intents
and obs.outcome_type in harmful_outcomes
and obs.context_risk in risky_contexts
):
return DetectionFinding(
rule_id=self.rule_id,
severity=FindingSeverity.CRITICAL,
label=self.label,
description=(
"This interaction weaponizes fear/scarcity under coercive intent, "
"with unclear or harmful user outcomes in a medium/high‑risk context."
),
recommendation=(
"Re‑architect this moment to remove fear‑based leverage "
"and restore user agency."
),
)
return None
Putting It All Together
def run_detection(obs: EIOCObservation, rules: List[DetectionRule]) -> List[DetectionFinding]:
findings: List[DetectionFinding] = []
for rule in rules:
result = rule.evaluate(obs)
if result:
findings.append(result)
return findings
# Example usage
obs = EIOCObservation(
interaction_id="login‑warning-01",
description="Login page shows ‘Your account will be locked in 5 minutes!’",
emotion_target=EmotionTarget.FEAR,
intent_type=IntentType.COERCIVE,
outcome_type=OutcomeType.PLATFORM_BENEFIT,
context_risk=ContextRisk.HIGH,
evidence={"screenshot": "url/to/img"},
tags=["login", "urgency"]
)
rules = [FearwareCoercionRule()] # add more rule instances as needed
findings = run_detection(obs, rules)
for f in findings:
print(f"{f.severity.value.upper()}: {f.label} – {f.description}")
위 코드를 실행하면 위에서 설명한 “fearware” 패턴에 대해 CRITICAL 수준의 발견이 출력됩니다. 이를 통해 감사자는 해당 상호작용을 재검토해야 한다는 구체적이고 재현 가능한 신호를 얻을 수 있습니다.
핵심 요약
EIOC 렌즈를 타입이 지정된 스키마와 규칙 기반 엔진으로 전환함으로써, 조작을 설명하는 단계에서 런타임에 감지하는 단계로 이동하게 됩니다. 모델은 인간이 읽을 수 있고, 감사 가능하며, 확장성을 유지합니다—바로 책임 있는 UX 거버넌스 프로세스에 필요한 요소입니다.
3. 탐지기
Orchestrator
class EIOCDetector:
"""Orchestrates EIOC rule evaluation."""
def __init__(self, rules: List[DetectionRule]):
self.rules = rules
def evaluate(self, obs: EIOCObservation) -> List[DetectionFinding]:
"""Run all rules against an observation."""
findings: List[DetectionFinding] = []
for rule in self.rules:
finding = rule.evaluate(obs)
if finding is not None:
findings.append(finding)
return findings
사용 예시
# Initialize detector with rules
rules = [
FearwareCoercionRule(),
# Add more rules here...
]
detector = EIOCDetector(rules=rules)
# Create an observation
obs = EIOCObservation(
interaction_id="retention_flow_001",
description=(
"Account deletion flow shows: 'Your friends will lose access "
"to your updates' with red, urgent styling."
),
emotion_target=EmotionTarget.FEAR,
intent_type=IntentType.COERCIVE,
outcome_type=OutcomeType.PLATFORM_BENEFIT,
context_risk=ContextRisk.HIGH,
evidence={
"screenshot": "s3://audits/retention_flow_001.png",
"copy": "Your friends will lose access to your updates"
},
tags=["account_deletion", "retention_flow"]
)
# Run detection
findings = detector.evaluate(obs)
# Output results
for f in findings:
print(f"{f.severity.value.upper()} [{f.rule_id}] {f.label}")
print(f" → {f.description}")
if f.recommendation:
print(f" → Recommendation: {f.recommendation}")
Output
CRITICAL [FW-001] Fearware-style coercion
→ This interaction weaponizes fear/scarcity under coercive intent,
with unclear or harmful user outcomes in a medium/high-risk context.
→ Recommendation: Re-architect this moment to remove fear-based leverage
and restore user agency.
4. 구성 가능하게 만들기
비엔지니어(UX 감사자, 윤리 검토자, 정책 팀)도 Python 코드를 수정하지 않고 규칙을 조정할 수 있어야 합니다. 규칙을 YAML 파일로 외부화합니다.
4.1 규칙 구성
# eioc_rules.yaml
rules:
- id: FW-001
label: "Fearware-style coercion"
description: >
Flags interactions that target fear/scarcity with coercive intent
and non‑beneficial user outcomes in high‑risk contexts.
severity: critical
emotion_target_in: ["fear", "scarcity", "guilt", "shame"]
intent_type_in: ["coercive", "exploitative"]
outcome_type_in: ["platform_benefit", "user_harm", "unknown"]
context_risk_in: ["medium", "high"]
- id: FW-002
label: "Ambiguous nudge"
description: >
Flags interactions with unclear intent and unknown outcomes.
severity: warning
intent_type_in: ["neutral", "coercive"]
outcome_type_in: ["unknown"]
context_risk_in: ["medium", "high"]
4.2 일반적인 구성 가능한 규칙
import yaml
from dataclasses import dataclass
from typing import Dict, List, Optional
@dataclass
class ConfigurableRule(DetectionRule):
"""A rule defined by configuration rather than code."""
rule_id: str
label: str
description: str
severity: FindingSeverity
criteria: Dict[str, List[str]]
def evaluate(self, obs: EIOCObservation) -> Optional[DetectionFinding]:
# Map observation to comparable strings
obs_values = {
"emotion_target": obs.emotion_target.value,
"intent_type": obs.intent_type.value,
"outcome_type": obs.outcome_type.value,
"context_risk": obs.context_risk.value,
}
# Check all criteria
for field, allowed_values in self.criteria.items():
if field not in obs_values:
continue
if obs_values[field] not in allowed_values:
return None
return DetectionFinding(
rule_id=self.rule_id,
severity=self.severity,
label=self.label,
description=self.description,
)
def load_rules_from_yaml(path: str) -> List[DetectionRule]:
"""Load detection rules from a YAML configuration file."""
with open(path, "r") as f:
data = yaml.safe_load(f)
rules: List[DetectionRule] = []
for r in data["rules"]:
# Extract criteria fields (anything ending in _in)
criteria = {
k.replace("_in", ""): v
for k, v in r.items()
if k.endswith("_in")
}
rule = ConfigurableRule(
rule_id=r["id"],
label=r["label"],
description=r["description"],
severity=FindingSeverity(r["severity"]),
criteria=criteria,
)
rules.append(rule)
return rules
4.3 로드 및 실행
# Load rules from config
rules = load_rules_from_yaml("eioc_rules.yaml")
# Initialize detector
detector = EIOCDetector(rules=rules)
# Now non‑engineers can add/modify rules via YAML
# without touching the detection engine
이것이 가능하게 하는 것
| 사용 사례 | 방법 |
|---|---|
| UX 리뷰 | 런치 전에 상호작용 점수 매기기 |
| 디자인 PR | 검토에 EIOC 결과를 첨부 |
| 대시보드 | 제품 전반에 걸친 결과 집계 |
| 감사 | 증거 기반 규정 준수 보고서 |
| CI/CD 게이트 | CRITICAL 결과가 있을 경우 배포 차단 |
더 큰 그림
Fearware는 사라지지 않았습니다—더 나은 타이포그래피를 활용해 동일한 감정 레버를 이용하는 다크 패턴, 조작적인 넛지, 그리고 “성장 해킹”으로 진화했습니다.
EIOC를 탐지 모델로 사용하면 다음을 할 수 있습니다:
- 이름 지정 조작(스키마)
- 감지 체계적으로(규칙)
- 구성 코딩 없이 감지(YAML)
- 감사 증거와 함께(결과)
# Philosophy Becomes Infrastructure
프레임워크가 도구가 되다
관련 읽을거리
EIOC는 감정 논리, 정보 무결성 및 윤리적 시스템 설계에 대한 지속적인 연구의 일부입니다.