"""Synthetic user personas for simulation.""" import math from dataclasses import dataclass @dataclass class Persona: name: str description: str # Feature preference weights — used by deterministic judge prefers_high_priority: float # 0–1: scales response to priority prefers_overdue: float # 0–1: scales response to overdue tasks morning_active: bool # higher engagement hours 6–10 evening_active: bool # higher engagement hours 18–22 recency_bias: float # 0–1: prefers recently-due tasks # Synthetic profile features for egreedy-v2 sim (ADR-0012). # Values represent what a typical user of this persona would have # accumulated after a few weeks of app use. _completion_rate: float = 0.3 _dismiss_rate: float = 0.2 _mean_dwell_ms: float = 60_000.0 # ms _preferred_hour: float = 12.0 # 0–23 _tip_volume_30d: float = 15.0 def profile_features(self, now_hour: int | None = None) -> dict: """Return profile_features dict compatible with the ml/serving API.""" return { "completion_rate_30d": self._completion_rate, "dismiss_rate_30d": self._dismiss_rate, "mean_dwell_ms_30d": self._mean_dwell_ms, "preferred_hour": self._preferred_hour, "tip_volume_30d": self._tip_volume_30d, } PERSONAS: list[Persona] = [ Persona( name="deadline-driven", description=( "Responds urgently to overdue and high-priority tasks. " "Most active in the morning. Dismisses low-priority tips." ), prefers_high_priority=0.9, prefers_overdue=0.85, morning_active=True, evening_active=False, recency_bias=0.3, _completion_rate=0.55, _dismiss_rate=0.10, _mean_dwell_ms=45_000.0, _preferred_hour=8.0, _tip_volume_30d=22.0, ), Persona( name="evening-relaxed", description=( "Reviews tasks in the evenings. Neutral on priority. " "Snoozes morning recommendations." ), prefers_high_priority=0.5, prefers_overdue=0.4, morning_active=False, evening_active=True, recency_bias=0.5, _completion_rate=0.30, _dismiss_rate=0.25, _mean_dwell_ms=90_000.0, _preferred_hour=20.0, _tip_volume_30d=12.0, ), Persona( name="low-priority-first", description=( "Clears small tasks first. Snoozes urgent items until deadline. " "Morning person." ), prefers_high_priority=0.2, prefers_overdue=0.6, morning_active=True, evening_active=False, recency_bias=0.7, _completion_rate=0.40, _dismiss_rate=0.15, _mean_dwell_ms=30_000.0, _preferred_hour=9.0, _tip_volume_30d=18.0, ), Persona( name="consistent-responder", description=( "Engages consistently across hours and days. " "Acts on helpful tips regardless of priority." ), prefers_high_priority=0.6, prefers_overdue=0.6, morning_active=True, evening_active=True, recency_bias=0.5, _completion_rate=0.50, _dismiss_rate=0.10, _mean_dwell_ms=60_000.0, _preferred_hour=12.0, _tip_volume_30d=30.0, ), Persona( name="overdue-ignorer", description=( "Avoids overdue tasks (stress avoidance). " "Focuses on future-due, high-priority items. Evening person." ), prefers_high_priority=0.8, prefers_overdue=0.1, morning_active=False, evening_active=True, recency_bias=0.2, _completion_rate=0.20, _dismiss_rate=0.40, _mean_dwell_ms=120_000.0, _preferred_hour=19.0, _tip_volume_30d=10.0, ), ]