14  Attribution

Stage 2: which layer caused a defect class

14.1 Why attribution comes first

A repair removes a defect class only if it changes the layer that produced it. A normalizer cannot restore text that the engine never transcribed; a new OCR pass cannot correct a DTD that forbids a structure the source prints. The attribution assigns each class one layer before any remedy is chosen.

14.2 Layers

Layer The defect is The remedy changes
reocr text missing from the page nothing in code; the next engine of the chain transcribes the page
prompt-overlay wrong structure produced by the engine the engine’s overlay (or the shared base template)
normalizer a deterministic rewrite of the XML repairs it the collection’s normalizer module
css the XML is right, the rendering is wrong page.css
dtd the schema lacks a structure the source prints page.dtd via schema-derive
engine one engine fails where another succeeds the order of engine_chain
source the scan is defective a new scan

14.3 Sources of the assignment

  1. The collection’s config/audit_rules.yaml: the field layer of a structure rule or a cue rule. It takes precedence.
  2. pdai/skills/pipeline/pdai-cure/defect_layers.yaml assigns the text-validity codes, which have no per-collection rule.
  3. The fault dossier of pdai-audit: the fix type of its cases (prompt_overlay, normalizer, normalizer_map, dtd_schema). A code whose cases name one layer takes it; the compound type prompt_and_normalizer names two layers and leaves the code unattributed.

14.4 Defect codes and their layers

Structure codes (layer from audit_rules.yaml of copernicus-prim):

Code Defect Layer
LOOP-REP generation loop: padding or one unit repeated prompt-overlay
TRUNC output stops before </page> prompt-overlay
NORM-REOCR the normalizer cut a loop or closed a truncated page reocr
EMPTY-MAIN <main> nearly empty although the scan carries ink reocr
TABLE-FLAT a number grid transcribed as pipe-separated <p> rows prompt-overlay
DUP-BLOCK an apparatus entry or note transcribed twice prompt-overlay
FN-BIJECTION a marker without its note prompt-overlay
FN-MARKER a note without a marker normalizer
TAG-VARIANT HTML tags or legacy footnote forms normalizer

Text-validity codes (layer from defect_layers.yaml):

Code Defect Layer
TXT-PAGE-LOST most of the page text is missing reocr
TXT-GAP two or more consecutive scan lines missing reocr
FN-MISSING a printed note number without <footnote> reocr
FN-PARTIAL a footnote shorter than its scan lines reocr
TXT-EXCESS XML text without a counterpart in the scan prompt-overlay
BODY-IN-FN body lines filed as a note prompt-overlay
FN-IN-BODY note lines filed as body text prompt-overlay
SEG-ORDER zones out of the scan’s reading order prompt-overlay

Codes of the collection’s cue rules (SCH-*) carry no layer until the owner assigns one. On 2026-09-26 the baseline found SCH-APPARATUS (copernicus-prim, GW-II and GW-IV, 7 pages) and SCH-REGEST-MISSING, SCH-SALUTATION-MISSING (pirckheimer, 3 pages) unattributed. LN-DRIFT (marginal line numbers out of step with the lines) is a candidate code of the line-numbered editions without a rule.

14.5 Output and gate

The op pdai:cure_attribute collects the flags of fail and warn pages, every code of the pdai-audit defect register (quality/<doc>_defects.json) and the codes of the fault dossier, and produces one class per code: page count, layer, anchor, the source of the layer and the first five pages as specimen candidates. A code without a layer from any source is listed as unattributed and fails the stage. The role attribute-uncoded (kimi-k2.7-code:cloud, fallback gemini-3.8-flash) may propose a layer; the owner confirms it before it is written into the rule file.