exlab_wizard.cache.ingest_writer#

Orchestrator-only writer for ingest.json. Backend Spec §13.4, §4.4.5.

The orchestrator writes one ingest.json per staged run, capturing the five-state lifecycle (§13.3): staging -> complete -> sync_queued -> sync_verified -> cleared. State transitions are append-only – a new entry is added to the history array on every transition, and the top-level current_state mirrors the latest entry.

Disk-side guarantees per §4.4.5:

  • msgspec.json for typed encode/decode (schema validation in one pass).

  • filelock.FileLock advisory exclusive lock around the read-mutate-write cycle so concurrent appends never lose entries.

  • Atomic write via tempfile + fsync + os.replace.

Reads enforce the §11.9.2 reader policy: a file at a different schema major than the writer raises SchemaMajorMismatchError (no silent partial-parse across major boundaries).

Functions

default_host()

Return socket.gethostname() (orchestrator default for host).

Classes

IngestWriter()

Writer for ingest.json.

class exlab_wizard.cache.ingest_writer.IngestWriter[source]#

Bases: object

Writer for ingest.json. Orchestrator-mode only.

Backend Spec §13.4. State history is append-only (§13.3) to preserve full audit history – the writer never edits or deletes prior entries.

All public methods are async to match the §4.4.5 CacheWriter contract; the blocking lock + I/O work is dispatched through asyncio.to_thread so the FastAPI event loop is never blocked.

async append_state_transition(path, new_state, *, host, files_received=None, bytes_received=None, nas_path=None, checksum_file=None)[source]#

Append a state-transition entry and update current_state.

File-locked for the entire read-mutate-write cycle so concurrent callers never lose entries. The new history entry has the shape:

{"state": "<new_state>", "at": "<UTC ISO 8601>", "host": "<host>"}

Per §13.4 the entry carries optional extras when transitioning to specific states:

  • completefiles_received and bytes_received.

  • sync_verifiednas_path and checksum_file.

Other state transitions ignore those extras (they are silently dropped because the spec does not define their meaning at those states).

Raises ValueError if new_state is not a permitted forward transition from the file’s current state. Going backward (e.g. cleared -> staging) is rejected. The full state machine is documented in _FORWARD_TRANSITIONS above and §13.3.

Parameters:
Return type:

IngestJson

async read_ingest(path)[source]#

Read and decode path into an IngestJson.

Raises SchemaMajorMismatchError (§11.9.2) when the on-disk file carries a different schema major than INGEST_JSON_VERSION.

Parameters:

path (Path)

Return type:

IngestJson

async write_ingest(path, payload)[source]#

Write payload to path atomically under an exclusive lock.

Reserved for the initial-creation path (no file exists yet); the per-file lock is taken defensively so a concurrent initial-write attempt serializes rather than races.

Parameters:
Return type:

None