aeat.application.diagnostics module

Application-owned diagnostics, version reports, and repair probes.

build_cli_version_report() and render_cli_version_text() back the root aeat --version surface. They keep the fast path import-light unless the caller requests registry detail.

build_config_repair_report() composes environment checks, WorkflowState loading, ActiveProfileHealth profile storage verdicts, WizardStatusReport readiness, registry summaries, and secure-object decryptability into a ConfigRepairReport of DiagnosticCheck rows. The full registry integrity probe is intentionally opt-in through RegistryIntegrityReport; it loads the registry authority only for repair commands that ask for that validation.

Every warn/fail DiagnosticCheck is actionable by construction: it must carry either next_action or dead_end and the validator raises DiagnosticModelError if a row is silent or ambiguous. Renderers and CLI payloads can therefore treat the repair report as a typed contract, not a best-effort text scan.

Secure-object repair helpers return SecureObjectIntegrityReport instances shared with application.repair_integrity. Dry-run preview and quarantine use the same decryptability probe so the committed mutation has the same namespace counts the operator saw before confirming it. Registry validation routes through ValidatedRegistryAuthority and the core Modelo identifier enum only on the explicit repair-integrity path.

See also

application.repair_integrity owns metadata-only repair decisions and active-bucket repair sessions. application.workflow._profile_health supplies the redacted active-profile health verdict when secure workflow state is readable or degraded. application.wizard._status supplies semantic profile/auth readiness once the workflow state has loaded. entrypoints.cli._config._repair_cli wires these reports into aeat config repair commands.

class RegistryVersionSummary(**data)[source]

Bases: BaseModel

Stable registry summary suitable for version and repair surfaces.

Built from ValidatedRegistryAuthority when registry detail is requested, then embedded in both CliVersionReport and ConfigRepairReport.

Parameters:
  • available (bool)

  • registry_root (str)

  • modelo_count (int)

  • revision_count (int)

  • casilla_count (int)

  • formula_count (int)

  • revision_ids (tuple[str, ...])

  • error (str | None)

available: bool
registry_root: str
modelo_count: int
revision_count: int
casilla_count: int
formula_count: int
revision_ids: tuple[str, ...]
error: str | None
class CliVersionReport(**data)[source]

Bases: BaseModel

Version payload rendered by root CLI version surfaces.

build_cli_version_report() fills the RegistryVersionSummary field, and render_cli_version_text() renders the text form used by the root aeat --version command.

Parameters:
package_name: str
package_version: str
registry: RegistryVersionSummary
DiagnosticAudience

Who can act on a check.

operator rows describe a state the taxpayer can themselves resolve (an incomplete profile, a missing certificate). internal rows describe an application-side defect the taxpayer cannot fix (a registry-integrity regression). The renderer words the two distinctly so a taxpayer is never alarmed into thinking an internal bug is a field they forgot to fill in.

alias of Literal[‘operator’, ‘internal’]

class DiagnosticFinding(**data)[source]

Bases: BaseModel

One concrete, named sub-finding inside a DiagnosticCheck.

A bare counter (31/40) or a one-word verdict (warn) tells the operator that something is wrong but never what. Each finding names one specific cause in operator language and, where an automated route exists, the exact aeat ... command that resolves it. The profile-keys check emits one finding per unset key; a failing check emits one finding per concrete cause. Findings are explanatory children, not a replacement for the parent row’s required next_action or dead_end recovery channel.

Parameters:
  • summary (str)

  • detail (str | None)

  • next_action (str | None)

  • requirement (Literal['required', 'optional'] | None)

summary: str
detail: str | None
next_action: str | None
requirement: Literal['required', 'optional'] | None
class DiagnosticCheck(**data)[source]

Bases: BaseModel

One concrete config repair check.

A failing or warning row MUST carry exactly one of next_action (an exact aeat ... command string the operator can run) or dead_end (a short explanation of why no automated route exists). A row that supplies neither, or both, is a pydantic.ValidationError at construction time by raising DiagnosticModelError. ok rows MUST carry neither.

findings carries the per-cause breakdown: the specific keys that are unset, the specific reasons a check failed. audience records whether the operator can act on the row or whether it reports an internal application defect. render_config_repair_text() and ConfigRepairReport preserve this distinction.

