15  Remedy and gate

Stages 3 and 4: one change, tested on 3–5 pages

15.1 Stage 3 — Remedy

A remedy is the smallest change on the attributed layer. The iteration declares it as input of the Partitur:

remedy:
  kind: normalizer          # normalizer | reocr | overlay
  code: FN-MARKER
  specimen: [copernicusGW-IV/page_127, copernicusGW-IV/page_347, copernicusGW-IV/page_553]

Without a specimen list the first pages of the class are taken. All specimen pages come from one document, so that the gate runs against one document’s settings and placement rule.

Kind How the remedy is made
normalizer a rule in the collection’s normalizer module, loaded through cure.yaml normalizer.module; generic tree rules live in ocr_runner/tree_rules.py
reocr no code change; the next engine of engine_chain transcribes the page
overlay a new overlay version proposed and A/B-tested by ocr_runner.cure_learn

15.1.1 Document normalizers

A collection registers its document-level normalizer in the shared registry of ocr_runner/normalize.py:

from .normalize import DocumentNormalizer, register_document
register_document("copernicus-prim", DocumentNormalizer(
    id=NORMALIZER_ID, normalize_document=normalize_document, page_hook=copernicus_hook))

normalize_apply and the runner find the module through cure.yaml; a module that does not register itself raises an error instead of running without rules.

15.1.2 Overlay revision

.venv/bin/python -m ocr_runner.cure_learn --collection <c> --engine kimi --rounds 1

The learning sample is the sample_pages list of agent-store/ocr_instruction_learning_agent/<c>.partitur.setting.yaml. It must contain pages with the defect. On copernicus-prim, three screenshot pages already scored 1.000 under the current kimi overlay; an A/B on those three pages could not show any difference between two authors (see Reference).

15.2 Stage 4 — Gate

# normalizer: specimen normalized in memory, nothing written
.venv/bin/python -m ocr_runner.normalize_apply --collection <c> --doc <d> --specimen 127,347,553
# re-OCR or overlay: pilot tree under <tmp>/pilot/<d>/<stamp>/
.venv/bin/python -m ocr_runner.cure_run --collection <c> --doc <d> --pilot --sample 5 --also 127,347,553

The two gates check different properties.

Gate A specimen page passes when
normalizer (normalize_apply --specimen) the rule changes the page (a no-op fails), the result is well-formed, applying the rule again changes nothing (idempotent), and the word sequence is preserved except for rejoined hyphenations
re-OCR and overlay (cure_run --pilot) the best engine answer reaches verdict ok without a reject code (LOOP-REP, TRUNC, SYN-WELLFORMED), or the current XML is already valid and is kept; no page is deferred by the budget

The normalizer gate stores for every passed page the hash of the source XML and the structural_hash of the result in <data>/quality/<d>_norm_gate.json. --apply refuses when the gate is missing, belongs to another normalizer version, or when a specimen page changed after the gate.

For a document of more than 50 pages the pilot adds five random pages to the specimen. That is the obligatory pilot gate of book-sized documents; the random pages show whether the remedy damages pages that were not defective.

Both commands exit 0 only on PASS. The op pdai:cure_gate reads the exit code and the verdict and publishes a FAIL as an error, so the stage grades FAILED and the Partitur does not reach stage 5.