exlab_wizard.sync.verifier#

SHA-256 verifier wrapper around rclone check --download.

Rclone-only NAS sync migration (2026-05-26). The verifier is now a thin adapter over exlab_wizard.sync.transports.rclone.RcloneDriver.check() that translates a CheckResult into the VerifyResult shape the queue worker already consumes. The actual integrity guarantee comes from rclone check --download --combined – rclone streams the remote files back to the wizard, hashes them locally, and writes a =/*/+/-/! line per file to a tempfile that the driver parses.

The Slot A SHA-256 capture (the durable sync_state.json:files[*].verified_sha256 field) is owned by exlab_wizard.sync.nas_client._compute_local_shas() – the verifier itself never sees a local SHA. This keeps the verifier a leaf abstraction that depends only on the rclone driver, and keeps the SHA-capture logic local to the one code path that has access to the freshly-read local bytes.

The previous Python SHA pipeline and the durable <run>/.exlab-wizard/checksums.sha256 artefact are gone (the spec chose rclone check as the authority on integrity at sync time).

Classes

Verifier([driver])

Verifier: rclone check wrapper, no Python SHA pipeline.

VerifyResult(ok[, mismatched, missing, ...])

Outcome of one rclone check --download pass against a remote.

class exlab_wizard.sync.verifier.Verifier(driver=None)[source]#

Bases: object

Verifier: rclone check wrapper, no Python SHA pipeline.

Constructed with an RcloneDriver; production callers pass the same driver instance the push path uses so subprocess settings (binary path, etc.) stay consistent. Tests can pass a stub driver whose check returns a canned CheckResult.

Parameters:

driver (RcloneDriver | None)

async verify(run_path, remote, *, files_from)[source]#

Run rclone check --download over files_from and translate.

Raises TransportError from the driver only on a spawn failure (the rclone binary is missing); every other failure mode – auth / network / hash-mismatch – is folded into the returned VerifyResult.

Parameters:
Return type:

VerifyResult

class exlab_wizard.sync.verifier.VerifyResult(ok, mismatched=(), missing=(), extra=(), errors=(), error_kind=None, verified=())[source]#

Bases: object

Outcome of one rclone check --download pass against a remote.

ok is True iff no files differ, none are missing on the destination, and the rclone subprocess reported no per-file errors. Files in mismatched / missing / errors are run-relative POSIX paths drawn from the --combined output. extra lists files present on the destination but not in the source – it does not flip ok (it is informational, mirroring the pre-migration contract).

error_kind is set when the rclone subprocess itself failed (auth / network / unknown) before producing usable combined output. The queue worker keys off this field to route through the spec §7.1.5 retry policy.

Parameters:
error_kind: TransportErrorKind | None#
errors: tuple[str, ...]#
extra: tuple[str, ...]#
classmethod from_check_result(check_result)[source]#

Translate a successful rclone check into a VerifyResult.

ok is True iff nothing differs, nothing is missing on the destination, and rclone reported no per-file errors. extra (present on the destination only) is carried for reporting but does not flip ok. The single source of truth for the CheckResult -> VerifyResult mapping shared by the queue worker, the force_verify path, and Verifier.verify().

Parameters:

check_result (CheckResult)

Return type:

VerifyResult

mismatched: tuple[str, ...]#
missing: tuple[str, ...]#
ok: bool#
verified: tuple[str, ...]#