# Backend Enum and String Compatibility Contract Planet keeps finite, stable protocol states in `backend/app/core/enums.py`. Databases and APIs continue to store and return lowercase strings. Enums provide internal type safety, validation, and deduplication without requiring a migration to database enum types. ## Selection Rules A value should become an enum only when it is finite and stable, invalid outside the known set, and compared, sorted, or branched on by multiple modules. Typical examples are job states, AI Playground message roles and states, user roles, alert states, log levels, news importance, and Breaking states. The following must remain configurable strings: - news categories and tags; - provider, model, datasource, collector, news source, and Feed identifiers; - extensible incident and anomaly types; and - user-authored and free-form text. ## Boundary Conversion Services should use `StrEnum` internally. Database writes and external responses use `.value`, preserving existing strings such as `JobStatus.RUNNING.value == "running"`. Use the compatibility parser when reading historical database values, JSON, or external input: ```python status = parse_enum(JobStatus, raw_status, JobStatus.FAILED) ``` Known historical strings normalize to enum members. Empty values use the explicit default. Unknown values emit a warning and safely fall back instead of breaking historical reads. Pydantic request fields may use enums directly so invalid protocol values return `422`. Ordinary String and JSON database columns must not be converted to SQLAlchemy Enum. ## Earth News Decisions Earth news decisions live in `backend/app/services/earth_news_classification.py`: - category answers what the story is and remains configurable; - importance answers whether it has long-term value; and - Breaking answers whether it must temporarily jump ahead. Importance levels are fixed: | Level | Score | |---|---:| | `low` | 0–34 | | `medium` | 35–59 | | `high` | 60–79 | | `critical` | 80–100 | Breaking rules use the typed `BreakingRule` structure. Levels, scopes, sources, and TTLs are managed by the public classification module. `earth_news.py` remains responsible for fetching, parsing, orchestration, and serialization. ## Regression Prevention When adding or changing protocol states, check `app/core/enums.py` first and do not redefine duplicate `Literal` aliases, status sets, or normalization helpers in business modules. Add enum value and boundary contracts to `tests/test_enum_contracts.py`, and preserve API strings and database representation.