# Tolerance & diagnostics Real-world IIIF is imperfect. iiisight's core promise is that **normalization never raises on a spec-imperfect document** — it repairs what it can and records each repair as a {class}`~iiisight.Diagnostic`. (This is distinct from *transport* failures like a 404 or non-JSON body, which do raise {class}`~iiisight.FetchError`.) ## Diagnostics Every normalized document carries a `diagnostics` tuple: ```python manifest = iiisight.normalize(document) for d in manifest.diagnostics: print(d.severity, d.code, d.path, d.message, d.recovered) ``` Each {class}`~iiisight.Diagnostic` has: - `code` — a stable machine code (e.g. `"coerced-language-map"`, `"upgraded-v2-to-v3"`). - `severity` — a {class}`~iiisight.Severity`: - `INFO` — spec-sanctioned normalization (a default the spec allows, or a v2→v3 upgrade). - `WARNING` — a deviation repaired without losing information (missing recommended field, coerced type). - `ERROR` — something that could not be represented and was dropped/skipped; the model is lossy at `path` but still usable — and it still did not raise. - `path` — a JSON pointer to the offending node. - `recovered` — what was assumed, coerced, or skipped. For example, a manifest whose `label` is a bare string instead of a language map is coerced (`{"none": ["…"]}`) and flagged with a `coerced-language-map` warning — you get a usable label *and* a record that the source was non-conforming. ## The lint The lint is a reporting view over those diagnostics — *"what did a real client have to guess or fix to read this document?"* It is client-compatibility feedback, not a strict spec-conformance check. ```python report = iiisight.lint(manifest) # accepts a Manifest/Collection or a raw dict report.ok # True if nothing beyond INFO occurred report.summary() # "1 error(s), 2 warning(s), 3 info" for problem in report.errors: # also .warnings, .infos print(problem.code, problem.path, problem.message) report.counts() # {Severity.ERROR: 1, ...} ``` You can lint a document you have not fetched yet by passing a URL through a client first: ::::{tab-set} :::{tab-item} Async ```python async with iiisight.AsyncClient() as client: manifest = await client.fetch_manifest(url) report = iiisight.lint(manifest) print(report.summary()) ``` ::: :::{tab-item} Sync ```python with iiisight.Client() as client: manifest = client.fetch_manifest(url) report = iiisight.lint(manifest) print(report.summary()) ``` ::: :::: ## Why tolerance matters Running iiisight against production manifests (Wellcome, the Bodleian) surfaces real deviations — e.g. a search service with a bare-string `label` where v3 requires a language map. A stricter parser would reject those documents outright; iiisight reads them *and* tells you what it had to repair.