Mechaniczny weryfikator cytatu dla tekstów prawnych po polsku z GRADIENTEM weryfikacji (ISTNIENIE / TREŚĆ / FRAGMENT) - sprawdza string-matchem, czy każdy cytat z orzeczenia, ustawy, umowy lub pisma...
Cytat niezweryfikowany mechanicznie = cytat zmyślony, dopóki nie udowodnisz inaczej.
Model językowy potrafi wygenerować fragment wyroku, który brzmi idealnie - sygnatura, ton, słownictwo sądu - a którego w orzeczeniu nigdy nie było. Dla opinii prawnej cytującej nieistniejący fragment SN to katastrofa zawodowa i ryzyko odpowiedzialności (art. 6 Prawa o adwokaturze, należyta staranność).
Zasada: weryfikacja jest mechaniczna, nie semantyczna. Nie pytamy modelu „czy ten cytat pasuje". Robimy string-match znormalizowanego cytatu wobec znormalizowanego źródła. Match albo go nie ma. Odwrotny ciężar dowodu - to cytat musi się znaleźć w źródle.
v1 sprawdzał tylko jedną rzecz: czy dosłowny cytat istnieje w źródle. To zostawiało dwie ślepe plamy, które v2 zamyka:
Trzy poziomy (adaptacja Existence/Content/Paragraph z biblioteki Jeanne Sulzer, CC BY 4.0):
| Poziom | Co potwierdza | Stosuj do |
|---|---|---|
| ISTNIENIE | Kotwica - sygnatura/CELEX, data, organ - jest realna i zgadza się z deklaracją | „wyrok z 12.03.2019, II CSK…", „por. II CSK 123/19" |
| TREŚĆ | Źródło CO DO ISTOTY zawiera to, co twierdzi output | „SN przyjął, że…", parafraza holdingu |
| FRAGMENT | Cytowany akapit/zdanie istnieje dosłownie w źródle | każdy cytat w cudzysłowie, każdy pinpoint akapitu |
Reguła kalibracji (rdzeń v2): dopasuj siłę twierdzenia do osiągniętego poziomu. Jeśli
output twierdzi na poziomie FRAGMENT (dosłowny cytat), a weryfikacja dochodzi tylko do TREŚĆ
(źródło dotyczy tematu, ale cytatu dosłownie nie ma) → status KALIBRACJA: złagodź do
parafrazy ALBO oznacz pinpoint jako prowizoryczny. Pełna doktryna i macierz typów twierdzeń:
references/gradient-weryfikacji.md.
Grounding post-hoc łapie halucynację na końcu. Taniej jest nie wyprodukować jej wcale. Gdy generujesz tekst prawny (a nie tylko weryfikujesz cudzy), obowiązują trzy klasy z tagiem przy linii, której dotyczy - nie zbiorczo na końcu akapitu:
| Klasa | Kiedy | Jak znakować |
|---|---|---|
| Zweryfikowane | Źródło sprawdzone w tej sesji (SAOS/EUR-Lex/ISAP/dokument lokalny) | pełna kotwica przy tezie: (wyrok SN II CSK NN/RR, SAOS) |
| Do sprawdzenia | Prawdopodobne, ale z pamięci modelu: przepis, termin, wyliczenie | tag przy linii: [z pamięci - sprawdź w SAOS/ISAP], [wyliczenie modelu - sprawdź] |
| Nie używać | Sygnatura/numer/cytat, którego nie da się rozwiązać | fail-closed: nie produkuj wcale. Napisz „zgodnie z utrwalonym orzecznictwem SN [uzupełnij sygnaturę]" zamiast zmyślać numer |
Reguły domknięcia pętli generacja→weryfikacja:
items[] i musi wyjść 🟢/🟡. Zweryfikowane, które nie przechodzi
skryptu, to błąd klasyfikacji, nie pech.II CSK NN/RR,
sygn. akt [uzupełnij]) - realistyczne sygnatury z przykładów wyciekają do prawdziwych
outputów (audyt niemieckiego zbioru skilli prawnych: ~58% z 3228 sygnatur w outputach
było błędnych, w dużej części przeniesionych z materiałów przykładowych).Zawsze przed wysłaniem do klienta / sądu:
Co teraz JEST w zakresie (zmiana wobec v1): parafrazy i powołania samej sygnatury -
oznacz je claim_type i poddaj weryfikacji na właściwym poziomie. Bez cudzysłowu ≠ bez kontroli.
Zbierz źródła i rozwiąż kotwice - tekst dokumentu źródłowego dostępny lokalnie:
saos-orzecznictwo (zwraca też datę i organ → kotwica)eu-sparql-search (CELEX → kotwica)references/drabinka-zrodel-pl.mdBRAK ŹRÓDŁA, nie „prawdopodobnie ok".Sklasyfikuj każde twierdzenie - dla każdego powołania ustal claim_type (patrz macierz
w references/gradient-weryfikacji.md). To ustawia WYMAGANY poziom weryfikacji:
cytat_doslowny, teza_pinpoint → FRAGMENTstanowisko_sadu, parafraza → TREŚĆfakt_proceduralny, powolanie → ISTNIENIEZbuduj zadanie - jeden rekord na twierdzenie (format niżej): quote dla FRAGMENT,
claim_text dla TREŚĆ, anchor + anchor_resolved dla ISTNIENIA.
Weryfikacja mechaniczna - uruchom skrypt:
node scripts/ground-citations.mjs <plik-zadania.json>
Skrypt liczy osiągnięty poziom, porównuje z wymaganym, kalibruje. Exit 1 = twarda blokada.
Klasyfikuj wynik (skrypt robi to automatycznie):
ZWERYFIKOWANY - osiągnięty poziom ≥ wymagany. Dla FRAGMENT podaje zakres {start, end}
w oryginalnym source_text (indeksy JS, koniec wyłączny), offset = zakres.start,
segmenty dla cytatu z luką [...] i fragment_zrodla - dosłowny wycinek źródła do wgląduZMODYFIKOWANY - cytat znaleziony z drobną różnicą (interpunkcja, diakrytyki) - diff;
fragmenty_zrodla pokazują najbliższe miejsce w źródle dla każdego segmentuWYMAGA_OSADU - poziom TREŚĆ: terminy nośne obecne, substancję potwierdza człowiek / paraphrase-judgeKALIBRACJA - osiągnięto niżej niż twierdzono (cytat dosłowny nieobecny, temat pokryty) - złagodź tezęNIEZWERYFIKOWANY - brak trafienia / rozbieżna kotwica = potencjalna halucynacja, BLOKUJBRAK ŹRÓDŁA - nie dostarczono dokumentu / nierozwiązana sygnatura tam, gdzie wymaganaRaport - zwróć tabelę (niżej). 🔴 i ⛔ = twarda blokada (exit 1). 🟠 i 🟡 = decyzja człowieka przed publikacją (miękka). Nigdy nie przepuszczaj 🔴 milcząco.
Wszystkie sygnatury, strony i cytaty w przykładach tego pliku są fikcyjne - ilustrują format, nie realne sprawy. Nie przenoś ich do zadań ani deliverable.
{
"items": [
{
"id": "C1",
"source_id": "II CSK 123/19",
"claim_type": "cytat_doslowny",
"quote": "sąd związany jest granicami zaskarżenia",
"source_text": "<pełny znormalizowany tekst orzeczenia>"
},
{
"id": "C2",
"source_id": "I CSK 50/18",
"claim_type": "stanowisko_sadu",
"claim_text": "SN przyjął, że klauzula waloryzacyjna w umowie kredytu jest dopuszczalna",
"source_text": "<pełny tekst orzeczenia>"
},
{
"id": "C3",
"source_id": "II CSK 123/19",
"claim_type": "fakt_proceduralny",
"anchor": { "sygnatura": "II CSK 123/19", "data": "12.03.2019", "organ": "SN Izba Cywilna", "strony": "Kowalski przeciwko Bank Millennium S.A." },
"anchor_resolved": { "sygnatura": "II CSK 123/19", "data": "2019-03-12", "organ": "Sąd Najwyższy Izba Cywilna", "strony": "Nowak przeciwko Skarb Państwa" }
}
]
}
anchor = co twierdzi output. anchor_resolved = co zwrócił resolver (SAOS/EUR-Lex). Skrypt
porównuje mechanicznie (rozwija skróty: SN→sąd najwyższy, NSA, TK, TSUE…, normalizuje
daty DD.MM.YYYY↔YYYY-MM-DD). Brak claim_type → domyślnie cytat_doslowny (zachowanie v1).
Pole strony (opcjonalne, string „X przeciwko Y" albo tablica nazw) uruchamia guard STRONY:
gdy sygnatura się zgadza, ale nazwy stron zadeklarowane vs rozwiązane rozjeżdżają się (Jaccard tokenów
nośnych < 0.30 przy ≥2 tokenach) → 🔴 blokada („prawdziwy cytat, fałszywa teza" na poziomie kotwicy).
Częściowa zgodność (0.30–0.50) → 🟡 miękka uwaga. Stop-lista odsiewa formy prawne (sp. z o.o.,
S.A., przeciwko, v., i inni), więc Bank Millennium S.A. ≡ Bank Millennium Spółka Akcyjna.
anchor_resolved.strony dostarcza resolver (SAOS zwraca strony postępowania).
Aby uniknąć fałszywych 🔴 z powodu kosmetyki, przed porównaniem skrypt:
ß/ẞ → ss, odpowiednik casefold Pythona), zwija białe znaki„ " » ‹ ‚ ' ´ → ") i całą rodzinę kresek
(‐ ‑ ‒ – — ― − ⁃ - → -), rozwija wielokropek … → ...U+00AD,
zerowa szerokość U+200B/U+200C/U+200D, BOM, word joinerpraw-\nnik → prawnik), miękki dywiz na łamaniu też
(renderuje się wyłącznie tam, więc tam znaczy przeniesienie)[...] / ... w cytacie jako dozwoloną lukęNormalizacja NIE zmienia treści merytorycznej - jeśli słowo nośne jest inne, to nadal 🔴.
Tablica prawdy: contract/normalizacja.cases.json w skillu doc-intel-contract-pl
(w tym repo: dokumenty/skills/doc-intel-contract-pl/).
Czytają ją oba runtime'y - ten skrypt (Node) i evidence.py (Python) po stronie
doc-intel-contract-pl. Zgodność jest bramkowana w obu zestawach testów; zmiana samej
tablicy zapala oba naraz (sprawdzone mutacją).
Dlaczego to powstało: do 08-30 każda strona miała własną implementację tej samej reguły.
Tutejsza gubiła sześć z ośmiu mierzonych znaków, które polski PDF wstawia naprawdę -
U+2011 w sygnaturach akt, U+00AD w justowanych akapitach, U+2212, U+200B, U+2026
oraz wejście w NFD. Skutek był groźniejszy niż przeoczenie: na poziomie FRAGMENT skrypt
orzekał „cytatu nie ma w źródle" o cytacie, który tam był - czyli stawiał zarzut halucynacji,
którego przyczyną był błąd normalizacji. Ten sam fakt w dwóch domach rozjeżdża się po cichu.
## Raport grounding (gradient) - <nazwa deliverable>
| ID | Źródło | Typ | Wym.→Osiąg. | Status | Uwaga |
|----|---------------|------------------|--------------------|-------------------|-----------------------------------------|
| C1 | II CSK 123/19 | cytat_doslowny | FRAGMENT→FRAGMENT | 🟢 ZWERYFIKOWANY | znak 4821 |
| C2 | I CSK 50/18 | stanowisko_sadu | TREŚĆ→TREŚĆ | 🟡 WYMAGA_OSADU | terminy 86% - potwierdź substancję |
| C3 | III CZP 5/21 | cytat_doslowny | FRAGMENT→ISTNIENIE | 🔴 NIEZWERYFIKOWANY| brak w źródle - BLOKADA |
| C4 | I CSK 50/18 | cytat_doslowny | FRAGMENT→TREŚĆ | 🟠 KALIBRACJA | złagodź do parafrazy lub oznacz prowizor.|
| C5 | II CSK 999/19 | fakt_proceduralny| ISTNIENIE→BRAK | 🔴 NIEZWERYFIKOWANY| rozbieżna sygnatura - możliwe falszerstwo|
Wynik: 1/5 zweryfikowane. 2 blokady (C3, C5), 1 kalibracja (C4), 1 do osądu (C2).
NIE publikuj dopóki C3 i C5 nie zostaną poprawione lub usunięte. C4 wymaga złagodzenia tezy.
anchor_resolved.)let-it-be.Mechaniczny grounding to dowód należytej staranności i element dokumentacji z art. 12 (rejestrowanie
zdarzeń) oraz nadzoru człowieka z art. 14. Gradient dodaje wymiar kalibracji ryzyka: poziom
weryfikacji per twierdzenie to ślad, jak mocno każda teza jest osadzona. Raport grounding wkładaj
do legal-ai-audit-bundle obok deliverable.
legal-request-router-pl routuje TU, gdy zapytanie zawiera powołania. Wysoka stawka →
rozwiąż wszystkie kotwice (ISTNIENIE) + paraphrase-judge na 🟡.saos-orzecznictwo / eu-sparql-search = resolver kotwic (dają anchor_resolved) i źródło tekstu.deliverable-fidelity-pl pyta „czy nic nie wypadło z podsumowania"; ten skill pyta „czy to,
co zostało, jest prawdziwe". Komplementarne - oba przed wysłaniem high-stakes.WYMAGA_OSADU to dokładnie wejście dla warstwy paraphrase-judge (kaskada PATRON) -
mechanika robi tani pre-filtr, osąd substancji robi człowiek lub model._is_name_mismatch z john-walkoe/courtlistener_citations_mcp (MIT, 2026). Zaadaptowano ideę
(parse → porównaj nazwy stron zadeklarowane vs rozwiązane → flaguj rozbieżność); kod, stop-lista
form prawnych PL/EU i progi napisane od zera. Logika walidacji reporterów US z tamtego repo NIE jest
przenoszona - żyje po stronie serwera CourtListener (wywołanie sieciowe + token), co łamie kontrakt
zero-cloud; z repo bierzemy tylko lokalną, jurysdykcyjnie-neutralną heurystykę nazw stron.akunikkola/claude-for-legal-finland (MIT, references/viittaustyyli.md). Stamtąd też lekcja
dyscypliny placeholderów w przykładach (audyt siostrzanego projektu DE: ~58% złych sygnatur).COMMON_LEGAL_PHRASES z AnttiHero/lavern
(Apache 2.0, src/mcp/tools/grounding-verifier.ts) - trafiona fraza-wytrych liczy się 0.5 zamiast
1.0, żeby boilerplate nie zawyżał dowodu. Lista polskich fraz („z zastrzeżeniem", „w szczególności",
„chyba że umowa stanowi inaczej"...) i kod napisane od zera.citation-content-matcher z chrisryugj/korean-law-mcp
(MIT) - n-gram-Jaccard twierdzenia z najlepszym oknem źródła łapie „prawdziwe słowa, fałszywa
teza" (terminy obecne, ale rozproszone; żaden zwarty fragment nie odpowiada tezie). Tam bigramy
znakowe (koreański: 1 znak = sylaba); tu TRIGRAMY dla polskiego alfabetu łacińskiego (zmierzone
na fixture: bigram dawał szum 0.33 na rozproszeniu, trigram 0.15 przy parafrazie 0.45-0.78).
Wyłącznie sygnał (uwaga dla człowieka), nigdy samodzielna blokada. Kod i progi od zera.jeannesulzer/international-criminal-tribunals-skills (CC BY 4.0, Jeanne Sulzer / Impact
Litigation Lab, 2026). Zaadaptowano ideę gradientu i regułę kalibracji, nie kod ani treść -
ich biblioteka to dyscyplina promptowa pod web_fetch publicznych archiwów; tutaj to mechaniczny
silnik string-match pod lokalne źródła PL (RODO, zero-egress). Kod, prompty i reguły normalizacji
napisane od zera pod polskie realia (cudzysłowy „…", sygnatury SN/NSA/TSUE, CELEX).Te reguły obowiązują w każdym skillu tej wtyczki, także gdy sam skill milczy. Są skopiowane do każdego skilla, więc działają zarówno po instalacji całej wtyczki, jak i pojedynczego skilla. Pełniejszy standard: https://github.com/matematicsolutions/awesome-matematic-skills-pl/tree/main/references
Jeśli błąd przeszedłby bez zatrzymania przez warstwy 1-5, wina jest w skillu. Naprawiamy narzędzie, nie dopisujemy noty. Nota "to nie porada prawna" nie zatrzymuje błędu i nie przenosi odpowiedzialności.
(kodeks cywilny art. 415), (wyrok SN II CSK NN/RR, SAOS).[sprawdź w SAOS].Tag stoi przy linii, której dotyczy. Samo istnienie sygnatury nie wystarcza - treść trzeba sprawdzić.
Nic nie zostaje wysłane, złożone, podpisane ani opublikowane, zanim sprawdzi i zatwierdzi to uprawniony człowiek. Wynik skilla to projekt, nie gotowy dokument.
Fundament weryfikacyjny jest neutralny jurysdykcyjnie - to rdzeń metody, nie substancja prawa. Nie łączy się z żadnym źródłem zewnętrznym (brak konektorów MCP) i nie wysyła danych na zewnątrz. Substancję dostarczają osobne pluginy (orzecznictwo, dokumenty).