"""Support types and defaults for the central settings facade.This module holds the closed settings enums and derived records consumedby :class:`~core.config.Settings`: LLM provider selection(:class:`~core.config_support.LLMProvider`), and database routing via:class:`~core.config_support.StorageRouteKind` and:class:`~core.config_support.StorageRouteClassification`.The route records are produced by:func:`~core.config.classify_storage_route`; output language strings arecoerced to :class:`~core.external_constants.OutputLanguage`; and AEAT URLdefaults are read from :func:`~core.external_constants.load_external_constants`."""from__future__importannotationsfromenumimportStrEnumfrompathlibimportPathfrompydanticimportBaseModel,Field,SecretStrfrom.external_constantsimportOutputLanguage,load_external_constantsfrom.identity.bucketimportBucketIdfrom.modelsimportSTRICT_FROZEN_CONFIG_EXTERNAL_CONSTANTS=load_external_constants()AEAT_CERTIFICATE_PROTECTED_ORIGIN=_EXTERNAL_CONSTANTS.aeat.domains.www6"""Exact Playwright client-certificate origin for AEAT certificate authentication."""AEAT_CERTIFICATE_PROTECTED_PATH=_EXTERNAL_CONSTANTS.aeat.sede_paths.expedientes_resumen"""Exact protected AEAT resource path used to prove certificate authentication."""AEAT_CERTIFICATE_PROTECTED_URL=f"{AEAT_CERTIFICATE_PROTECTED_ORIGIN}{AEAT_CERTIFICATE_PROTECTED_PATH}""""Canonical protected navigation URL for certificate authentication."""
[docs]defassert_canonical_protected_resource(value:str,*,subject:str)->str:"""Return ``value`` if it is the canonical protected resource, else raise. Certificate authentication is proved by reaching one specific AEAT resource, so a record claiming proof against any other URL is not evidence of anything. Both the persisted proof and the live session detail assert this, and they asserted it with separate copies of the comparison until this became its one home — beside the constant it is about, where a change to the route and a change to the rule cannot separate. Args: value: The protected-resource URL the record carries. subject: What is being validated, for the refusal message — the two call sites name different records and the operator needs to know which one refused. Returns: ``value`` unchanged. Raises: ValueError: ``value`` is not the canonical protected resource. A plain ``ValueError`` because both call sites are pydantic validators, which fold it into the model's own ``ValidationError``. """ifvalue!=AEAT_CERTIFICATE_PROTECTED_URL:raiseValueError(f"{subject} must use the canonical protected resource")returnvalue
[docs]classTuiAppearance(StrEnum):"""Supported appearances for the full-screen terminal surfaces. :class:`~core.config.Settings` exposes this closed set through ``cadrumo_tui_appearance`` so the profile manager, the paged flow frontend, and the read-only status page share one spelling for the operator's light/dark preference. ``AUTO`` defers to the host terminal rather than pinning an appearance. """AUTO="auto"LIGHT="light"DARK="dark"
[docs]defunwrap_optional_secret(value:SecretStr|None)->str:"""Return the cleartext of an optional :class:`pydantic.SecretStr`. Optional Cl@ve and certificate settings use this helper at adapter boundaries so unset secrets materialise as ``""`` rather than leaking :class:`pydantic.SecretStr` wrappers into string handling. """returnvalue.get_secret_value()ifvalueisnotNoneelse""
[docs]classLLMProvider(StrEnum):"""The closed set of model-transport identities, declared once, here. Canonical home for the value set, not a settings-only convenience. Two byte-identical copies of it existed -- this one and a second in the inference package's request models -- so a reader could not tell which was authoritative and a value added to one would silently not exist in the other. It lives in ``core`` because a closed value set is declared in ``core`` by the architecture boundary, and because the direction is forced: the inference package may import ``core`` (inward), while ``core`` importing the optional inference package is refused by contract. The package consumes this enum; it does not redeclare it. """ANTHROPIC="ANTHROPIC"OPENAI="OPENAI"GEMINI="GEMINI"LOCAL="LOCAL"
[docs]classStorageRouteKind(StrEnum):"""Resolved primary database route classification. Members distinguish operator-supplied database URLs from computed active bucket routes and cold root-fallback routes. The storage write policy consumes this value through :func:`~application.storage_write_policy.inspect_storage_write_policy`. """EXPLICIT_DATABASE_URL="explicit_database_url"ACTIVE_BUCKET_DATABASE="active_bucket_database"ROOT_FALLBACK_DATABASE="root_fallback_database"
[docs]classStorageRouteClassification(BaseModel):"""Strict classification of the effective primary database route. Instances are returned by :func:`~core.config.classify_storage_route` and carry the effective :class:`StorageRouteKind`, original database URL, SQLite path when derivable, and active bucket id for bucket-attached routes. """model_config=STRICT_FROZEN_CONFIGkind:StorageRouteKinddatabase_url:str=Field(min_length=1)database_path:Path|None=Nonebucket_id:BucketId|None=None
[docs]defdefault_clave_sede_access_url_template()->str:"""Return the configured Cl@ve Movil selector access URL template."""returnload_external_constants().aeat.clave_movil.selector_access_url_template
[docs]defdefault_clave_permanente_sede_access_url_template()->str:"""Return the configured Cl@ve Permanente selector access URL template."""returnload_external_constants().aeat.clave_permanente.selector_access_url_template
[docs]defdefault_sede_expedientes_path()->str:"""Return the configured AEAT Sede expedientes summary path."""returnload_external_constants().aeat.sede_paths.expedientes_resumen
[docs]defdefault_status_detail_url_template()->str:"""Return the configured AEAT expediente status detail URL template."""returnload_external_constants().aeat.sede_paths.expediente_detail_template
[docs]defdefault_status_notificaciones_path()->str:"""Return the configured AEAT notifications status path."""returnload_external_constants().aeat.sede_paths.notificaciones
[docs]defdefault_aeat_sede_origin()->str:"""Return the configured AEAT Sede origin."""returnload_external_constants().aeat.domains.sede
[docs]defdefault_aeat_sede_origin_with_slash()->str:"""Return the configured AEAT Sede origin with a trailing slash."""returnf"{default_aeat_sede_origin()}/"
[docs]classJustificanteParserBackendSetting(StrEnum):"""Settings-shape selector for the justificante PDF parsing backend."""PDFPLUMBER="pdfplumber"
def_runtime_object(value:object)->object:"""Capture an environment value before applying its runtime shape guard."""returnvalue
[docs]defcoerce_output_language_setting(value:str)->OutputLanguage|None:"""Coerce an env-var output-language string to an :class:`OutputLanguage`. Returns ``None`` for invalid input so :class:`~core.config.Settings` validation can decide how to fall back or report the bad value. A non-string value (e.g. a bare ``bool``, which is a subtype of ``int`` and would otherwise reach ``.lower()``) is invalid input, not a crash. """raw_value=_runtime_object(value)ifnotisinstance(raw_value,str)ornotraw_value:returnNonenormalized=raw_value.lower().strip()try:returnOutputLanguage(normalized)exceptValueError:returnNone