16 Application
Stage 5: flagged pages only
16.1 Commands
pgrep -fl "cure_run|cure_learn|normalize_apply|ai-scholar process" # must print nothing
.venv/bin/python -m ocr_runner.normalize_apply --collection <c> --doc <d> --apply [--only 127,347]
.venv/bin/python -m ocr_runner.cure_run --collection <c> --doc <d> --worklist \
--max-pages 40 --max-minutes 90normalize_apply --apply refuses unless the specimen gate passed for the same normalizer version. cure_run --worklist processes the document’s worklist from pdai-validity.
16.2 The worklist
The worklist holds only pages with verdict fail. For each page it names the next engine to try: the page walks the collection’s engine_chain, skipping engines already tried on it, including the one that produced the current XML. gemini-3.8-flash comes only after every engine of the chain has failed on the page. Pages with verdict warn are listed for review; pages with verdict ok never appear.
16.3 Runner guards
| Guard | Value (copernicus-prim) | Effect |
|---|---|---|
num_predict |
4096 | bounds a generation loop |
repeat_penalty |
1.1 | reduces repeated units |
| reject codes | LOOP-REP, TRUNC, SYN-WELLFORMED |
the answer is discarded, the next engine is tried |
| page budget | 40 pages | later pages are deferred |
| time budget | 90 minutes | later pages are deferred |
Every overwritten page XML is kept as a backup next to it. Each engine answer is ranked by the audit (blockers, validity verdict); the best answer is written, and a page whose best answer is not better than the current XML keeps its XML.
16.4 Adjudication by audit
An engine answer is accepted by measurement only: the runner assesses each answer with the same validity check and structural audit as the diagnosis. A page is written when its verdict improves; it is accepted as repaired when the verdict is ok.
16.5 Billing
Every Gemini call of the runner is recorded in the ocr-billing DuckDB (agents/document-processing/ocr_billing.duckdb) with collection, document, page and template label. Before this method was set up, the billing path of ocr_runner/client.py pointed to a non-existent directory and failed silently; copernicus-prim has no billing rows for its earlier Gemini fallback calls.
16.6 In the Partitur
Stage apply (op pdai:cure_apply). Without the input apply: true the op runs the dry run (--dry-run, or the specimen for a normalizer) and reports the plan. It refuses to start when the gate did not pass or another processing agent is running.