Parameters:
name: str
status: DiagnosticStatus
summary: str
detail: str | None
next_action: str | None
dead_end: str | None
audience: DiagnosticAudience
findings: tuple[DiagnosticFinding, ...]
class SecureObjectIntegrityReport(**data)[source]

Bases: BaseModel

Aggregated decryptability counts across every populated namespace.

Surfaces how many rows of the local secure_objects table can be decrypted under the current master key. A non-zero unreadable total almost always means the keychain master-key entry was rotated or regenerated since the affected rows were written; the plaintexts are cryptographically unrecoverable from this process.

namespaces carries SecureObjectNamespaceIntegrity rows produced by the encrypted SecureObjectRepository. The same aggregate shape is shared by ConfigRepairReport, RepairIntegrityReport, preview_quarantine_unreadable_secure_objects(), and quarantine_unreadable_secure_objects().

Parameters:
namespaces: tuple[SecureObjectNamespaceIntegrity, ...]
readable_total: int
unreadable_total: int
class ConfigRepairReport(**data)[source]

Bases: BaseModel

Composite report rendered by the bare aeat config repair command.

The report combines the public RegistryVersionSummary, the secure-object SecureObjectIntegrityReport, and ordered DiagnosticCheck rows into one operator-facing health payload. setup is a redacted WizardStatusReport when WorkflowState can be loaded. build_config_repair_report() is the producer, and render_config_repair_text() is the compact text renderer.

Parameters:
overall: DiagnosticStatus
package_name: str
package_version: str
python_version: str
log_file: str
registry: RegistryVersionSummary
setup: WizardStatusReport | None
secure_objects: SecureObjectIntegrityReport
checks: tuple[DiagnosticCheck, ...]
class RegistryIntegrityReport(**data)[source]

Bases: BaseModel

Result of the opt-in full registry-validation probe.

Disaster ADR Ruling 4 moves the full registry TOML parse + cross-domain referential-integrity gate off the --version and bare-invocation surfaces into the explicit aeat config repair integrity registry verb. This typed report is what that verb renders: a RegistryVersionSummary plus the aggregate DiagnosticCheck from _registry_cross_domain_integrity_check().

Parameters:
registry: RegistryVersionSummary
check: DiagnosticCheck
build_cli_version_report(registry_root=None, *, with_registry=True)[source]

Return the package and registry summary for CLI version surfaces.

The with_registry flag controls whether the full registry TOML load fires. The CLI root callback passes with_registry=False for bare aeat --version invocations (the fast-path mandated by disaster ADR Ruling 4 — the operator must see name + version in under a second on cold start). When --detail is on, the caller re-invokes with with_registry=True to populate the registry summary.

Returns a CliVersionReport whose registry field is either the fast-path empty RegistryVersionSummary or the detailed summary from ValidatedRegistryAuthority.

Return type:

CliVersionReport

Parameters:
  • registry_root (Path | None)

  • with_registry (bool)

build_config_repair_report(registry_root=None)[source]

Return local diagnostics for the aeat config repair surface.

Returns a ConfigRepairReport enumerating every diagnostic check and any suggested repairs. Expensive registry validation beyond the rollup check remains in build_registry_integrity_report(), so the bare repair command stays focused on actionable local health.

The secure-state branch reads WorkflowState, derives ActiveProfileHealth, and builds a WizardStatusReport. If that load fails, the report still emits profile and auth rows from the redacted health verdict so repair remains usable on a cold or degraded storage root. Each emitted warning/failure row is validated by DiagnosticCheck so the caller never receives a silent repair finding.

Return type:

ConfigRepairReport

Parameters:

registry_root (Path | None)

probe_browser_connectivity(settings=None)[source]

Probe the configured AEAT browser target through the browser adapter.

Returns a SiteHealthStatus.

Return type:

SiteHealthStatus

Parameters:

settings (Settings | None)

render_browser_connectivity_text(status)[source]

Render one site-health status as compact repair output.

Return type:

str

Parameters:

status (SiteHealthStatus)

render_config_repair_text(report)[source]

Render a compact human-readable repair report.

