Source code for cadrumo.adapters.persistence.storage.secure_object_namespaces

"""Typed secure-object namespace and hierarchy contracts.

Each :class:`SecureObjectNamespaceDefinition` carries a
:class:`SensitivityClass` field that governs the at-rest encryption
treatment applied by the substrate for every object in that namespace.
"""

from __future__ import annotations

from collections.abc import Callable
from functools import wraps

from pydantic import BaseModel, Field, field_validator, model_validator

from ....core.classification.policies import SensitivityClass
from ....core.errors.hierarchy import pydantic_validation_boundary
from ....core.models import STRICT_FROZEN_CONFIG as _STRICT_FROZEN
from ....core.storage_taxonomy import StorageCustodyProfile
from .errors import NamespaceRegistryError
from .namespace_taxonomy import (
    CUSTODY_PROFILE_DISPOSITIONS,
    StorageCustodyDisposition,
    StorageNamespaceScope,
    StorageRemoteMirrorPolicy,
)
from .storage_path_definitions import (
    StoragePathDefinition,
)

SECURE_OBJECT_SCHEMA_VERSION_V1 = 1
SECURE_OBJECT_SCHEMA_VERSION_V2 = 2
SECURE_OBJECT_SCHEMA_VERSION_V4 = 4
_WORKFLOW_RUN_SCHEMA_VERSION_V3 = 3
SECURE_OBJECT_CATALOGUE_KEY = "catalogue"
SECURE_OBJECT_DEFAULT_KEY = "default"
SECURE_OBJECT_WORKFLOW_STATE_KEY = "state"

FORMER_PRODUCT_NAMESPACE_PREFIXES = ("aeat.", "aeat-test.", "aeat-tests.")


def _pydantic_namespace_validator[ValidationResultT](
    function: Callable[..., ValidationResultT],
) -> Callable[..., ValidationResultT]:
    """Translate the registered namespace refusal at Pydantic's callback edge."""

    @wraps(function)
    def wrapped(*args: object, **kwargs: object) -> ValidationResultT:
        try:
            return function(*args, **kwargs)
        except NamespaceRegistryError as exc:
            raise ValueError(str(exc)) from exc

    return wrapped


