"""In-memory Repository: M0 default, and the reference fake for tests. Single-process only (fine for one Gradio app); durable backends (SQLite local, Supabase Postgres on the Space) land in M3. """ from tutor.domain.models import Attempt, Learner class InMemoryRepository: def __init__(self) -> None: self._learners: dict[str, Learner] = {} self._attempts: dict[str, Attempt] = {} async def save_learner(self, learner: Learner) -> None: self._learners[learner.id] = learner async def get_learner(self, learner_id: str) -> Learner | None: return self._learners.get(learner_id) async def save_attempt(self, attempt: Attempt) -> None: self._attempts[attempt.id] = attempt async def list_attempts(self, learner_id: str) -> list[Attempt]: attempts = [a for a in self._attempts.values() if a.learner_id == learner_id] return sorted(attempts, key=lambda a: a.created_at)