Skip to content

Inspect a damaged archive

You have an archive that fails verification, or one you do not trust, and you want to see exactly what is wrong without loading it into an application.

Sample.load uses the same bounded reader and refuses a damaged archive exactly as Mtrl.load() does, so this forensic route stays the recovery path.

This guide assumes: you have finished the tutorial path, including Save, load, and verify, and you know that verification reports several separate statuses rather than one yes/no answer.

Mtrl.load() refuses a damaged archive outright, which protects your data but tells you little about the damage. forensic_inspect(path) is the read-only alternative: it examines the bounded archive and returns a VerifyResult of facts — what is structurally sound, which digests disagree, and which entries are affected — without ever returning the damaged records as analysis inputs.

The example below saves a sound archive and inspects it, so you can see the shape of the report before you ever meet a damaged one.

from pathlib import Path
from tempfile import TemporaryDirectory
import numpy as np
from mtrl import InstrumentRun, MaterialData, Mtrl, forensic_inspect
application = Mtrl(sample_id="polymer-film-01")
run = InstrumentRun(run_name="ftir-replicate-01")
run.add_checkpoint(
MaterialData(
content=np.array([0.15, 0.21, 0.19]),
type="raw",
checkpoint_name="spectrum",
)
)
application.add(run)
with TemporaryDirectory() as directory:
archive_path = application.save(Path(directory) / "polymer-film-01.mtrl")
result = forensic_inspect(archive_path)
print(f"structural status: {result.structural_status.value}; issues: {len(result.issues)}")
structural status: valid; issues: 0

The print shows structural status: valid; issues: 0: the archive is structurally well formed and there are no findings. On a damaged archive the same two values carry the diagnosis — a structural_status of invalid or a digest status of inconsistent, plus one entry in result.issues per finding.

forensic_inspect(archive_path) read the archive through the same bounded reader that guards every load, then reported what it could determine safely. The result keeps the separate verification statuses independent: structural_status (is the archive well formed), hash_status (do the bytes match their recorded digests), plus anchor_status, coverage_status, and source_closure_status. There is deliberately no aggregate verified flag, because a damaged archive can be sound in one layer and broken in another, and you need to know which.

Each finding in result.issues is one ordered fact, not a verdict. An issue carries a code naming the failed check, a state such as not-checked, and — where the check could determine them — the entry_path of the affected archive entry, the digest_layer, the expected and observed values, and a blocked_by note when one failure prevented a later check from running. Reading them in order reconstructs what happened to the file.

Notice the boundary the inspection keeps. It reports structural and digest facts and stops there. It does not repair the archive, and it does not make damaged records valid analysis inputs — the purpose is to let you see the damage and decide what to do, not to let the damaged data back into your work.

Caution — Forensic inspection is read-only evidence gathering. Never treat its findings as a repair, and never route a damaged archive back into analysis because the report looked small. If you hold a receipt for the archive, verify the archive against that anchor as well, so you know whether the whole file was replaced.