[docs] def is_former_product_namespace(namespace: str) -> bool: """Return whether ``namespace`` uses a retired product-owned prefix.""" return namespace.startswith(FORMER_PRODUCT_NAMESPACE_PREFIXES)
[docs] class SecureObjectNamespaceDefinition(BaseModel): """Contract for one encrypted SQL secure-object namespace.""" model_config = _STRICT_FROZEN key: str = Field(min_length=1) namespace: str = Field(min_length=1, max_length=128) owner: str = Field(min_length=1) sensitivity: SensitivityClass schema_version: int = Field(ge=1) object_key_grammar: str = Field(min_length=1) scope: StorageNamespaceScope custody_disposition: StorageCustodyDisposition default_object_key: str | None = Field(default=None, min_length=1) record_formats: tuple[str, ...] = () """Persisted-format inventory keys carried by this namespace's rows. A namespace is not a persisted format. The great majority hold rows under the secure-object envelope's one schema version and one upgrader registry, and declare nothing here. The few that do carry a record grammar enrolled in the durability inventory on its own axis: the envelope governs whether the bytes decrypt, the record's own declaration governs whether what is inside them can still be read, and a floor on the first does not cover the second. Declared beside the namespace rather than in the gate that reads it, so the author adding such a record sees the obligation where the row lives. Three of these once sat in a hand-maintained table inside a test module, where a correct durability declaration read as a stale one because nothing in production pointed at it. """ remote_mirror_policy: StorageRemoteMirrorPolicy = StorageRemoteMirrorPolicy.CIPHERTEXT_WITH_METADATA remote_mirror_requires_revision: bool = True remote_mirror_requires_integrity_manifest: bool = True @field_validator("key") @classmethod @_pydantic_namespace_validator @pydantic_validation_boundary def _key_is_registry_safe(cls, value: str) -> str: if value != value.strip(): raise NamespaceRegistryError("registry key must not carry surrounding whitespace") if any(separator in value for separator in ("/", "\\", ":", ".")): raise NamespaceRegistryError("registry key must be a storage-safe slug") return value @field_validator("namespace") @classmethod @_pydantic_namespace_validator @pydantic_validation_boundary def _namespace_is_sql_safe(cls, value: str) -> str: if value != value.strip(): raise NamespaceRegistryError("namespace must not carry surrounding whitespace") if "/" in value or "\\" in value: raise NamespaceRegistryError("namespace must not contain path separators") return value @field_validator("default_object_key") @classmethod @_pydantic_namespace_validator @pydantic_validation_boundary def _default_key_is_repository_safe(cls, value: str | None) -> str | None: if value is None: return None if value != value.strip(): raise NamespaceRegistryError("default object key must not carry surrounding whitespace") if "/" in value or "\\" in value: raise NamespaceRegistryError("default object key must not contain path separators") return value @property def singleton_object_key(self) -> str | None: """Return the one key this namespace admits, or ``None`` when it is multi-key. A grammar carrying no ``{placeholder}`` names a literal key rather than a template, so the namespace holds exactly one row under exactly that key -- ``catalogue``, ``default``, ``state``. That makes the declared grammar machine-checkable for this class of namespace without a per-namespace parser. """ if "{" in self.object_key_grammar: return None return self.object_key_grammar
[docs] def validate_object_key(self, object_key: str) -> None: """Raise :class:`NamespaceRegistryError` when ``object_key`` violates this contract. Two checks apply. Every namespace rejects surrounding whitespace and a ``..`` traversal segment, because the key also names a logical storage path (:func:`secure_object_logical_path`). Path SEPARATORS are not rejected: several namespaces declare a grammar rooted at a logical path (``{logical_root}|...``, ``{storage_state_path_posix}``) whose keys legitimately contain them. A singleton namespace additionally requires the key to equal its declared literal. Without that, a valid envelope written under a mistyped key round-trips through raw storage while the owning repository -- which addresses the singleton by its canonical key -- reports the record absent: the row is silently orphaned rather than refused. A templated (multi-key) namespace is checked for traversal safety only. Its placeholder grammar stays documentation until a typed per-namespace key validator exists; asserting more here would refuse keys the registry itself declares as valid. Args: object_key: The natural (pre-digest) key a caller is addressing. Raises: NamespaceRegistryError: When the key is unsafe or, for a singleton namespace, is not the declared literal. """ if object_key != object_key.strip(): raise NamespaceRegistryError( f"object key for namespace {self.namespace!r} must not carry surrounding whitespace", ) segments = object_key.replace("\\", "/").replace(":", "/").split("/") if ".." in segments: raise NamespaceRegistryError( f"object key for namespace {self.namespace!r} must not contain a traversal segment", ) singleton_key = self.singleton_object_key if singleton_key is not None and object_key != singleton_key: raise NamespaceRegistryError( f"namespace {self.namespace!r} is a singleton addressed only by {singleton_key!r}; got {object_key!r}", )
@model_validator(mode="after") @_pydantic_namespace_validator @pydantic_validation_boundary def _singleton_default_key_matches_grammar(self) -> SecureObjectNamespaceDefinition: """Keep a singleton namespace's default key equal to its declared grammar. The default key is what repositories address the singleton by, and the grammar is what :meth:`validate_object_key` enforces. If the two disagreed, every write through the repository's own default would be refused by the namespace's own contract. """ singleton_key = self.singleton_object_key if singleton_key is not None and self.default_object_key not in (None, singleton_key): raise NamespaceRegistryError( f"singleton namespace {self.namespace!r} declares grammar {singleton_key!r} " f"but default object key {self.default_object_key!r}", ) return self @model_validator(mode="after") @_pydantic_namespace_validator @pydantic_validation_boundary def _remote_mirror_policy_is_consistent(self) -> SecureObjectNamespaceDefinition: if self.remote_mirror_policy is StorageRemoteMirrorPolicy.CIPHERTEXT_WITH_METADATA: if not self.remote_mirror_requires_revision or not self.remote_mirror_requires_integrity_manifest: raise NamespaceRegistryError( "ciphertext remote mirror namespaces require revision and integrity metadata", ) elif self.remote_mirror_requires_revision or self.remote_mirror_requires_integrity_manifest: raise NamespaceRegistryError("local-only and test-only namespaces must not require remote mirror metadata") return self
[docs] def require_default_object_key(self) -> str: """Return the singleton object key or raise when the namespace is multi-key.""" if self.default_object_key is None: raise NamespaceRegistryError(f"namespace {self.namespace!r} does not define a singleton object key") return self.default_object_key
[docs] class StorageHierarchyRegistry(BaseModel): """Registry carrying the known secure-storage hierarchy contracts.""" model_config = _STRICT_FROZEN namespaces: tuple[SecureObjectNamespaceDefinition, ...] paths: tuple[StoragePathDefinition, ...] @model_validator(mode="after") @_pydantic_namespace_validator @pydantic_validation_boundary def _reject_duplicate_keys_and_namespaces(self) -> StorageHierarchyRegistry: namespace_keys = [item.key for item in self.namespaces] namespace_values = [item.namespace for item in self.namespaces] path_keys = [item.key for item in self.paths] if len(namespace_keys) != len(set(namespace_keys)): raise NamespaceRegistryError("duplicate secure-object namespace registry key") if len(namespace_values) != len(set(namespace_values)): raise NamespaceRegistryError("duplicate secure-object namespace value") if len(path_keys) != len(set(path_keys)): raise NamespaceRegistryError("duplicate storage path registry key") return self
[docs] def namespace_by_value(self, value: str) -> SecureObjectNamespaceDefinition: """Return a :class:`SecureObjectNamespaceDefinition` by persisted namespace value.""" for namespace in self.namespaces: if namespace.namespace == value: return namespace raise KeyError(value)
[docs] def path_by_key(self, key: str) -> StoragePathDefinition: """Return a :class:`StoragePathDefinition` by registry key.""" for path in self.paths: if path.key == key: return path raise KeyError(key)
[docs] def namespaces_for_custody_profile( self, profile: StorageCustodyProfile, ) -> tuple[SecureObjectNamespaceDefinition, ...]: """Return carried :class:`SecureObjectNamespaceDefinition` rows for a custody profile.""" dispositions = CUSTODY_PROFILE_DISPOSITIONS[profile] return tuple(namespace for namespace in self.namespaces if namespace.custody_disposition in dispositions)
WORKFLOW_STATE_NAMESPACE = SecureObjectNamespaceDefinition( key="workflow_state", namespace="cadrumo.workflow", owner="cadrumo.application.workflow", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="state", default_object_key=SECURE_OBJECT_WORKFLOW_STATE_KEY, scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) WORKFLOW_RUN_NAMESPACE = SecureObjectNamespaceDefinition( key="workflow_runs", namespace="cadrumo.application.workflow.runs", owner="cadrumo.application.workflow", sensitivity=SensitivityClass.FINANCIAL, schema_version=_WORKFLOW_RUN_SCHEMA_VERSION_V3, object_key_grammar="{run_id}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) OPERATION_SECURE_REFERENCE_NAMESPACE = SecureObjectNamespaceDefinition( key="operation_secure_references", namespace="cadrumo.application.operations.secure_references", owner="cadrumo.adapters.persistence.operations", # The supervisor carries the validated request and result types for every # operation family. Financial is the conservative shared classification for # that cross-domain envelope: it preserves ciphertext-at-rest treatment for # identifier-bearing profile requests without inventing one namespace per # operation definition. The rows are process-local operational state, not # portable profile data, so bundle custody accounts for but never carries it. sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{content_digest}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) USER_PROFILE_VALUE_NAMESPACE = SecureObjectNamespaceDefinition( key="user_profile_value", namespace="cadrumo.application.user_profile.value", owner="cadrumo.application.user_profile", sensitivity=SensitivityClass.IDENTITY, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="user-profile:{profile_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, record_formats=("profile_record",), ) USER_PROFILE_SNAPSHOT_NAMESPACE = SecureObjectNamespaceDefinition( key="user_profile_snapshot", namespace="cadrumo.application.user_profile.snapshot", owner="cadrumo.application.user_profile", sensitivity=SensitivityClass.IDENTITY, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="user-profile-snapshot:{profile_id}:{snapshot_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) PROFILE_INVENTORY_LEDGER_NAMESPACE = SecureObjectNamespaceDefinition( key="profile_inventory_ledger", namespace="cadrumo.persistence.profile.inventory", owner="cadrumo.adapters.persistence.profile.inventory", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="default", default_object_key=SECURE_OBJECT_DEFAULT_KEY, scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) PROFILE_BIENES_INVERSION_IVA_REGISTER_NAMESPACE = SecureObjectNamespaceDefinition( key="profile_bienes_inversion_iva_register", namespace="cadrumo.persistence.profile.bienes_inversion", owner="cadrumo.adapters.persistence.profile.bienes_inversion", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V2, object_key_grammar="default", default_object_key=SECURE_OBJECT_DEFAULT_KEY, scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) PROFILE_PRORRATA_REGISTER_NAMESPACE = SecureObjectNamespaceDefinition( key="profile_prorrata_register", namespace="cadrumo.persistence.profile.prorrata_register", owner="cadrumo.adapters.persistence.profile.prorrata_register", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V2, object_key_grammar="default", default_object_key=SECURE_OBJECT_DEFAULT_KEY, scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) APPLICATION_FILING_HISTORY_NAMESPACE = SecureObjectNamespaceDefinition( key="application_filing_history", namespace="cadrumo.application.filing.history", owner="cadrumo.application.filing", sensitivity=SensitivityClass.AUDIT, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{modelo}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) AUTH_APODERADO_CONFIGURATION_NAMESPACE = SecureObjectNamespaceDefinition( key="auth_apoderado_configuration", namespace="cadrumo.auth.apoderado", owner="cadrumo.application.auth", sensitivity=SensitivityClass.IDENTITY, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{bucket_id}", scope=StorageNamespaceScope.PROFILE_LOCAL, # Durable per-bucket apoderamiento setup (represented NIF + granted scopes): it # is not a host credential or session and is not re-derivable, so it must # survive a recovery restore. Sealed-only because it carries identity data. custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) CALCULATION_OBSERVATIONS_NAMESPACE = SecureObjectNamespaceDefinition( key="calculation_observations", namespace="cadrumo.calculations.observations", owner="cadrumo.application.calculations", sensitivity=SensitivityClass.AUDIT, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V2, # Single-filer rows key on (modelo, filing_year, period); a per-grupo-member # filing widens the same key with an optional trailing member segment so two # members' filings for one triple persist as distinct rows (the 353<-322 # per_grupo_member fan-in). Both live in this one namespace. # # The member segment is a digest of the member's canonical identity token, # never the identifier itself, matching every other identifier-bearing # grammar here. The digest is what makes the segment an IDENTITY rather than # a spelling: a padded or lower-case rendering of one member canonicalises # to the same token and therefore addresses the same row, where a verbatim # segment persisted that member twice. object_key_grammar="{modelo}:{filing_year}:{period}[:{sha256(member_nif)}]", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) # Per-perceptor retención records (perceptor NIF + scheme + taxable base + # retención) for the M180/M193 calc-mesh perceptor-count resolver. The # DEDICATED store lets the distinct-NIF count be computed from one persisted # source shared by the pull and calculate surfaces — never the wrong sum of # quarterly aggregate counts. # FINANCIAL sensitivity: perceptor NIFs are identity-bearing financial data and # live encrypted at rest, never plaintext. RETENCION_OBSERVATIONS_NAMESPACE = SecureObjectNamespaceDefinition( key="retencion_observations", namespace="cadrumo.retenciones.observations", owner="cadrumo.application.aggregation", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, # The perceptor NIF is sha256-hashed in the object key (mirroring the # iva-wallet-decision key convention) so the plaintext NIF lives ONLY inside # the encrypted payload, never in a repository identifier. object_key_grammar="{modelo}:{filing_year}:{period}:{sha256(perceptor_nif)}:{scheme}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) WITHHOLDING_OBSERVATIONS_NAMESPACE = SecureObjectNamespaceDefinition( key="withholding_observations", namespace="cadrumo.withholding.observations", owner="cadrumo.application.aggregation", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, # The perceptor NIF is sha256-hashed in the object key (mirroring the # iva-wallet-decision key convention) so the plaintext NIF lives ONLY inside # the encrypted payload, never in a repository identifier. The clave/subclave # are non-identifying AEAT percepcion codes, so they stay plain in the key. object_key_grammar="{modelo}:{filing_year}:{period}:{sha256(perceptor_tax_id)}:{clave}:{subclave}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) IVA_WALLET_RECONCILIATION_DECISIONS_NAMESPACE = SecureObjectNamespaceDefinition( key="iva_wallet_reconciliation_decisions", namespace="cadrumo.calculations.iva_wallet.reconciliation_decisions", owner="cadrumo.application.calculations", sensitivity=SensitivityClass.AUDIT, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V2, object_key_grammar="iva-wallet-decision:{sha256(taxpayer_nif,target_year,target_period)}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) IVA_WALLET_RECONCILIATION_DECISION_EVENTS_NAMESPACE = SecureObjectNamespaceDefinition( key="iva_wallet_reconciliation_decision_events", namespace="cadrumo.calculations.iva_wallet.reconciliation_decision_events", owner="cadrumo.application.calculations", sensitivity=SensitivityClass.AUDIT, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V2, object_key_grammar="iva-wallet-decision-event:{sha256(decision_identity_and_payload)}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) MODELO_RECONCILIATION_RECORDS_NAMESPACE = SecureObjectNamespaceDefinition( key="modelo_reconciliation_records", namespace="cadrumo.modelo.reconciliation.records", owner="cadrumo.application.modelo", sensitivity=SensitivityClass.AUDIT, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, # N records per work unit, never one that overwrites: reconciliation is # repeatable and `reconcile list` is a shipped verb, so a key that # collapsed runs would destroy the history this store exists to hold. The # trailing segment is the content-addressed id of the MODELO_RECONCILED # bucket event this record is co-written with, which already folds the # reconciliation instant, the actor and the verdict — so it distinguishes # every run and binds record to event by identity rather than by a # cross-reference field that could drift. # # No revision id participates. Both the receipt-total and the # declaracion-casilla reconciles emit a `no_persisted_revision` advisory and # still produce a report, and an identity-header reconcile needs no revision # at all; a revision-derived key could not store those runs. object_key_grammar="modelo-reconciliation:{work_unit_id}:{bucket_event_id}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) SYNC_RUN_RECORDS_NAMESPACE = SecureObjectNamespaceDefinition( key="sync_run_records", namespace="cadrumo.storage.sync_run.records", owner="cadrumo.application.storage", sensitivity=SensitivityClass.AUDIT, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, # N records per surface, never one that overwrites. The phase this store # serves is last-sync PROVENANCE, and a key scoped to the surface alone # would make "last sync" the only sync -- destroying the history the record # exists to carry, exactly as a collapsing key would for reconciliation. # # The trailing segment is the content-addressed id of the sync-run bucket # event this record is co-written with, which already folds the completion # instant and the outcome, so it distinguishes every run and binds record to # event by identity rather than by a cross-reference field that could drift. # # No scope participates in the key. A run's resolved scope is a property of # what it covered, not of which run it was, and a truncated sweep and a full # one over the same surface are different runs that must both be storable. object_key_grammar="sync-run:{surface}:{bucket_event_id}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) IVA_COMPENSATION_HISTORY_NAMESPACE = SecureObjectNamespaceDefinition( key="iva_compensation_history", namespace="cadrumo.calculations.iva_compensation.history", owner="cadrumo.application.calculations", sensitivity=SensitivityClass.AUDIT, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="303:{filing_year}:{period}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) LIVE_IVA_REMOTE_STATE_ACQUISITIONS_NAMESPACE = SecureObjectNamespaceDefinition( key="live_iva_remote_state_acquisitions", namespace="cadrumo.application.live.iva_remote_state_acquisitions", owner="cadrumo.application.live", sensitivity=SensitivityClass.AUDIT, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar=( "live-iva-acquisition:{target_year}:{target_period}:{timestamp}:{sha256(redacted_manifest_seed)}" ), scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) APPLICATION_EVIDENCE_BUNDLE_NAMESPACE = SecureObjectNamespaceDefinition( key="application_evidence_bundles", namespace="cadrumo.application.evidence.bundles", owner="cadrumo.application.evidence", sensitivity=SensitivityClass.AUDIT, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{bundle_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) LEDGER_PURCHASE_INVOICE_EVIDENCE_NAMESPACE = SecureObjectNamespaceDefinition( key="ledger_purchase_invoice_evidence", namespace="cadrumo.application.ledger.purchase_invoice_evidence", owner="cadrumo.application.ledger", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{bucket_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) LEDGER_EXTRACTION_DRAFT_NAMESPACE = SecureObjectNamespaceDefinition( key="ledger_extraction_draft", namespace="cadrumo.application.ledger.extraction_draft", owner="cadrumo.application.ledger", # An extraction draft is DERIVED FINANCIAL DATA -- supplier tax id, invoice # number, taxable base, per-rate cuota. Persisting it is storage, not # processing, so it sits on the core side of the inference boundary at # FINANCIAL sensitivity like every other record carrying those figures. # It is pre-confirm and operator-correctable, which changes its LIFECYCLE # but not its sensitivity: a draft that leaked would disclose exactly what # the confirmed invoice would. sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{bucket_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) LEDGER_CONFIRMATION_RECORD_NAMESPACE = SecureObjectNamespaceDefinition( key="ledger_confirmation_record", namespace="cadrumo.application.ledger.confirmation_record", owner="cadrumo.application.ledger", # The provenance of one human confirmation: who accepted which figures for # which counterparty, and what the document said before they did. That is the # same derived financial data the draft carried plus the operator identity # that accepted it, so it is stored at FINANCIAL sensitivity rather than at an # audit-only classification -- a leaked record would disclose the counterparty, # the base and the cuota exactly as the confirmed invoice would. sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{bucket_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) LEDGER_CONFIRMED_COUNTERPARTY_FACTS_NAMESPACE = SecureObjectNamespaceDefinition( key="ledger_confirmed_counterparty_facts", namespace="cadrumo.application.ledger.confirmed_counterparty_facts", owner="cadrumo.application.ledger", # An establishment fact names one of the taxpayer's trading counterparties # and states where that party is established. The record therefore carries a # counterparty tax identifier and a territorial claim about it, which is the # same disclosure the confirmed invoice carries -- so it is stored at # FINANCIAL sensitivity rather than at an audit-only classification. # # The object key is a digest of the canonical identifier rather than the # identifier itself: an object key is addressing metadata, and putting a # taxpayer's counterparty NIF in one would place a real tax identifier # outside the encrypted payload. sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{sha256(canonical_tax_identifier)}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) LEDGER_CLASSIFICATION_RULES_NAMESPACE = SecureObjectNamespaceDefinition( key="ledger_classification_rules", namespace="cadrumo.ledger.classification.rules", owner="cadrumo.application.ledger", sensitivity=SensitivityClass.AUDIT, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{rule_id}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) LIVE_BORRADOR_100_SNAPSHOT_NAMESPACE = SecureObjectNamespaceDefinition( key="live_borrador_100_snapshot", namespace="cadrumo.application.live.borrador_100_snapshot", owner="cadrumo.application.live", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="modelo-100-borrador-snapshot:{bucket_id}:{snapshot_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) LIVE_M036_DECLARATION_NAMESPACE = SecureObjectNamespaceDefinition( key="live_m036_declaration", namespace="cadrumo.application.modelo.m036_declaration", owner="cadrumo.application.modelo", sensitivity=SensitivityClass.IDENTITY, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="m036-declaration:{bucket_id}:{declaration_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) M145_COMMUNICATION_RECORD_NAMESPACE = SecureObjectNamespaceDefinition( key="m145_communication_record", namespace="cadrumo.application.modelo.m145_communication_record", owner="cadrumo.application.modelo", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="m145-communication:{bucket_id}:{communication_record_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) TEST_SNAPSHOT_BASE_PROBE_NAMESPACE = SecureObjectNamespaceDefinition( key="test_snapshot_base_probe", namespace="cadrumo.application.live.test_snapshot_base_probe", owner="cadrumo.application.live", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="snapshot-base-probe:{bucket_id}:{snapshot_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, remote_mirror_policy=StorageRemoteMirrorPolicy.TEST_ONLY, remote_mirror_requires_revision=False, remote_mirror_requires_integrity_manifest=False, ) TEST_SESSION_LIFECYCLE_NAMESPACE = SecureObjectNamespaceDefinition( key="test_session_lifecycle", namespace="cadrumo-test.session.lifecycle", owner="cadrumo.entrypoints.cli.tests.test_session_lifecycle_roundtrip", sensitivity=SensitivityClass.OPERATIONAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="roundtrip-row", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, remote_mirror_policy=StorageRemoteMirrorPolicy.TEST_ONLY, remote_mirror_requires_revision=False, remote_mirror_requires_integrity_manifest=False, ) TEST_SECURE_BOUND_CONTRACT_NAMESPACE = SecureObjectNamespaceDefinition( key="test_secure_bound_contract", namespace="cadrumo-test.envelope.secure_bound_contract", owner="cadrumo.adapters.persistence.storage.envelope.tests.test_secure_bound_repository_contract", sensitivity=SensitivityClass.AUDIT, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, remote_mirror_policy=StorageRemoteMirrorPolicy.TEST_ONLY, remote_mirror_requires_revision=False, remote_mirror_requires_integrity_manifest=False, ) TEST_RUNTIME_PROFILE_NAMESPACE = SecureObjectNamespaceDefinition( key="test_runtime_profile", namespace="cadrumo-tests.runtime.profile", owner="cadrumo.adapters.persistence.storage.tests.test_secure_sql", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="runtime-row", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, remote_mirror_policy=StorageRemoteMirrorPolicy.TEST_ONLY, remote_mirror_requires_revision=False, remote_mirror_requires_integrity_manifest=False, ) LIVE_EXPEDIENTES_SNAPSHOT_NAMESPACE = SecureObjectNamespaceDefinition( key="live_expedientes_snapshot", namespace="cadrumo.application.live.expedientes_snapshot", owner="cadrumo.application.live", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="expedientes-snapshot:{bucket_id}:{snapshot_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) LIVE_NOTIFICATIONS_SNAPSHOT_NAMESPACE = SecureObjectNamespaceDefinition( key="live_notifications_snapshot", namespace="cadrumo.application.live.notifications_snapshot", owner="cadrumo.application.live", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="notifications-snapshot:{bucket_id}:{snapshot_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) LIVE_NOTIFICATION_DOCUMENT_NAMESPACE = SecureObjectNamespaceDefinition( key="live_notification_document", namespace="cadrumo.application.live.notification_document", owner="cadrumo.application.live", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="notification-document:{bucket_id}:{certificado_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) LIVE_JUSTIFICANTE_CAPTURE_SNAPSHOT_NAMESPACE = SecureObjectNamespaceDefinition( key="live_justificante_capture_snapshot", namespace="cadrumo.application.live.justificante_capture_snapshot", owner="cadrumo.application.live", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="justificante-capture-snapshot:{bucket_id}:{snapshot_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) LIVE_VERIFY_OBSERVATION_NAMESPACE = SecureObjectNamespaceDefinition( key="live_verify_observations", namespace="cadrumo.application.live.verify_observations", owner="cadrumo.application.live", sensitivity=SensitivityClass.IDENTITY, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="verify-observation:{bucket_id}:{observation_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) ATTACHMENT_BLOB_NAMESPACE = SecureObjectNamespaceDefinition( key="attachment_blobs", namespace="cadrumo.domain.attachments.blobs", owner="cadrumo.adapters.persistence.storage.attachment", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{sha256_hex}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) ATTACHMENT_MANIFEST_NAMESPACE = SecureObjectNamespaceDefinition( key="attachment_manifests", namespace="cadrumo.domain.attachments.manifests", owner="cadrumo.adapters.persistence.storage.attachment", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{attachment_id_sha256_hex}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) AEAT_BROWSER_SESSION_NAMESPACE = SecureObjectNamespaceDefinition( key="aeat_browser_sessions", namespace="cadrumo.outbound.aeat.auth.sessions", owner="cadrumo.adapters.outbound.aeat.auth", sensitivity=SensitivityClass.SESSION, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{storage_state_path_posix}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, # Three separately versioned authority-session metadata records ride this # one namespace. That a namespace can carry several is the clearest # statement that a namespace is not the unit of persisted format. record_formats=( "aeat_certificate_session_metadata", "aeat_clave_movil_session_metadata", "aeat_clave_permanente_session_metadata", ), ) CLAVE_MOVIL_DIAGNOSTICS_NAMESPACE = SecureObjectNamespaceDefinition( key="clave_movil_diagnostics", namespace="cadrumo.outbound.aeat.auth.clave_movil.diagnostics", owner="cadrumo.adapters.outbound.aeat.auth", sensitivity=SensitivityClass.SESSION, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{diagnostic_id_or_timestamp_iso}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) GOOGLE_OAUTH_CLIENT_NAMESPACE = SecureObjectNamespaceDefinition( key="google_oauth_client", namespace="cadrumo.google.oauth.client", owner="cadrumo.adapters.outbound.google", sensitivity=SensitivityClass.SECRET, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{profile}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) GOOGLE_OAUTH_TOKEN_NAMESPACE = SecureObjectNamespaceDefinition( key="google_oauth_token", namespace="cadrumo.google.oauth.token", owner="cadrumo.adapters.outbound.google", sensitivity=SensitivityClass.SECRET, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{profile}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) GOOGLE_OAUTH_METADATA_NAMESPACE = SecureObjectNamespaceDefinition( key="google_oauth_metadata", namespace="cadrumo.google.oauth.metadata", owner="cadrumo.adapters.outbound.google", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{profile}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) GOOGLE_DRIVE_CONFIG_NAMESPACE = SecureObjectNamespaceDefinition( key="google_drive_config", namespace="cadrumo.google.drive.config", owner="cadrumo.adapters.outbound.google", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{profile}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) GOOGLE_CREDENTIAL_SOURCE_NAMESPACE = SecureObjectNamespaceDefinition( key="google_credential_source", namespace="cadrumo.google.credential.source", owner="cadrumo.adapters.outbound.google", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{profile}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) LLM_CACHE_NAMESPACE = SecureObjectNamespaceDefinition( key="llm_cache", namespace="cadrumo.adapters.outbound.llm.cache", owner="cadrumo.adapters.outbound.llm", sensitivity=SensitivityClass.DIAGNOSTIC, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{logical_root}|{provider}|{model}|{prompt_hash}|{args_hash}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) LLM_USAGE_NAMESPACE = SecureObjectNamespaceDefinition( key="llm_usage", namespace="cadrumo.adapters.outbound.llm.usage", owner="cadrumo.adapters.outbound.llm", sensitivity=SensitivityClass.DIAGNOSTIC, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{logical_root}|{created_at_iso}|{request_id}|{uuid4_hex}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) LLM_RUN_TELEMETRY_NAMESPACE = SecureObjectNamespaceDefinition( key="llm_run_telemetry", namespace="cadrumo.adapters.outbound.llm.run_telemetry", owner="cadrumo.adapters.outbound.llm", sensitivity=SensitivityClass.DIAGNOSTIC, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{logical_root}|{started_at_iso}|{run_id}|{uuid4_hex}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) # The off-host evidence-consent audit trail. Unlike its three PROCESS_LOCAL # siblings above, this one is STRUCTURED_CUSTODY and carries no retention # sweep: it is the record a consent-withdrawal re-derivation reads to find # which artefacts depend on a cloud read, so an entry pruned away would make # the withdrawal silently incomplete. It holds the content ADDRESS, the # provider/model, and the surface that took the acknowledgement -- never the # document bytes, the prompt, or the response. LLM_EVIDENCE_CONSENT_LEDGER_NAMESPACE = SecureObjectNamespaceDefinition( key="llm_evidence_consent_ledger", namespace="cadrumo.adapters.outbound.llm.evidence_consent_ledger", owner="cadrumo.adapters.outbound.llm", sensitivity=SensitivityClass.IDENTITY, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{recorded_at_iso}|{evidence_content_address}|{uuid4_hex}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) AEAT_FILED_DECLARATION_ARTEFACTS_NAMESPACE = SecureObjectNamespaceDefinition( key="aeat_filed_declaration_artefacts", namespace="cadrumo.outbound.aeat.sede.filed_declaration.artefacts", owner="cadrumo.adapters.outbound.aeat.sede", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{sha256_hex}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) AEAT_FILED_DECLARATION_OBSERVATIONS_NAMESPACE = SecureObjectNamespaceDefinition( key="aeat_filed_declaration_observations", namespace="cadrumo.outbound.aeat.sede.filed_declaration.observations", owner="cadrumo.adapters.outbound.aeat.sede", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{sha256(modelo,ejercicio,period,expediente_id)}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) AEAT_IVA_WALLET_OBSERVATIONS_NAMESPACE = SecureObjectNamespaceDefinition( key="aeat_iva_wallet_observations", namespace="cadrumo.outbound.aeat.sede.iva_compensation_wallet.observations", owner="cadrumo.adapters.outbound.aeat.sede", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{sha256(taxpayer_nif,target_year,target_period,captured_at)}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) MODELO_REVIEW_PACKAGE_SIGNING_KEY_NAMESPACE = SecureObjectNamespaceDefinition( key="modelo_review_package_signing_key", namespace="cadrumo.application.modelo.review_package_signing_key", owner="cadrumo.application.modelo", sensitivity=SensitivityClass.SECRET, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="review-package-signing-key:{bucket_id}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) MODELO_REVIEW_PACKAGE_RECIPIENT_FINGERPRINT_REGISTRY_NAMESPACE = SecureObjectNamespaceDefinition( key="modelo_review_package_recipient_fingerprint_registry", namespace="cadrumo.application.modelo.review_package_recipient_fingerprint_registry", owner="cadrumo.application.modelo", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="default", default_object_key=SECURE_OBJECT_DEFAULT_KEY, scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) MODELO_REVIEW_PACKAGE_RECIPIENT_REPLAY_GUARD_NAMESPACE = SecureObjectNamespaceDefinition( key="modelo_review_package_recipient_replay_guard", namespace="cadrumo.application.modelo.review_package_recipient_replay_guard", owner="cadrumo.application.modelo", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="default", default_object_key=SECURE_OBJECT_DEFAULT_KEY, scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) MODELO_REVIEW_PACKAGE_RECIPIENT_ENCRYPTION_KEY_NAMESPACE = SecureObjectNamespaceDefinition( key="modelo_review_package_recipient_encryption_key", namespace="cadrumo.application.modelo.review_package_recipient_encryption_key", owner="cadrumo.application.modelo", sensitivity=SensitivityClass.SECRET, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="review-package-recipient-encryption-key:{bucket_id}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.PROCESS_LOCAL, ) BUCKET_EVENT_HISTORY_NAMESPACE = SecureObjectNamespaceDefinition( key="bucket_event_history", namespace="cadrumo.domain.buckets.event_history", owner="cadrumo.domain.buckets", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="catalogue", default_object_key=SECURE_OBJECT_CATALOGUE_KEY, scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) SUBMISSION_RECORDS_NAMESPACE = SecureObjectNamespaceDefinition( key="submission_records", namespace="cadrumo.domain.submission.records", owner="cadrumo.domain.submission", sensitivity=SensitivityClass.AUDIT, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{submission_id}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) JUSTIFICANTE_METADATA_NAMESPACE = SecureObjectNamespaceDefinition( key="justificante_metadata", namespace="cadrumo.domain.justificante.metadata", owner="cadrumo.domain.justificante", sensitivity=SensitivityClass.AUDIT, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{csv}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) FILING_DRAFTS_NAMESPACE = SecureObjectNamespaceDefinition( key="filing_drafts", namespace="cadrumo.domain.filing.drafts", owner="cadrumo.domain.filing", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V2, object_key_grammar="{draft_id}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) INVOICE_CATALOGUE_NAMESPACE = SecureObjectNamespaceDefinition( key="invoice_catalogue", namespace="cadrumo.domain.invoices", owner="cadrumo.domain.invoices", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="catalogue", default_object_key=SECURE_OBJECT_CATALOGUE_KEY, scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) TRANSACTION_CATALOGUE_NAMESPACE = SecureObjectNamespaceDefinition( key="transaction_catalogue", namespace="cadrumo.domain.transactions.bucket", owner="cadrumo.domain.transactions", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V2, # One secure-object row per transaction keyed transaction:{bucket_id}:{tx_id} # (transaction_object_key), plus a single per-bucket membership-index row keyed # transaction-index:{bucket_id} (transaction_index_object_key). The unrelated # transaction-catalogue:{bucket_id} token is a BucketEvent audit object_id, not # a secure-object key, and must not be conflated with this key grammar. object_key_grammar="transaction:{bucket_id}:{transaction_id}; transaction-index:{bucket_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) USAGE_RATIO_PROFILE_NAMESPACE = SecureObjectNamespaceDefinition( key="usage_ratio_profile", namespace="cadrumo.domain.usage_ratios", owner="cadrumo.domain.usage_ratios", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="profile:{bucket_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) MODELO_WORK_UNIT_CATALOGUE_NAMESPACE = SecureObjectNamespaceDefinition( key="modelo_work_unit_catalogue", namespace="cadrumo.domain.modelos.work_units", owner="cadrumo.domain.modelos", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="catalogue", default_object_key=SECURE_OBJECT_CATALOGUE_KEY, scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) MODELO_VERIFICATION_REPORT_CATALOGUE_NAMESPACE = SecureObjectNamespaceDefinition( key="modelo_verification_report_catalogue", namespace="cadrumo.domain.modelos.verification_reports", owner="cadrumo.domain.modelos", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="catalogue", default_object_key=SECURE_OBJECT_CATALOGUE_KEY, scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) MODELO_FILING_RECORD_CATALOGUE_NAMESPACE = SecureObjectNamespaceDefinition( key="modelo_filing_record_catalogue", namespace="cadrumo.domain.modelos.filing_records", owner="cadrumo.domain.modelos", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V2, object_key_grammar="catalogue", default_object_key=SECURE_OBJECT_CATALOGUE_KEY, scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) MODELO_EDIT_RECEIPT_NAMESPACE = SecureObjectNamespaceDefinition( key="modelo_edit_receipt", namespace="cadrumo.application.modelo.edit_receipts", owner="cadrumo.application.modelo", # The receipt is the domain proof a guarded compare-and-swap edit # committed: work identity, resulting calculation-revision id, and # bucket-event id. No financial value or raw input ever reaches it, but # the identity triple it does carry is the same evidentiary provenance a # ledger confirmation record carries, so it shares that FULL_CUSTODY_ONLY # posture rather than the lighter structured-custody one. sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{receipt_id}", scope=StorageNamespaceScope.BUCKET_LOCAL, custody_disposition=StorageCustodyDisposition.FULL_CUSTODY_ONLY, ) MODELO_CALCULATION_REVISION_CATALOGUE_NAMESPACE = SecureObjectNamespaceDefinition( key="modelo_calculation_revision_catalogue", namespace="cadrumo.domain.modelos.calculation_revisions", owner="cadrumo.domain.modelos", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V4, object_key_grammar="catalogue", default_object_key=SECURE_OBJECT_CATALOGUE_KEY, scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.STRUCTURED_CUSTODY, ) TRANSACTION_PARTICIPATION_INDEX_NAMESPACE = SecureObjectNamespaceDefinition( key="transaction_participation_index", namespace="cadrumo.domain.modelos.participation_index", owner="cadrumo.domain.modelos", sensitivity=SensitivityClass.FINANCIAL, schema_version=SECURE_OBJECT_SCHEMA_VERSION_V1, object_key_grammar="{transaction_id}", scope=StorageNamespaceScope.PROFILE_LOCAL, custody_disposition=StorageCustodyDisposition.DERIVED_REBUILDABLE, # Enrolled and classified on its own axis, though its version constant is # read straight off this namespace's ``schema_version`` rather than declared # independently -- the softest case in this field, recorded rather than # smoothed over. record_formats=("participation_index",), ) DOMAIN_NAMESPACE_DEFINITIONS = ( BUCKET_EVENT_HISTORY_NAMESPACE, SUBMISSION_RECORDS_NAMESPACE, JUSTIFICANTE_METADATA_NAMESPACE, FILING_DRAFTS_NAMESPACE, INVOICE_CATALOGUE_NAMESPACE, TRANSACTION_CATALOGUE_NAMESPACE, USAGE_RATIO_PROFILE_NAMESPACE, MODELO_WORK_UNIT_CATALOGUE_NAMESPACE, MODELO_VERIFICATION_REPORT_CATALOGUE_NAMESPACE, MODELO_FILING_RECORD_CATALOGUE_NAMESPACE, MODELO_CALCULATION_REVISION_CATALOGUE_NAMESPACE, TRANSACTION_PARTICIPATION_INDEX_NAMESPACE, )