kb-wiki/_meta/conventions.md
oskar 9fc6703e2f docs(kb): scal decyzje (d)-(f) audytu 08-26 do _meta/conventions.md
Rekoncyliacja faza 5 etap 1 (kb-m5-faza5-wiki.md §4), krok 2 z 3. Trzy
decyzje z kb/audits/wiki-kompilat-recon-2026-08-26.md, już wypracowane i
zastosowane w bootstrapie sesyjnym (~/kb-wiki-etap1-sesja-2026-08-27/
_meta/conventions.md §5/§7/§8), scalone tu bez duplikowania tego, co w tym
repo już było (6 typów wliczając `meta` i sekcja "Brak danych w KB" — obie
już scalone wcześniej, commity 156925c i 3bd2441):

(d) Fallback envelope-only w przypisach — `[^envelope_id]` bez `#chunk_id`,
gdy dowód nie ma konkretnego chunka albo chunk przestał istnieć po
re-chunkingu (`document_chunk.id` niestabilny między przebiegami embeddingu).
Dopisane do sekcji "Przypisy inline i cytowanie faktów".

(e) Sekcja "Niepewne / sprzeczne" jako nazwana sekcja końca strony (już
używana de facto na żywych stronach: pzu.md, warta.md, mbank.md — teraz
sformalizowana pisemnie) + polityka aktualizacji "dopisz, nie nadpisuj" przy
nowym sprzecznym dowodzie, z wyjątkiem dla jawnych aktualizacji tego samego
faktu. Nowa sekcja, między "Sprzeczności między źródłami" a "Wersjonowanie
dokumentów źródłowych".

(f) Inwariant 7 — izolacja retrievalu kompilacji od source='wiki'
(mitygacja self-citation/citogenesis), CC/API-only jako wykonawca kompilacji.
Nowa sekcja przed "Integracja z retrievalem".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W7AnxL6pbgySpEgcCwAfww
2026-08-27 19:55:57 +02:00

