"""The platform user-data storage root.
The central settings facade (:class:`~core.config.Settings`) roots the
encrypted profile store at ``cadrumo_local_storage_root``, from which the
token, log, secret, blob and audit roots derive. This module resolves that
default, and resolves it to exactly one place: the platform user-data
directory (``%LOCALAPPDATA%`` on Windows, ``$XDG_DATA_HOME`` with the
``~/.local/share`` fallback on Linux, ``~/Library/Application Support`` on
macOS).
It does NOT classify how the process was installed. Cadrumo is a tax-filing
product; a repository is a development artefact with no runtime meaning, so
production code never inspects the filesystem for a ``pyproject.toml`` or a
``.git`` marker. An earlier revision did exactly that and branched on the
answer to choose between a checkout-local ``var/storage`` and the platform
directory — which meant a source-layout guess decided where a taxpayer's
regulated financial state was written. Detection is gone; only the platform
answer remains.
The dev loop is served by configuration, not by detection: a developer who
wants the store inside their checkout sets ``CADRUMO_LOCAL_STORAGE_ROOT``
(the justfile does), and an explicit operator override wins over this
default like any other setting.
Every input the resolution reads — the platform string, the environment
mapping, and the home directory — is captured in the frozen
:class:`StateRootInputs` seam, so resolution is a pure function of its
argument and testable without mutating the ambient process.
:func:`default_storage_root` is the live entry point
:class:`~core.config.Settings` binds as its ``cadrumo_local_storage_root``
default factory.
See Also:
:class:`~core.config.Settings`
Central settings aggregate whose storage-root default is resolved here.
:class:`StateRootInputs`
Frozen seam that captures every environmental input used by resolution.
:func:`resolve_state_root`
Pure resolver that returns the effective storage root.
:func:`default_storage_root`
Live default factory bound into the settings model.
"""
from __future__ import annotations
import os
import sys
from pathlib import Path
from pydantic import BaseModel
from .errors.hierarchy import CoreError
from .models import STRICT_FROZEN_CONFIG
from .product_identity import PRODUCT_IDENTITY
from .storage_taxonomy import StorageCategory
from .storage_taxonomy_locations import storage_location
_WINDOWS_PLATFORM = "win32"
_MACOS_PLATFORM = "darwin"
#: Vendor/application directory name appended to the platform user-data base.
_APP_DIRNAME = PRODUCT_IDENTITY.python_package
#: Retired ``aeat`` directory inspected only to refuse implicit state adoption.
_FORMER_PRODUCT_APP_DIRNAME = "aeat"
#: Storage substrate subdirectory under the resolved installed state root.
_STORAGE_DIRNAME = "storage"
#: Bucket container directory name, read from the one core storage authority.
BUCKETS_DIRNAME = storage_location(StorageCategory.BUCKETS).subpath
#: Per-bucket database directory name, read from the one core storage authority.
BUCKET_DB_DIRNAME = storage_location(StorageCategory.BUCKET_DATABASE).subpath
#: Canonical SQLite filename, read from the one core storage authority.
PRODUCT_DATABASE_FILENAME = storage_location(StorageCategory.ROOT_FALLBACK_DATABASE).subpath
#: Retired ``aeat`` database filename inspected only for refusal.
FORMER_PRODUCT_DATABASE_FILENAME = "aeat.db"
[docs]
class StateRootResolution(BaseModel):
"""Typed outcome of resolving the storage state root.
Carries the platform user-data base and the effective ``storage_root``
that :class:`~core.config.Settings` defaults ``cadrumo_local_storage_root``
to. No run-mode or repository concept appears here: the product does not
classify its own installation.
"""
model_config = STRICT_FROZEN_CONFIG
platform_user_data_root: Path
storage_root: Path
def _env_absolute_path(environ: dict[str, str], name: str) -> Path | None:
"""Return an absolute :class:`~pathlib.Path` from ``environ[name]``, or ``None``.
A blank, unset, or non-absolute value yields ``None`` so the caller falls
back to the platform default. The absolute-only rule matches the XDG Base
Directory specification (a relative ``$XDG_DATA_HOME`` is ignored) and is
applied uniformly to ``%LOCALAPPDATA%`` for the same robustness.
"""
raw = environ.get(name, "").strip()
if not raw:
return None
candidate = Path(raw)
return candidate if candidate.is_absolute() else None
def _refuse_former_product_state(user_data_root: Path) -> None:
"""Refuse a recognizable sibling directory left by retired ``aeat`` state."""
former_root = user_data_root.parent / _FORMER_PRODUCT_APP_DIRNAME
if not former_root.exists():
return
raise FormerProductStateError(
"Cadrumo detected incompatible retired `aeat` state at "
f"{former_root}. Cadrumo will not read, move, re-key, delete, or adopt that state.",
)
[docs]
def resolve_state_root(inputs: StateRootInputs) -> StateRootResolution:
"""Resolve the effective storage state root.
Unconditional: the store always lands under the platform user-data
directory. Cadrumo is a tax-filing product and is blind to how it was
installed — it never inspects the filesystem for a ``pyproject.toml``
or a ``.git`` marker to decide where a taxpayer's encrypted state
belongs. A repository is a development artefact with no meaning at
runtime, and branching on one put regulated financial data in a
location chosen by a source-layout guess.
A developer who wants the store inside their checkout sets
``CADRUMO_LOCAL_STORAGE_ROOT`` (the justfile does this), which wins
over this default like any other operator override. That keeps the
dev loop working through the ordinary configuration channel instead
of through product code that detects its own environment.
"""
user_data_root = platform_user_data_root(inputs)
_refuse_former_product_state(user_data_root)
return StateRootResolution(
platform_user_data_root=user_data_root,
storage_root=user_data_root / _STORAGE_DIRNAME,
)
[docs]
def default_storage_root() -> Path:
"""Return the ``cadrumo_local_storage_root`` default for the live process.
Bound as the :class:`~core.config.Settings` ``cadrumo_local_storage_root``
default factory. Always the platform user-data storage directory — the
product does not classify its installation. A developer overrides it with
``CADRUMO_LOCAL_STORAGE_ROOT``.
"""
return resolve_state_root(live_state_root_inputs()).storage_root