domain/practice_resolution — collapsing catalog + override¶
backend/src/domain/practice_resolution.py (42 lines). Pure helpers that
collapse (Practice, UserPractice) into the effective values the
frontend reads. Keeping them pure (no DB access) makes them trivially
testable and lets endpoints reuse them without round-tripping through the
ORM (practice_resolution.py:1-8).
effective_name(practice, user_practice) -> str¶
The user's custom_name if set (non-empty), else the catalog name
(practice_resolution.py:17-21).
effective_config(practice, user_practice) -> ModeConfig¶
The override-resolution rule, verbatim
(backend/src/domain/practice_resolution.py:24-42):
def effective_config(practice: Practice, user_practice: UserPractice | None) -> ModeConfig:
"""Return the user's override if set, else the catalog ``mode_config``.
Validates the resolved payload through :class:`ModeConfigAdapter` so a
structurally invalid override surfaces as a domain error rather than
leaking into engine code. Raises ``ValueError("mode_mismatch")`` when
the override's ``mode`` discriminator doesn't agree with the catalog
mode — the override may only swap fields *within* a mode.
"""
payload = (
user_practice.mode_config_override
if user_practice is not None and user_practice.mode_config_override is not None
else practice.mode_config
)
cfg = ModeConfigAdapter.validate_python(payload)
if cfg.mode != practice.mode:
msg = "mode_mismatch"
raise ValueError(msg)
return cfg
Rules:
- Payload selection:
user_practice.mode_config_overridewhen present, elsepractice.mode_config. - The payload is validated through the
schemas.practice_mode_config.ModeConfigAdapterdiscriminated union — a structurally invalid override is a domain error, not an engine crash. - Cross-mode swaps are refused:
ValueError("mode_mismatch")when the resolved config'smodediffers from the catalog row'smode. This enforces the model-layer contract thatmodeitself is not overridable (backend/src/models/user_practice.py:51-53).
Worked example¶
Catalog Practice(mode="interval_bell", mode_config={...bell fields...});
UserPractice(mode_config_override=None) → the catalog config, validated.
Same catalog with
override={"mode": "interval_bell", "interval_seconds": 90} → the
override wins. override={"mode": "metronome", ...} →
ValueError("mode_mismatch") (the API layer maps this to a 4xx — see
api/user-practices).
Grounded in adepthood@fbc529d, 2026-07-31.