252 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: Konwencje kb-wiki
type: meta
status: active
tags: []
sources: []
compiled_by: claude-sonnet-5
compiled_at: 2026-07-21
updated_at: 2026-08-27
---
# Konwencje kb-wiki
Ten dokument definiuje format stron tej wiki. Rozwinięcie decyzji architektonicznych
z `homelab-codex-ws`, `docs/kb/modules/05-faza3-plan.md` §8 (szkic operatora, NIE
zmieniamy stamtąd decyzji — tylko doprecyzowujemy wykonanie). To repo jest read-write
tylko dla kompilatora (CC/API); baza źródłowa (`kb-postgres@PIHA`) jest zawsze
read-only z tej strony.
## Struktura katalogów
Typy stron = katalogi; płasko wewnątrz każdego, graf robią linki `[[...]]`, nie
hierarchia plików.
| Katalog | Zawartość |
|---|---|
| `podmioty/` | Firmy i instytucje: ubezpieczyciele, banki, urzędy — encje trwałe, nie procesy |
| `osoby/` | Tożsamości/aliasy osób fizycznych |
| `sprawy/` | Procesy w czasie: sezony, remonty, procesy decyzyjne, porównania ofert |
| `umowy/` | Konkretne, zawarte kontrakty/polisy — jeden dokument prawny lub jego wersje |
| `tematy/` | Przekrojowe kategorie łączące wiele podmiotów/spraw (np. „ubezpieczenia auto”) |
| `_meta/` | Ten plik, raporty lintu |
Wybór katalogu dla nowej strony: jeśli encja to firma/instytucja → `podmioty/`;
jeśli to coś co się dzieje/działo w czasie (sezon, spór, zakup) → `sprawy/`; jeśli to
konkretna umowa prawna → `umowy/`; jeśli łączy wiele podmiotów pod wspólnym parasolem
tematycznym → `tematy/`.
## Frontmatter
```yaml
---
title: <nazwa strony, czytelna>
type: podmiot # podmiot | osoba | sprawa | umowa | temat | meta
status: active # active | archived
tags: [ubezpieczenie] # słownik wspólny z jobs/documents-ingest/tags-vocab.yaml
# (homelab-codex-ws) — nie wymyślamy nowego słownika dla wiki
sources:
- envelope_id: paperless:119
chunks: [4211, 4213] # document_chunk.id (klucz PK), NIE chunk_index
- envelope_id: "CABtrY-...@mail.gmail.com"
chunks: [] # koperta bez chunków (np. sam manifest)
compiled_by: claude-sonnet-5 # model/sesja, która skompilowała/ostatnio zmieniła stronę
compiled_at: 2026-07-20 # data pierwszej kompilacji
updated_at: 2026-07-20 # data ostatniej zmiany
---
```
`sources` agreguje **wszystkie** koperty, z których cokolwiek na stronie pochodzi —
niezależnie od tego, ile razy dana koperta jest cytowana w treści. To jest poziom
audytu „skąd strona czerpie w ogóle”; poziom „ten konkretny fakt” robią przypisy
inline (niżej).
## Przypisy inline i cytowanie faktów
Każdy fakt liczbowy lub identyfikujący (kwota, data, numer polisy/umowy, adres,
próg punktowy) dostaje przypis w miejscu użycia:
```markdown
składka 1 234 zł/rok [^paperless:119#4212]
```
Format: `[^<envelope_id>#<document_chunk.id>]`. Jeden fakt może mieć więcej niż
jeden przypis, jeśli potwierdzają go niezależnie różne chunki/koperty — wtedy oba
się wypisuje: `[^paperless:14#965][^paperless:22#2081]`.
**Fallback envelope-only (decyzja d, audyt 08-26):** `document_chunk.id` jest
kruchy — re-chunking (zmiana `chunk_size`/modelu embeddingu) usuwa i wstawia
wiersze na nowo, stary `id` przestaje istnieć. Gdy dowód nie ma konkretnego
chunka (sam nagłówek koperty) albo chunk już nie istnieje po re-chunkingu,
przypis degraduje się do samej koperty: `[^<envelope_id>]`, bez `#<chunk_id>`.
`envelope_id` jest stabilny (Message-ID/`sha256-…`, nigdy nie zmienia się po
insercie) — degradacja zostaje audytowalna, tylko mniej precyzyjna. Lint
raportuje liczbę zdegradowanych przypisów jako osobną metrykę (sygnał, że
re-chunking coś ruszył); re-chunking jest triggerem do ręcznego przeglądu
stron, nie do automatycznego remapowania (wymagałby ponownego embeddingu i
ryzykowałby przypisanie faktu do złego fragmentu po cichu).
Fakty opisowe/narracyjne (np. „PZU oferuje kilka wariantów ubezpieczenia") niosące
niską specyficzność mogą dzielić jeden przypis na koniec akapitu zamiast przypisu
po każdym zdaniu — przypis jest obowiązkowy per sekcja, nie per zdanie, ale musi
dawać się prześledzić do konkretnego chunka.
**Zakaz dopowiadania**: jeśli fakt nie występuje w żadnym pobranym chunku/streszczeniu,
strona pisze wprost „brak danych w KB" zamiast go zgadywać z wiedzy ogólnej modelu.
## Sprzeczności między źródłami
Gdy dwa dokumenty (typowo: dwie wersje tego samego OWU z różnymi datami
obowiązywania, albo dwie oferty konkurencyjne) podają różne wartości dla tego
samego faktu, strona **nie wybiera cicho jednej wersji**. Sprzeczność jest
flagowana jawnie w tekście, z obiema wartościami i obu przypisami, np.:
```markdown
Udział własny w AC: 300 zł wg OWU obowiązującego od 21.03.2026 [^paperless:14#871],
ale 500 zł wg wcześniejszej wersji OWU [^paperless:17#XXXX] — **rozbieżność między
wersjami, nie literówka**; przy sporze o odszkodowanie decyduje wersja obowiązująca
w dniu zdarzenia.
```
## Sekcja „Niepewne / sprzeczne" i polityka aktualizacji (decyzja e, audyt 08-26)
Sekcja wyżej pokazuje *jak* flagować sprzeczność w treści. To formalizuje ją
jako **nazwaną sekcję na końcu strony** (już używana na żywych stronach: `pzu.md`,
`warta.md`, `mbank.md`, ...), gdy sprzeczności nie da się rozstrzygnąć przy
kompilacji — nazwa i miejsce ujednolicone, żeby czytelnik/lint wiedział, gdzie
szukać:
```markdown
## Niepewne / sprzeczne
- Składka OC: [^paperless:24#N] podaje kwotę roczną bez liczby, [^<msg-id>#M]
(mail 2025-03) wspomina "1 450 zł" — nie jest jasne, czy to ta sama polisa
czy poprzedni rok. **Nie rozstrzygane automatycznie** — do potwierdzenia
przy następnej kompilacji tej strony.
```
Kolejność na końcu strony, gdy obie sekcje występują: „Niepewne / sprzeczne"
przed „Brak danych w KB" (niżej) — dowody, które się kłócą, nie to samo co
brak dowodów w ogóle. Strona bez tej sekcji nie jest „lepsza" — strona z
niewykrytą sprzecznością w treści głównej jest gorsza; to mechanizm
anty-propagacji (kompilator pisze „nie wiem" zamiast zgadywać i zamrażać
zgadywankę jako fakt).
**Polityka aktualizacji przy nowym, sprzecznym dowodzie: dopisz, nie
nadpisuj.** Domyślnie nowy sprzeczny dowód trafia do „Niepewne/sprzeczne",
fakt w treści głównej **nie** jest nadpisywany, dopóki sprzeczność nie
zostanie rozstrzygnięta. Wyjątek: gdy nowy dowód jest tego samego typu i
**wprost aktualizuje** poprzedni (np. „nowy cennik od 1.09" jawnie
zastępujący poprzedni, bez sprzeczności) — to nie jest sprzeczność, to
aktualizacja: idzie do treści głównej z nową `updated_at`. Rozróżnienie
„aktualizacja" vs „sprzeczność" robi **sesja kompilująca** (CC/API), nie
reguła automatyczna.
## Wersjonowanie dokumentów źródłowych
Ubezpieczenia i regulaminy w korpusie mają wielokrotne wersje z różnymi datami
„obowiązuje od". Strona encji **nie kompiluje jednej płaskiej prawdy** — jeśli
źródła mają rozbieżne daty obowiązywania, strona wymienia wersje osobno (np.
podsekcja per data) zamiast nadpisywać starszą nowszą bez adnotacji. To był
konkretny finding z pilota dedupa (`docs/kb/eval/retrieval-pilot-2026-07-16.md`,
`docs/kb/modules/05-faza3-plan.md` §3.2) — dokumenty bywają też **duplikatami
binarnymi** (`excluded_reason='duplicate'` w bazie), co jest czymś innym niż
kolejna wersja: duplikat pomijamy w kompilacji (baza już to wyklucza z retrievalu),
wersję z inną datą obowiązywania — nie.
## Sekcja „Brak danych w KB" (rozszerzenie, faza 5 etap 1 rekoncyliacja, 2026-08-27)
„Zakaz dopowiadania" wyżej mówi, że pojedynczy fakt bez pokrycia w źródłach pisze
się wprost jako „brak danych w KB" w miejscu użycia. To rozszerzenie formalizuje
to jako **osobną sekcję na końcu strony**, odróżnioną od „Niepewne / sprzeczne":
- **„Niepewne / sprzeczne"** — dowody **istnieją**, ale się nie zgadzają (dwa
chunki, dwie wartości, dwa przypisy).
- **„Brak danych w KB"** — zapytano retrievalem o coś istotnego dla tej encji, i
**żaden** pobrany chunk/streszczenie tego nie potwierdza. Nie jest to błąd
kompilacji — jest to jawne przyznanie granicy tego, co korpus dziś wie, zamiast
milczącego pominięcia pytania.
Format — krótka lista na końcu strony, po „Niepewne / sprzeczne" (jeśli obie
występują):
```markdown
## Brak danych w KB
- Nazwisko trenera drużyny (OCR nieczytelny w `paperless:175`).
- Wynik końcowy/klasyfikacja drużyny w całym turnieju (KB ma tylko wyniki cząstkowe).
```
Praktyczna wartość: kolejna kompilacja/aktualizacja tej strony (albo lint) wie od
razu, czego szukać przy następnym retrievalu, zamiast rekonstruować to z pamięci
sesji albo przeczytać stronę i domyślać się, co zostało pominięte a co nigdy nie
było sprawdzone. Pierwszy przykład użycia (przed formalizacją tej reguły):
`sprawy/fll-2025-26.md`, sekcja „Brak danych w KB", kompilacja 2026-07-21.
## Linkowanie między stronami
`[[nazwa-pliku-bez-rozszerzenia]]` — link do innej strony wiki po nazwie pliku
(bez katalogu, nazwy plików są unikalne w całym repo). Linkujemy tam, gdzie treść
się faktycznie styka (wspólny podmiot, wspólna sprawa, przywoływany dokument) —
nie tworzymy linków na wyrost do stron, które jeszcze nie istnieją, chyba że
świadomie oznaczamy brakujące pojęcie (patrz niżej), bo taki link psuje inwariant
lintu „brak stron-sierot i wiszących linków" dopóki strona docelowa nie powstanie.
## Brakujące pojęcia (przyszłe strony)
Jeśli podczas kompilacji natrafiamy na encję wartą osobnej strony, ale poza
zakresem bieżącej kompilacji (np. inny ubezpieczyciel wspomniany punktowo, inna
sprawa), **nie tworzymy linku `[[...]]`** do niej (byłby wiszący). Zamiast tego
kandydatka trafia do listy „brakujące pojęcia" w najbliższym raporcie lintu
(`_meta/lint-reports/`), żeby nie zgubić się w wątku.
## Zasady lintu
Okresowy lint (ręczny w tej fazie, `_meta/lint-reports/YYYY-MM-DD.md`) sprawdza:
1. **Strony-sieroty** — strona bez żadnego linku przychodzącego z innej strony
(poza `INDEX.md`, który z definicji linkuje do wszystkiego).
2. **Wiszące linki**`[[cel]]` bez odpowiadającego pliku `cel.md` w repo.
3. **Brakujące pojęcia** — encje wspomniane w treści (nie w linku) a nieopisane
osobną stroną; kandydaci na przyszłe strony, nie błąd.
4. **Spot-check** — dla losowej próbki przypisów `[^envelope_id#chunk_id]`
weryfikacja, że treść chunka w bazie faktycznie potwierdza przywołany fakt.
5. **Sprzeczności międzystronicowe** — ten sam fakt o tej samej encji opisany
różnie na dwóch stronach (nie mylić z rozbieżnością międzywersyjną w obrębie
jednej strony, która jest już jawnie flagowana w treści per wyżej).
## Kompilacja: CC/API-only i inwariant 7 — izolacja retrievalu (decyzja f, audyt 08-26)
Kompilację i lint robi wyłącznie CC/zewnętrzne API (patrz akapit wstępny) —
lokalny model za słaby na wielostronicowe operacje syntezy.
**Inwariant 7:** retrieval na potrzeby **kompilacji** strony wiki nigdy nie
czyta `source='wiki'` jako dowodu — zawsze wyklucza wiki
(`exclude_sources=('wiki',)` albo równoważny filtr SQL), czyta wyłącznie
warstwę dowodową (mail, paperless). Tylko retrieval na potrzeby `/search`
(warstwa użytkownika, po zbudowaniu syntezy odpowiedzi — poza zakresem tej
fazy) widzi wiki w kaskadzie. Mitygacja self-citation/citogenesis: bez tego
rozdziału kompilacja strony X mogłaby cytować inną stronę wiki (samą
skompilowaną z niepewnych przesłanek) jako „dowód", i błąd wzmacniałby się z
pozorem niezależnego potwierdzenia.
W praktyce (dopóki `source='wiki'` nie istnieje w bazie) retrieval
kompilacyjny i tak nie może dziś trafić na wiki — ale każde zapytanie
SQL/`cascade_retrieve`/`hybrid_retrieve` użyte przy kompilacji strony musi
jawnie nieść ten filtr od pierwszego dnia, nie dopisany post-factum, gdy wiki
już będzie źródłem w bazie.
Strony **mogą** linkować się nawzajem przez `[[nazwa-strony]]` (graf,
nawigacja) — to **nie jest** to samo co cytowanie jako dowód faktu. Przypisy
źródłowe (`[^...]`) zawsze wskazują `envelope_id` (warstwa dowodowa), nigdy
inną stronę wiki.
## Integracja z retrievalem (poza zakresem tej fazy)
Docelowo strony wiki wchodzą do `kb-postgres` jako koperty `source='wiki'`
(`id='wiki:<katalog>/<plik>'`), embedowane tym samym pipeline'em co chunki
dokumentów — kaskada retrievalu rozszerza się wtedy o trzeci poziom: wiki →
streszczenie → chunk. Nie jest to realizowane w tej fazie (proof-of-concept
ręcznej kompilacji 35 stron) — patrz `docs/kb/modules/05-faza3-plan.md` §8.2
w `homelab-codex-ws` po szczegóły.