Source code for exlab_wizard.cache.sync_state_schema

"""``msgspec.Struct`` types for the per-run ``sync_state.json`` cache.

Operator-free per-file NAS sync design (2026-05-21). These structs live in
the dependency-free ``cache`` package -- not ``api.schemas`` -- so the
``cache``, ``sync``, and ``orchestrator`` modules can import them (and
:class:`~exlab_wizard.cache.sync_state_writer.SyncStateWriter`) at module
scope without re-entering the ``api`` package and forming a circular
import. ``api.schemas`` re-exports both names so the wider "single source
of truth for cache schemas" surface is preserved for API callers.
"""

from __future__ import annotations

from msgspec import Struct

__all__ = ["FileSyncRecord", "SyncStateJson"]


[docs] class FileSyncRecord( Struct, omit_defaults=True, forbid_unknown_fields=False, ): """Per-file sync record stored under ``sync_state.json``'s ``files`` map. One record per run-relative POSIX path. These records are *freely mutated in place* by ``SyncStateWriter`` as a file is synced, re-modified, and re-synced. * ``synced_signature`` -- the ``(st_size, st_mtime_ns)`` captured at the last successful sync. ``None`` means the file has never synced. A file whose current signature differs is "modified since sync" and becomes eligible again once it re-settles. * ``verified_at`` -- the ISO-8601 timestamp at which the file's SHA-256 was confirmed against the NAS copy. ``None`` until verified; a file counts toward the ``SYNCED`` rollup only once this is set. * ``keep_local`` -- when ``True`` the file still syncs to the NAS but is excluded from cleanup deletion. * ``verified_sha256`` -- the SHA-256 hex digest of the local bytes captured at sync time. Slot A of the 2026-05-26 rclone-only migration: ``rclone check --download --combined`` confirms the NAS copy matches the local source, and we record the local SHA here so the offline-audit affordance lost by dropping ``checksums.sha256`` is preserved without any wire cost. ``None`` for records that pre-date the migration or for files synced via the legacy verify path; reads must tolerate its absence. """ synced_signature: tuple[int, int] | None = None verified_at: str | None = None keep_local: bool = False verified_sha256: str | None = None
[docs] class SyncStateJson( Struct, omit_defaults=True, forbid_unknown_fields=False, ): """``sync_state.json`` per-run sync-state record at schema version 1.0. Written by the orchestrator only. A *freely-mutable current-state map* (not append-only): ``files`` maps a run-relative POSIX path to its :class:`FileSyncRecord`. ``cleared_at`` is set once the run's staging copy has been cleaned up. The run-level ``SYNCING``/``SYNCED``/``CLEARED`` rollup is derived on read from this payload, never persisted as such. """ schema_version: str cleared_at: str | None = None files: dict[str, FileSyncRecord] = {}