doc-intel-contract-pl - kontrakt wyjscia Document Intelligence
Po co
Nasza drabinka PDF (pdftotext -> markitdown -> opendataloader -> Chandra -> vision) daje 5 roznych ksztaltow wyjscia. Ten skill ujednolica je do JEDNEGO kontraktu, ktory od razu odpowiada na trzy pytania:
- Ktory fragment ma zobaczyc czlowiek? - confidence-gating (Article III / AI Act art. 14).
- Co zredagowac? - typed blocks + flagi PII (signature/stamp/PESEL/NIP/IBAN).
- Gdzie w dokumencie jest ten cytat? - bbox + block_id -> most do [[citation-grounding-pl]].
Zamkniety jest MODEL Mistral OCR 4, nie idea. Odtwarzamy kontrakt na wlasnym, lokalnym, RODO-safe stacku. [[feedback_doktryna_skladanie_puzzli_nie_wynajdywanie_kola]]
Kontrakt (v1.1.0)
{
"doc_id": "<sha256 wejscia>",
"contract_version": "1.1.0",
"source": {"path": "...", "engine": "opendataloader|pdftotext|chandra|gaius|vlm-html", "engine_variant": "default|google_doc_ai|null", "pages": N},
"blocks": [
{"id": "b0001", "page": 1, "bbox": [x0,y0,x1,y1]|null,
"block_type": "title|paragraph|table|list|equation|signature|stamp|figure|header|footer|unknown",
"text": "...", "confidence": 0.0-1.0|null, "flags": ["partial","pii_suspected","pii:pesel","sensitive_block","signature_suspected",...]}
],
"gating": {"threshold": 0.85, "review_required": ["b0003"], "auto_approved": ["b0001"]},
"redaction_candidates": ["b0004"],
"meta": {"created_at": "ISO-8601"}
}
bboxznormalizowany 0-1 (przenosny miedzy DPI). Silnik bez bbox ->null+ flagapartial.confidence == null(partial) -> zawsze doreview_required(konserwatywnie; nie wiemy = czlowiek patrzy).
Uzycie (CLI)
cd ~/.claude/skills/doc-intel-contract-pl
python scripts/normalize.py --engine opendataloader wyjscie.json --pretty
python scripts/normalize.py --engine pdftotext dokument.txt --threshold 0.9
cat wyjscie.json | python scripts/normalize.py --engine opendataloader -
Exit: 0 = kontrakt schema-valid, 2 = blad wejscia / kontrakt niepoprawny (pasuje pod CI / pre-commit).
Bramka routingu (PRZED silnikiem) - routing_gate.py
Odpowiada na pytanie, ktore dotad rozstrzygalo oko: czy ten dokument w ogole da
sie przeczytac tekstowo i ktorym szczeblem. Werdykt trojstanowy z pelnym
mianownikiem, kod wyjscia 0/10/20 (ok/degraded/failed).
python scripts/routing_gate.py AKTA.pdf --pretty
python scripts/routing_gate.py *.pdf *.docx --quiet # tylko to, co nie jest ok
Lapie trzy rzeczy, ktorych zaden konwerter nie zglasza:
- PDF mieszany (czesc stron to skany) - kazde wyjscie tekstowe bedzie NIEPELNE,
a wyglada na kompletne. Status
degraded+ numery stron do OCR. - Pelny skan -
failed, eskalacja (Chandra wymaga GPU, ktorego tu nie ma). - Uszkodzona czesc OOXML - konwerter pominie ja bez slowa (zmierzone na anydoc:
uszkodzony
chart1.xml= exit 0, stderr pusty, znika cala tabela). Bramka nazywa czesc PRZED konwersja.
PDF wymaga pip install pdf-inspector (MIT). Jego brak = failed, nigdy ciche ok.
Miejsce w drabince PDF
Ten skill jest warstwa PO silniku OCR, PRZED groundingiem/redakcja:
routing_gate -> (pdftotext|anydoc|opendataloader|Chandra) -> doc-intel-contract-pl -> {gating do czlowieka | redaction_candidates | citation-grounding-pl}
Granica governance (Article III)
Skill PRZYGOTOWUJE: kolejke review_required, liste redaction_candidates,
wspolrzedne cytatu. NIE wykonuje redakcji ani akceptacji - to robi czlowiek.
Confidence-gating to kolejka, nie werdykt prawny.
Wyjatek pozorny - mask_for_model.py. Gdy fragment ma wyjsc do modelu (rung-5
vision, LLM-sedzia), kopia dostaje maske dlugosciowa: PESEL/NIP/REGON z suma kontrolna,
IBAN, e-mail, dowod, klucze API, Bearer -> * znak w znak. Oryginal, kontrakt i bloki
sa nietkniete, wiec to NIE jest redakcja dokumentu (Article III), tylko bezpiecznik na
kanale wyjscia (Article I). Dlugosc identyczna = offsety i bbox z grounding_bridge
pasuja do oryginalu bez przeliczania.
python scripts/mask_for_model.py < fragment.txt > fragment.dla_modelu.txt
# stderr: {"zamaskowane": 3, "kategorie": ["email", "iban", "pesel"]}
Status / roadmap (spec 001)
- US1 (MVP, DONE 2026-07-01): adaptery opendataloader+pdftotext, kontrakt, confidence-gating, walidacja schematu.
- US2 (DONE): flagi PESEL/NIP/REGON (checksum)/IBAN/email/dowod + redaction_candidates; signature/stamp=sensitive_block.
- US3 T030 (DONE): most
grounding_bridge.py-> zadanie citation-grounding-pl; lokalizuje cytat w blokach i dokladaanchor_resolved {page,bbox,block_id}(cytat -> region). - US3 T031 (DONE): adapter Chandra (layout DOM, bbox 0-1, block conf = MIN linii).
- US3 T032 (DONE):
signature.py- heurystyka podpisu/pieczatki (dol strony + krotki + low-conf); detektor vision wstrzykiwalny (opt-in). Potwierdzenie wizualne = krok operatora w runtime. - EXTRA T033 (DONE): adapter
gaius- OCR PATRONa (Gaius-Lex/ocr/poll), engine_variant default/google_doc_ai. - T034 (DONE 2026-08-05): adapter
chandradopasowany do REALNEGO formatu Chandry 2 (plaska lista{bbox,label,content-HTML}, 19 etykiet, BEZ confidence -> wszystko do review) + guard cichej niekompletnosci (niepuste wejscie, 0 blokow = ValueError, nie exit 0). - T035 (DONE 2026-08-05, kontrakt 1.1.0): silnik
vlm-html. Szablon promptureferences/prompt_vlm_ocr_pl.mdzmusza dowolny VLM do emisji constrained HTML z atrybutami data-label i data-bbox - wzorzec Chandry - a adapter parsuje to do kontraktu. VLM etykietujesignatureistampwprost, wiec podpis i pieczatka same laduja w redaction_candidates. Do tegodegeneracja.py: detektor zapetlenia generacji, w normalize daje flagedegenerate_taili ostrzezenie na stderr. - 83 testy zielone (contract+pii+grounding+chandra+chandra2+gaius+signature+vlm-html+degeneracja). Zero-dep Python stdlib.
Granica dowodu (stan 2026-08-05). Testy dowodza, ze parser czyta format
zgodnie ze specyfikacja - nie dowodza, ze zywy model ta specyfikacje stosuje.
Fixture vlm_html.sample.html napisalismy sami, wiec sprawdza adapter, nie
posluszenstwo VLM. Fixture chandra2.sample.json odwzorowuje format odczytany
z upstreamu chandra/output.py, ale bez przebiegu na realnej Chandrze.
Zanim silnik vlm-html pojdzie na akta, potrzebny jest przebieg bojowy:
prawdziwy skan, prawdziwy model, porownanie ze zrodlem.
[[feedback_zgodnosc_formatu_mierz_cudzym_czytnikiem]]
Render skanu do obrazow przed silnikiem VLM (flatten AcroForm + dynamiczne DPI,
pypdfium2 opcjonalnie): przepis w references/render_skanu_pl.md. UWAGA:
walidacja podpisu kwalifikowanego ([[waliduj-podpis-pdf-pl]]) PRZED flatten.
Most do groundingu:
python scripts/normalize.py --engine opendataloader wyjscie.json > kontrakt.json
python scripts/grounding_bridge.py kontrakt.json --quotes cytaty.txt --pretty
# -> {items:[{quote, source_text, anchor_resolved:{page,bbox,block_id}}]} do ground-citations.mjs
Governance: .matematic/konstytucja.md + .matematic/spec/001-output-contract-mvp/.
Czego NIE robi
- NIE jest silnikiem OCR (nie zastepuje Chandry).
- NIE wykonuje redakcji/akceptacji (przygotowuje, czlowiek decyduje).
- NIE wola cloud OCR (Mistral/Azure/Google) - zlamaloby Article I.
- NIE ocenia merytorycznie tresci prawnej.
Testy
python -m unittest discover -s tests -v
Zero zaleznosci npm/pip (czysty Python 3.11+ stdlib).