Preserves DiagnosticCheck.audience and the mutually exclusive next_action / dead_end contract so operator-actionable rows and internal application defects are visibly different in text output.

Return type:

str

Parameters:

report (ConfigRepairReport)

build_registry_integrity_report(registry_root=None)[source]

Run the full registry validation as a standalone RegistryIntegrityReport probe.

Backs the aeat config repair integrity registry verb. Bundles the registry version summary with the cross-domain referential-integrity check so the engineer-facing verb can render both the registry’s identity and its validation verdict. Disaster ADR Ruling 4 keeps this off every fast-path surface.

Return type:

RegistryIntegrityReport

Parameters:

registry_root (Path | None)

render_cli_version_text(report)[source]

Render a compact text line for human-facing version output.

Return type:

str

Parameters:

report (CliVersionReport)

secure_object_unreadable_total()[source]

Return the count of rows the current master key cannot decrypt.

Lightweight wrapper over _probe_secure_objects_integrity() for consumers (notably aeat app overview status) that want to surface a concise “N rows unreadable” pointer towards aeat config repair without rendering the per-namespace breakdown themselves. The full breakdown remains the authority of ConfigRepairReport.

Return type:

int

preview_quarantine_unreadable_secure_objects()[source]

Report the rows repair quarantine would move, mutating nothing.

Backs the aeat config repair quarantine --dry-run preview. Runs the same per-namespace decryptability probe that quarantine_unreadable_secure_objects() uses to decide which rows to archive, but performs no copy and no delete: the secure_objects table is left exactly as found. The returned SecureObjectIntegrityReport carries, per namespace, the unreadable count (= rows the non-dry-run verb would quarantine) and the readable count (= rows it would retain), so the operator can confirm the blast radius before committing - the same preview shape reset-progress --dry-run already offers.

Return type:

SecureObjectIntegrityReport

quarantine_unreadable_secure_objects()[source]

Move every undecryptable secure-object row into the quarantine table.

Delegates to quarantine_unreadable_rows(), which creates the secure_objects_quarantine archive table on first use, copies each undecryptable row’s metadata and (still encrypted) payload into the archive, then deletes the row from the active secure_objects table. Decryptable rows are not touched.

The user’s ciphertext is preserved in the archive; nothing is auto-deleted. If a missing master key is later recovered (e.g. restored from a recovery-key backup), the operator can manually re-import rows from the quarantine table.

Return type:

SecureObjectIntegrityReport

Returns:

A SecureObjectIntegrityReport whose namespaces report carries per-namespace unreadable counts (= rows moved to quarantine) and readable counts (= rows retained in secure_objects).

ensure_models_rebuilt()

Resolve the deferred forward references on the heavy report models.

SecureObjectIntegrityReport and ConfigRepairReport carry fields typed by SecureObjectNamespaceIntegrity and WizardStatusReport. Those names are imported lazily so the aeat --version fast path never pulls the heavy secure-object and wizard-status import subtrees. The two models are only ever constructed by the diagnostics functions below — never by the version path — so their forward references are resolved here, on first use of a heavy function, when the real types are imported anyway. Idempotent: the rebuild runs once per process.

Return type:

None

profile_check(report, *, profile_health=None, state=None)

Render semantic profile readiness from wizard status plus workflow state.

report supplies the WizardStatusReport counters and next action. profile_health can override the row when ActiveProfileHealth says the active profile bucket is unavailable. state lets the check expand missing profile keys from WorkflowState into per-key DiagnosticFinding rows.

Return type:

DiagnosticCheck

Parameters:
registry_cross_domain_integrity_check(registry_root)

Cross-domain integrity check by exercising the snapshot-build gate.

Loads ValidatedRegistryAuthority (which runs validate_registry at construction time) and attempts to build a representative snapshot for Modelo member M100. The snapshot-build path wires _check_all_id_references() (typed-ID existence checks + renta first-slice routing target check + per-binding selector- shape gate); any divergence between code-side typed contracts and registry data surfaces here as a typed failure.

A failure routes the operator to a structured diagnostic rather than a runtime KeyError mid-calculation.

Return type:

DiagnosticCheck

Parameters:

registry_root (Path)