Read-only recon pod fazę 5. Ustala że architektura jest już w dużej mierze zatwierdzona (kb-m5-faza3.md §8, 2026-07-15/17) i że blokada "pełna wiki po fazie mailowej" jest dziś zdjęta (korpus sięga 2026-08-26 po naprawie incydentu 20-dni-ciszy). Dociąga trzy luki nieadresowane w tamtym szkicu: fallback chunk-id→envelope_id przy re-chunkingu, inwariant 7 (rozdział retrievalu kompilacji od retrievalu zapytań, mitygacja self-citation) i sekcję "niepewne/sprzeczne". Lista 17 encji zalążkowych z SELECT-ów na żywym korpusie (top nadawcy/domeny wśród zaembedowanych kopert, streszczenia paperless). Plan iteracji: Etap 1 = 3 strony proof (1 sesja), Etap 2 = lint + skala do 17. Decyzje operatora (a)-(h). Co: kb/audits/wiki-kompilat-recon-2026-08-26.md Co nie: implementacja — nic zdeployowane ani skommitowane poza tym dokumentem. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWrHr2z1tGhFrGUvPSx2vU
47 KiB
| okf | type | visibility | status | updated | as_of | links | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0.1 | audit | private | active | 2026-08-26 | 2026-08-26 |
|
Recon — wiki-kompilat (faza 5), 2026-08-26
Read-only recon. Zakres: przygotowanie fazy 5 subsystemu B (KB) — syntezy wiki nad warstwą dowodową RAG/pgvector. Zlecenie: zbadać 9 punktów (lokalizacja, bootstrap encji, tryb kompilatora, format linku dowodowego, anty-propagacja, integracja z kb-query, zależności/kolizje, plan iteracji, decyzje operatora) i wynieść wniosek per punkt. Nic nie zostało zaimplementowane, zdeployowane ani skommitowane poza tym dokumentem.
Dowody: repo (worktree task/wiki-kompilat-recon, cięty z mastera @ 4fa10f0),
pilot ~/narty-2027/saalbach-kb na SOLARII (lokalny odczyt), żywa baza kb na
PIHA przez ssh piha 'docker exec kb-postgres psql ...' (SELECT-y, zero zapisów),
systemctl status na PIHA dla stanu timerów.
Znalezisko nadrzędne, zanim cokolwiek innego: to nie jest recon od zera.
kb/phases/kb-m5-faza3.md §8 zawiera już zatwierdzony przez operatora szkic
architektoniczny wiki-kompilatu (decyzja 2026-07-15, opisana jako „NIE podlega
zmianie") plus rozwinięcie wykonawcze (§8.2, 2026-07-17) z konkretnymi
rozstrzygnięciami: osobne repo kb-wiki, struktura katalogów, format frontmattera
z blokiem sources, inline-przypisy [^envelope_id#chunk_id], trzypoziomowa
kaskada retrievalu wiki → summary → chunk, kompilacja przez CC/API, lint
okresowy, pętla zwrotna. Zadanie tego reconu — tak jak je czytam — to zweryfikować
te ustalenia w świetle tego, co się wydarzyło od 07-17 (pilot narty27, cała faza
mailowa, incydent 20 dni ciszy), dociągnąć luki, których tamten szkic nie
rozstrzygał (chunk-id vs re-chunking, self-citation, konkretna lista encji z
prawdziwych danych), i złożyć to w plan pierwszego etapu. Poniżej cytuję zamiast
odtwarzać, i mówię wprost, gdzie się zgadzam, a gdzie proponuję dociągnięcie.
1. Stan korpusu na dziś (2026-08-26) — czy blokada z faza3 jest zdjęta
kb/phases/kb-m5-faza3.md:628, cytat ze szkicu operatora: „Pełna wiki po fazie
mailowej (przyrostówka) — wcześniej kompilat byłby fotografią przeszłości."
kb/audits/mail-sync-2026-08-06.md §7 nazywa to jedyną znalezioną jawną
zależność „X czeka na przyrostówkę" w całym KB.
Zmierzone dziś na żywej bazie:
SELECT source, max(ts)::date AS latest, count(*) FROM envelope GROUP BY 1;
| source | latest | count |
|---|---|---|
| gmail | 2026-08-26 | 227 280 |
| fastmail | 2026-08-26 | 105 |
| paperless | 2026-07-13 | 191 |
SELECT count(*) FROM document_chunk WHERE embedding IS NULL AND excluded_reason IS NULL;
-- → 0
Korpus mailowy sięga dziś, nie 2026-06-19 jak w audycie 08-06 — incydent
20 dni ciszy naprawiony tego
samego dnia co to zlecenie domknął przyrostówkę: kursor dogonił IMAP, 548
zaległych kopert wchłonięte, zero błędów. kb-mail-sync.timer (co godzinę) i
kb-ingest.timer (co 2h, embed) oba active (waiting) na PIHA, żywe od
2026-08-06, bez przerwy odkąd monitoring realnie działa (od tego samego
incydentu). Embed backlog = 0 — nic nie czeka na wektor.
Wniosek: blokada z faza3 jest zdjęta dziś, nie wcześniej. To jest właściwy
moment na ten recon — zrobiony tydzień wcześniej trafiłby na korpus wciąż
urwany, a wiki-kompilat skompilowałby na trwałe fotografię z czerwca. Warto
odnotować kruchość tego stanu: przyrostówka działa dzięki jednemu chown i
jednemu /-/reload, oba ręczne, oba bez automatyzacji (R1/R2 z incydentu —
poprawna własność katalogów przy sudo-runach i reload reguł Prometheusa w
deployu — zostają otwarte). Faza 5 dziedziczy to ryzyko: gdyby przyrostówka
znów ucichła cicho, wiki-kompilat kompilowałby dalej z coraz starszej wody, bez
sygnału. Patrz §7 niżej (interakcja z monitoringiem KbMailSyncStale).
191 kopert paperless nie rosną od 2026-07-13 — to osobny fakt: paperless nie ma przyrostówki (dokumenty trafiają tam ręcznie), niezwiązany z blokadą mailową. Nie wstrzymuje fazy 5.
2. Punkt 1 — Lokalizacja wiki: kb/wiki/ w repo vs osobne repo
Co już zdecydowano
kb-m5-faza3.md §8.2: „Repozytorium (rozstrzygnięcie punktu 6 szkicu): osobne
repo kb-wiki — decyzja 7, uzasadnienie w §2. Klon roboczy na PIHA:
/opt/homelab/data/kb-wiki/." — i dalej: „D7 — rekomendacja: osobne
kb-wiki" w podsumowaniu (§12). To jest już podjęta decyzja, nie propozycja.
Weryfikacja na wzorcu pilota
narty27 (~/narty-2027/saalbach-kb) potwierdza ten wzorzec empirycznie:
kb/services/narty27.md — „Content is personal and lives outside the repo… It
is never committed — not to this repo, not to any other." Źródło leży w osobnym
lokalnym gicie na SOLARII, poza homelab-codex, infra (services/narty27)
zostaje w homelab-codex. Dokładnie ten sam split, jaki faza3 projektuje dla
kb-wiki: treść osobno, infrastruktura hostująca w repo.
Rekomendacja: potwierdzam D7 (osobne repo), z jednym doprecyzowaniem
Zgadzam się z decyzją bez zmian co do kierunku. Powody, które faza3 już podała i które podtrzymuję:
- Cykl życia inny niż kodu infry. Commity do
kb-wikibędą częste, drobne, generowane maszynowo (compile: <strona> ← <envelope_ids>) — zalałyby historięhomelab-codex-ws, gdzie commituje operator ręcznie i rzadko (CLAUDE.md: „Primary control node — only node where commits are made"). - Widoczność
visibilityper strona nie mapuje się na modelhomelab-codex.check_okf.pytego repo ma zamkniętą listęTYPESi regułęPOINTER_GLOBS/EXCLUDE_DIRSdopasowaną do tego, co tu jest — dodanie setek stron-encji (firmy, osoby, sprawy) dokb/zaszumiłoby indeks tego repo i pomieszałoby dwa różne reżimy publikacji (kb-site publikujevisibility: publiczkb/;kb-wikipotrzebuje własnego, bo część stron — dane osobowe, umowy, ludzie — nigdy nie powinna nawet teoretycznie wpaść w tę samą ścieżkę co dokumentacja infrastruktury). - Rozmiar. Korpus mailowy to 227k+ kopert; nawet skromna kompilacja
(setki stron) to inny rząd wielkości commitów niż
homelab-codex-wswidział kiedykolwiek. Osobne repo izoluje ten wzrost od repo, które operator przegląda i na którym pracują agenty infrastrukturalne.
Doprecyzowanie względem faza3: szkic nie rozstrzyga dostępu CC w
worktree. homelab-codex-ws ma wzorzec agent.sh new → worktree per task,
każdy dostaje pełne repo homelab-codex-ws sklonowane z gita. kb-wiki nie
jest tym repo — sesja kompilująca stronę potrzebuje dwóch klonów
jednocześnie: homelab-codex-ws (żeby czytać packages/kb-retrieval, DSN,
.env na PIHA) i kb-wiki (żeby pisać stronę). To nie jest problem dla
worktree pojedynczej sesji CC odpalonej ręcznie na PIHA/SOLARII z dwoma
katalogami obok siebie — jest problemem dla wzorca scripts/dev/agent.sh new, który zna tylko jedno repo. Rekomendacja: kompilacja wiki nie idzie
przez agent.sh-owe worktree homelab-codex-ws — to osobny tryb pracy
(sesja CC z dwoma katalogami roboczymi, jak dziś narty27 na SOLARII), do
zapisania w kb-wiki/_meta/conventions.md, nie w tym repo.
Publish.sh i public/private per strona
kb-site (services/kb-site/) publikuje wyłącznie kb/**/*.md z
visibility: public, fail-closed, przez token w URL (kb-e2a24af3.okit.pl).
kb-wiki leżący poza kb/ nie wejdzie do tego pipeline'u automatycznie —
i to dobrze, bo strony wiki (dane o ludziach, umowach, finansach) mają zupełnie
inny profil ryzyka publikacji niż dokumentacja infrastruktury. Jeśli/kiedy
pojawi się potrzeba publicznej (lub choćby LAN-owej) wystawki kb-wiki, to
osobny generator + osobny serwis (wzorzec narty27: nginx + named volume,
exposure: private domyślnie), nie rozszerzenie gen_pages.py. Na tym
etapie (proof-of-concept, 3–10 stron) nie ma potrzeby stawiać hostingu w ogóle
— git log/cat na PIHA wystarczy do przeglądu.
3. Punkt 2 — Bootstrap: analiza korpusu i lista encji zalążkowych
Zapytania i wyniki (żywa baza, 2026-08-26)
Wolumen per rok/źródło (envelope, pełne dane w §1 wyżej dla świeżości;
poniżej rozkład historyczny):
SELECT source, date_trunc('year', ts) AS yr, count(*) FROM envelope GROUP BY 1,2 ORDER BY 1,2;
Szczyt 2011–2012 (~23k/rok — dawny pracodawcy przez outbox.pl), potem
stabilne 9–13k/rok 2013–2025. 2 559 kopert ts=epoch 1970 (daty nieodzyskane,
opisane w kb-overview.md backlog).
Top nadawcy wśród kopert, które realnie mają zaembedowany, nie-wykluczony
chunk (czyli faktycznie trafiają w wyniki /search — to jest właściwe sito
pod encje, nie surowy wolumen, który zdominowany jest przez newslettery
wykluczone z indeksu):
SELECT h->'from'->>'name', h->'from'->>'address', count(DISTINCT e.id),
min(e.ts)::date, max(e.ts)::date
FROM envelope e
JOIN jsonb_array_elements(e.entities) h ON h->>'type' = 'headers'
WHERE EXISTS (SELECT 1 FROM document_chunk c
WHERE c.envelope_id = e.id AND c.embedding IS NOT NULL AND c.excluded_reason IS NULL)
GROUP BY 1,2 ORDER BY 3 DESC LIMIT 40;
| Nadawca | Adres | Koperty | Zakres |
|---|---|---|---|
| oskar kapala | oskar.kapala@gmail.com | 10 021 | 2005–2020 |
| Oskar Kapala | oskar.kapala@outbox.pl | 6 399 | (epoch)–2014 |
| Kasia Lorenc-Kapala | katalia@gmail.com | 3 385 | 2007–2026 |
| Oskar Kapala | oskar.kapala@gmail.com | 2 910 | 2010–2026 |
| System Synergia | robot2@robot.librus.pl | 2 818 | 2018–2026 |
| Allegro | powiadomienia@allegro.pl | 2 170 | 2008–2026 |
| Tomasz Anuszewski | tomasz.anuszewski@outbox.pl | 1 913 | 2011–2012 |
| Dziennik Bankier.pl (×2 adresy) | …bankier.pl | 1 736 + 1 676 | 2007–2014 |
| RSW_TECH_TEAM | rsw_tech_team@outbox.pl | 1 628 | 2011–2012 |
| Groupon | info@news.groupon.pl | 1 447 | 2011–2012 |
| Miron Mironiuk | m@cosmose.co | 1 126 | 2015–2016 |
| kontakt@mbank.pl | 1 099 | 2005–2026 | |
| Jan Boboli | jan.boboli@outbox.pl | 969 | 2011–2013 |
| Paweł Cesar Sanjuan Szklarz | paweld2@gmail.com, pawel@cosmose.co | 757+555+418+376 | 2005–2024 |
| InPost | info@paczkomaty.pl | 722 | 2017–2026 |
| Bogumil Jakubiak | B.Jakubiak@icm.edu.pl | 686 | 2004–2009 |
| sOKratis Liliana Banaszak | liliana.banaszak@sokratis.pl | 679 | 2009–2026 |
| Strava | update.strava.com / strava.com | 591+395 | 2017–2026 |
Domeny (§2, po odsianiu marketingu/newsletterów po heurystyce
noreply|notification|robot|mailer): outbox.pl (39,4k — domena prywatna
operatora, alias oskar.kapala@outbox.pl + koledzy z tej samej domeny =
prawdopodobnie dawny pracodawca/hosting), gmail.com, cosmose.co (2 982,
firma — Miron Mironiuk + Paweł Szklarz), icm.edu.pl/students.mimuw.edu.pl
(uczelnia/ICM UW), mbank.pl/bankier.pl (finanse), sokratis.pl.
Paperless — 191 kopert, w większości streszczone (document_summary,
162 claude-haiku-4-5 + 155 gemma3:12b, prawie 1:1 pokrycie). Próbka
streszczeń pokazuje wyraźne klastry tematyczne:
| Klaster | Liczba (próbka 40 najnowszych) | Przykład |
|---|---|---|
| FIRST LEGO League / Fundacja Future Minds | 8 | zgody na wizerunek, karty wyników, harmonogramy |
| Regulaminy OLX (pakiety, ochrona kupującego, ads) | 5 | umowa serwisowa |
| Revolut (krypto, regulaminy, cennik) | 4 | umowa finansowa |
| Spółdzielnia Mieszkaniowa „Przy Metrze" | 2 | RODO, dane kontaktowe |
| Ubezpieczenia (PZU OC, itp.) | 2 | polisa |
| Wynajem auta (Dollar, Madryt) | 2 | rezerwacja |
| Faktura (ZigBee, Oskar Kapała Rozwiązania IT — działalność gospodarcza) | 1 | dowód zakupu |
Kryterium kolejności
Trzy sygnały, w tej kolejności ważności:
- Obecność w indeksowanym (nie-wykluczonym) korpusie — encja musi mieć
realne pokrycie w
document_chunkz wektorem, inaczej strona kompiluje się z pustki. To jedyny twardy filtr (zastosowany w zapytaniu wyżej). - Wielowątkowość źródeł — encje, które łączą paperless (dokument formalny:
umowa, polisa, regulamin) i gmail (korespondencja o tej samej sprawie),
są lepszymi kandydatami na
sprawy/umowyniż encje widoczne tylko w jednym źródle — bo demonstrują dokładnie to, co ma udowodnić wiki-kompilat (Karpathy-wzorzec: strona syntezuje, nie kopiuje jednego dokumentu). - Rozstrzygalność, nie wolumen.
outbox.pl/Tomasz Anuszewski/Jan Boboli/RSW_TECH_TEAMmają duży wolumen (2011–2012), ale to zamknięty w czasie epizod (prawdopodobnie dawny pracodawca) — dobry kandydat napodmiot, zły na pierwszy PoC, bo wymaga ustalenia kontekstu (kim była ta firma), którego recon nie ma. Odłożone na drugą turę, nie na pierwszą.
Proponowana lista 10–20 encji zalążkowych
| # | Strona | Typ | Uzasadnienie (z danych) |
|---|---|---|---|
| 1 | fll-2025-26 |
sprawa | 8/40 streszczeń paperless; żywa sprawa (2026), krzyżuje szkołę + fundację + dziecko |
| 2 | future-minds (fundacja) |
podmiot | organizator FLL, NIP w danych, kontakt jawny w treści dokumentów |
| 3 | spoldzielnia-przy-metrze |
podmiot | nieruchomość, RODO + dane kontaktowe, aktywna (bieżąca korespondencja o pożarówce 2026) |
| 4 | revolut |
podmiot | 4 dokumenty regulaminowe w próbce, konto aktywne (kontekst kryptowalut) |
| 5 | mbank |
podmiot | 1 099 kopert 2005–2026, ciągłość 20 lat, kontakt@mbank.pl + dziennik bankier.pl (powiązana marka) |
| 6 | pzu |
podmiot | kandydat wymieniony wprost w szkicu operatora (§8.1 przykład), polisa OC w paperless |
| 7 | cosmose (firma) |
podmiot | 2 982 kopert, dwóch nazwanych korespondentów (Mironiuk, Szklarz) — test cross-osoba w jednym podmiocie |
| 8 | miron-mironiuk |
osoba | 1 126 kopert, jeden zidentyfikowany adres, powiązanie z cosmose |
| 9 | pawel-cesar-sanjuan-szklarz |
osoba | 4 warianty adresu/nazwy (757+555+418+376 kopert) — dobry test entity resolution na aliasach tej samej osoby |
| 10 | librus-synergia |
temat | 2 818 kopert 2018–2026, szkoła dzieci, ciągły strumień — test strony-tematu o dużym, jednorodnym źródle |
| 11 | inpost-paczkomaty |
temat | 722+681 (dwa nadawcy tej samej usługi) — test scalania dwóch adresów jednej usługi w jedną stronę |
| 12 | strava |
temat | 591+395, dwa adresy tej samej usługi, 2017–2026 ciągłe |
| 13 | bogumil-jakubiak |
osoba | ICM UW, 2004–2009 — zamknięty epizod, test strony status: archived |
| 14 | wynajem-samochodow (Dollar/Madryt) |
temat | rezerwacja 2026, dwa powiązane dokumenty paperless (potwierdzenie różnymi kanałami tej samej rezerwacji) — test dedupu treści |
| 15 | dzialalnosc-gospodarcza (Oskar Kapała Rozwiązania IT) |
podmiot | faktura w paperless, własna działalność — inny rejestr niż korespondencja prywatna |
| 16 | sokratis |
podmiot | 679 kopert 2009–2026, ciągłość 17 lat, nazwany kontakt (Liliana Banaszak) |
| 17 | allegro |
temat | 2 170 kopert 2008–2026 — najdłuższa ciągła relacja handlowa w korpusie |
| 18–20 | (druga tura, po pierwszej weryfikacji) | — | outbox.pl/dawny pracodawca po ustaleniu kontekstu; PZU↔mbank cross-link jako pierwszy test grafu sprawy łączących dwa podmioty |
17 pozycji zamiast równych 20 — reszta świadomie zostawiona na drugą turę
zamiast dopełniana sztucznie (Bogumil Jakubiak/ICM to jedyny archiwalny/
zamknięty przypadek na liście — reszta to żywe encje; warto mieć chociaż jeden
przykład status: archived w PoC, żeby lint (inwariant 3) miał co sprawdzać
na obu stanach od pierwszego dnia).
4. Punkt 3 — Tryb kompilatora: batch / pipeline / hybryda
Co już zdecydowano
Faza3 §8.2, inwariant 2: „Kompilację i lint robi CC/zewnętrzne API… Sesja CC/API dostaje wyniki retrievalu dla encji… pisze/aktualizuje stronę, commituje do kb-wiki." To opisuje batch przez sesje CC — potwierdzone też przez operatora w zleceniu tego reconu („Utrzymanie: CC/API — lokalny model za słaby — rozstrzygnięte"). Nie podważam tego kierunku; on jest już przesądzony. Pytanie, które faza3 zostawia otwarte, to rytm: czy kompilacja jest wyłącznie ręcznie wyzwalanym batchem, czy dostaje automatyczny trigger, i jak zamyka się pętla zwrotna (inwariant 4: „dobre odpowiedzi z zapytań wracają do wiki jako nowe strony").
Trzy tryby, ocenione pod kątem tego, co ta faza faktycznie robi
(A) Czysty batch (sesja CC, ręcznie wyzwalana). Operator albo agent
odpala sesję z listą encji, sesja robi N zapytań do hybrid_retrieve/
cascade_retrieve, pisze/aktualizuje strony, commituje. Koszt: przewidywalny
i widoczny w moment wywołania — tyle, ile ta jedna sesja zużyje tokenów API.
Częstotliwość: kiedy operator zdecyduje (np. raz na kilka sesji roboczych KB).
(B) Job z pipeline'em eskalacji (per-query, automatyczny). Każde
zapytanie do kb-query /search, które trafia próg (dist, heurystyki),
eskaluje do API i automatycznie zapisuje/aktualizuje stronę wiki z
odpowiedzi. To bezpośrednio realizuje pętlę zwrotną (inwariant 4) bez udziału
człowieka w każdym pojedynczym zapisie.
(C) Hybryda: bootstrap batch, utrzymanie pipeline. Pierwsza fala stron
(PoC, potem szersza kompilacja korpusu) idzie trybem (A) — bo trzeba pokryć
setki/tysiące encji z pustego stanu, co jest z natury wsadowe i wymaga
przeglądu jakości. Po ustabilizowaniu wiki, dopisywanie/aktualizacja idzie
trybem (B), zdarzeniowo, przy okazji zapytań /search, które i tak przechodzą
przez kb-query.
Rekomendacja: (C), z (B) odłożonym poza zakres tej fazy
Uzasadnienie:
- Skala nie pozwala na (B) od startu.
kb-querydziś nie robi syntezy odpowiedzi — to jawnie zapisane wkb/services/kb-query.md(„This is a search API, not chat: no answer synthesis over results, that's phase 5"). Automatyczny zapis strony z „dobrej odpowiedzi" wymaga najpierw tej syntezy (LLM nad wynikami retrievalu) — a to jest osobny, jeszcze niezbudowany komponent, w planiekb-m5-faza-mailowa.md§11 zapisany jako „Synteza odpowiedzi + polityka eskalacji | faza 5 | po fazie 3/4". Innymi słowy: (B) zakłada istnienie warstwy, którą dopiero ta faza ma zbudować. Zaczynanie od (B) to budowanie pipeline'u nad nieistniejącym sygnałem. - Bootstrap wymaga przeglądu, nie automatyzacji. 17 stron z §3 to
pierwsza próba entity resolution na korpusie, który nigdy wcześniej nie był
tak czytany — pierwsze przebiegi będą mylić się (aliasy tej samej osoby
pod różnymi adresami, jak
paweld2@gmail.comvspawel@cosmose.co, patrz #9). Batch z operatorem czytającym diff przed commitem jest tu właściwym trybem; automatyczny zapis bez przeglądu ryzykuje właśnie to, co inwariant 3 (lint) ma łapać po fakcie — lepiej łapać przed pierwszym zapisem. - Koszt. Batch: koszt jednej sesji, znany z góry (faza3 §11 szacuje
kompilację 3–5 stron proof jako „pomijalna" wobec ~1.5–4 USD pilota
streszczeń). Pipeline per-query: koszt proporcjonalny do ruchu na
kb-query, dziś zerowego (serwis bez UI logowania, brak ruchu produkcyjnego opisanego w żadnym audycie) — budowanie licznika kosztów pod ruch, którego jeszcze nie ma, jest przedwczesne.
Wniosek: w tej fazie — wyłącznie (A)/(C)-batch. Pipeline eskalacji (B) to
konsekwencja syntezy odpowiedzi, która sama jest poza zakresem tego reconu
(kb-m5-faza-mailowa.md §11) — wpisuję go do §8 (plan iteracji) jako osobny,
późniejszy etap, nie część pierwszego kroku.
Trigger i częstotliwość dla batcha
Rekomendacja: ręczny, przywiązany do sesji roboczych KB, nie do ticku
ingestu. Uzasadnienie: kb-ingest/kb-mail-sync tykają bez nadzoru
(systemd timer) właśnie dlatego, że są deterministyczne i tanie (lokalny
embed). Kompilacja wiki zużywa API i wymaga jakościowego osądu przy każdym
zapisie na tym etapie — sprzeczne z „bez nadzoru". Automatyczny trigger „po
ticku ingestu" dodałby niekontrolowany koszt API do procesu, który dziś nie ma
żadnego budżetu ani limitu (packages/kb-retrieval/kb-query nie mają
pojęcia o kosztach API — nigdzie w repo nie ma licznika wydatków Anthropica).
5. Punkt 4 — Format linku dowodowego i odporność na re-chunking
Co już zdecydowano
Faza3 §8.2 daje dokładną składnię, cytuję w całości bo to bezpośrednia odpowiedź na pytanie zlecenia:
---
sources:
- envelope_id: paperless:119
chunks: [4211, 4213] # document_chunk.id
- envelope_id: "CABtrY-...@mail.gmail.com"
chunks: [] # koperta bez chunków (np. sam manifest/headers)
---
Treść… składka 1 234 zł/rok [^paperless:119#4212].
Dwa poziomy: sources: we frontmatterze (agregat, dla lintu — sprawdza czy
strona ma dowody) i inline [^envelope_id#chunk_id] przy każdym fakcie
liczbowym (dla spot-checku — sprawdza czy zdanie ma dowód). To jest już
odpowiedź na „envelope_id vs chunk-id": oba, na dwóch poziomach
granularności, nie albo-albo.
Luka, którą faza3 zostawia: document_chunk.id (bigint PK) nie jest stabilny
To jest realny problem, którego szkic nie adresuje wprost. document_chunk.id
to bigint GENERATED … nextval(...) — PK generowany przy insercie. Re-chunking
(zmiana chunk_size/chunk_overlap, zmiana modelu embeddingu, poprawka
chunkera) w obecnym pipeline'u (jobs/mail-body-ingest, kb/phases/kb-m5-faza3.md
§1.6, Decyzja 1) usuwa i wstawia na nowo wiersze document_chunk dla
przetwarzanej koperty — nowe id. Strona wiki napisana dziś z przypisem
[^paperless:119#4212] po re-chunkowaniu paperless wskazuje na id, który już
nie istnieje.
Sprawdziłem: nie ma w repo żadnego mechanizmu "kotwiczenia" chunka niezależnego
od PK (np. hash treści, offset w dokumencie źródłowym). chunk_index (kolumna
w document_chunk) jest stabilniejszy semantycznie (n-ty fragment tej koperty)
ale też nie jest gwarantowany stabilny — zmiana chunk_size przesuwa
granice i renumeruje wszystkie chunki tej koperty.
Ocena: to nie jest luka krytyczna, bo lint już ją łapie — ale warto dociągnąć degradację
Inwariant 3 (lint) faza3 §8.2 już projektuje mechanizm wykrywania: „spot-check
N losowych przypisów [^...] vs treść chunka w bazie". Martwy chunk_id po
re-chunkingu to dokładnie to, co ten spot-check złapie — SELECT text FROM document_chunk WHERE id = 4212 zwróci zero wierszy, lint zgłasza to jako
znalezisko w _meta/lint-reports/. Mechanizm wykrywający już istnieje w
projekcie, więc rekomendacja to nie „zbuduj nowy system kotwiczenia" tylko
doprecyzowanie zachowania przy trafieniu martwego linku:
Rekomendacja — dwupoziomowy fallback, nie twardy błąd:
- Link prymarny to
[^envelope_id#chunk_id]— precyzyjny, ale kruchy. - Gdy
chunk_idnie istnieje (po re-chunkingu), fallback doenvelope_id— dowód wskazuje na kopertę jako całość ("ten fakt pochodzi z tej wiadomości", zamiast "z tego dokładnie fragmentu"). Zdegradowane, ale wciąż audytowalne, boenvelope_idjest stabilny (envelope.idto Message-ID albosha256-…, nigdy nie zmienia się po insercie —kb-mail-pillar.md§3, kontrakt zamrożony). - Lint raportuje liczbę zdegradowanych przypisów jako osobną metrykę w
_meta/lint-reports/(nie tylko listę zerwanych linków) — to jest wczesny sygnał "re-chunking coś ruszył, strony trzeba przejrzeć", zanim ktokolwiek zauważy to ręcznie. - Re-chunking = trigger do przeglądu, nie do automatycznej naprawy.
Automatyczne przepisanie
chunk_idna nowy najbliższy semantycznie chunk wymagałoby ponownego embeddingu i porównania — kosztowne i ryzykowne (może przypisać fakt do złego fragmentu po cichu). Degradacja doenvelope_id+ ręczny przegląd przy najbliższej kompilacji tej strony jest tańsza i bezpieczniejsza.
Konsekwencja praktyczna: re-chunking całego korpusu mailowego (227k kopert)
jest zdarzeniem rzadkim i świadomym (widziane już raz — Decyzja 1 fazy3,
UNIQUE+model), nie czymś co dzieje się przy okazji. Skala degradacji przy
takim zdarzeniu jest więc skokowa i rzadka, nie ciągła — fallback +
metryka w locie wystarczą, nie trzeba temu poświęcać osobnej infrastruktury.
6. Punkt 5 — Anty-propagacja: datowanie, sprzeczności, aktualizacja
Co już zdecydowano
Frontmatter niesie compiled_at/updated_at (datowanie na poziomie strony).
Inwariant 3: lint okresowy łapie „sprzeczności między stronami (fakty o tej
samej encji)". Inwariant 4: pętla zwrotna dopisuje nowe strony/aktualizacje z
dobrych odpowiedzi zapytań.
Luki, które faza3 nie precyzuje i które zlecenie wprost pyta
(1) Sekcja „niepewne/sprzeczne" na poziomie strony. Dziś nic w projektowanym frontmatterze/strukturze nie ma miejsca na "wiem, że dwa źródła mówią co innego, i to jest w rękopisie widoczne". Lint wykrywa sprzeczność między stronami — ale co z sprzecznością wewnątrz jednej kompilacji (np. paperless:119 podaje jedną kwotę składki, wcześniejszy mail podaje inną — podwyżka, błąd, czy różne polisy)?
Rekomendacja: sekcja ## Niepewne / sprzeczne jako konwencja treści
strony (nie pole frontmattera — to jest proza, nie metadane), umieszczana
zawsze na końcu strony, gdy występuje. Format:
## 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.
Lint (spot-check) traktuje tę sekcję jako oczekiwaną, nie jako defekt — strona bez tej sekcji nie jest "lepsza", strona z niewykrytą sprzecznością w treści głównej (fakt podany jako pewny, gdy dowody się rozjeżdżają) jest gorsza. To jest różnica między ukrywaniem niepewności (zły kompilat) a jej nazwaniem (dobry kompilat) — i to jest właśnie mechanizm, który ma zapobiegać propagacji błędu: LLM kompilujący wprost pisze "nie wiem", zamiast zgadywać i zamrażać zgadywankę jako fakt.
(2) Polityka aktualizacji przy nowym, sprzecznym dowodzie. Scenariusz ze zlecenia: nowy mail przeczy istniejącej stronie. Dwie opcje:
- Nadpisać stronę nowym stanem (traktować najnowszy dowód jako prawdziwy) — ryzyko: jeśli nowy mail jest błędny/nieaktualny/o innej sprawie, kasuje się poprawną wcześniejszą treść bez śladu.
- Dopisać do „Niepewne/sprzeczne" i nie nadpisywać faktu w treści głównej, dopóki sprzeczność nie zostanie rozstrzygnięta (przez kolejną kompilację z jeszcze jednym dowodem, albo ręcznie przez operatora).
Rekomendacja: druga opcja, z jednym wyjątkiem. Domyślnie dopisz, nie
nadpisuj — bo strona ma być audytowalnym destylatem, nie najświeższą
migawką, a "nowszy mail" nie zawsze znaczy "poprawniejszy" (może być o innej
polisie, literówka nadawcy, spam). 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, nie sprzeczny z nim) — to nie jest sprzeczność, to
aktualizacja, i idzie do treści głównej z nową datą updated_at, a stary fakt
przechodzi do sekcji „Historia" (jeśli strona jej potrzebuje) albo po prostu
znika, zastąpiony — to jest zwykła kompilacja, nie przypadek antypropagacji.
Rozróżnienie "to jest aktualizacja" vs "to jest sprzeczność" robi sesja
kompilująca (CC/API), nie automat — zgodnie z inwariantem 2 (kompilacja to
zadanie dla modelu, nie dla reguły).
(3) Datowanie twierdzeń w treści, nie tylko w frontmatterze. Rekomendacja
dodatkowa: każdy fakt z konkretną datą ważności (cena, status sprawy, "aktualnie
w toku") niesie datę przy fakcie, nie tylko w updated_at strony — bo
strona może zbierać fakty z różnych momentów (mail z 2019 o starej umowie +
mail z 2026 o nowej), a jedna data na całą stronę zaciera to rozróżnienie.
Przykład: „Składka 1 234 zł/rok (stan na 07.2026) [^paperless:119#4212]."
To jest rozszerzenie konwencji przypisu z §5, nie nowy mechanizm.
7. Punkt 6 — Integracja z kb-query: retrieval, ryzyko sprzężenia
Co już zdecydowano
Inwariant 5 (faza3 §8.1): „Wiki wchodzi do retrievalu jako dodatkowe źródło…
kaskada: wiki → summary → chunk." §8.2 rozwija: strona wiki = koperta
source='wiki', id='wiki:<ścieżka>', chunkowana i embedowana tym samym
jobem, bez nowego schematu bazy — reużywa istniejący kontrakt koperty.
Co to znaczy konkretnie w kodzie dzisiejszego packages/kb-retrieval
Sprawdziłem retrieval.py: dziś są trzy tory (flat/cascade/hybrid), z
cascade_retrieve jako dwupoziomowym (document_summary → document_chunk)
i hybrid_retrieve jako cascade + równoległy skan summaryless_sources
(gmail, fastmail) scalany po dist. Nie ma dziś trzeciego poziomu.
Realizacja inwariantu 5 wymaga:
- Nowej tabeli/kolekcji
document_summary-podobnej dla wiki, albo traktowania stron wiki jak paperless — envelope z summary (skoro strony są krótkie, 1–3 chunki,document_summarydla całej strony ma sens semantyczny inaczej niż dla 187k-wierszowego newslettera). - Nowej funkcji
wiki_retrievewkb_retrieval/retrieval.py, wołanej przedcascade_retrieve, z wynikiem scalanym analogicznie dohybrid_retrieve(ten sam embedder, ten sam cosine space — merge to sort, nie renormalizacja, dokładnie jak dziś). - Zmiany w
search.py/app/main.pykb-query, żeby nowy tryb (mode) albo rozszerzeniehybridobejmował wiki — i wapp/links.py(build_result) żeby wynik ze źródławikimiał sensownylink(raw_refdo pliku wkb-wiki, nie URL — bokb-wikinie jest hostowane publicznie, patrz §2).
To jest realna zmiana kodu w serwisie produkcyjnym (kb-query), nie tylko
w nowym repo kb-wiki — warto to mieć jawnie w planie iteracji (§8), bo
inwariant 5 bez tego pozostaje deklaracją, nie działaniem.
Ryzyko sprzężenia (self-citation / citogenesis) — luka w szkicu faza3
Zlecenie pyta wprost o to ryzyko i faza3 go nie adresuje. Mechanizm
ryzyka: kompilacja strony X czyta wyniki retrievalu (inwariant 2) → jeśli
retrieval w tym momencie już przeszukuje source='wiki' (inwariant 5, w pełni
wdrożony) → strona X może dostać jako "dowód" inną stronę wiki, która sama
została skompilowana z niepewnych/błędnych przesłanek → błąd się utrwala i
wzmacnia zamiast zanikać, bo kolejna kompilacja cytuje już nie surowy
mail, tylko wcześniejszą (błędną) syntezę, z pozorem niezależnego
potwierdzenia. To jest dokładnie mechanizm Wikipedia-citogenesis, przeniesiony
na kompilator jednoosobowy.
Rekomendacja — rozdzielić dwie ścieżki retrievalu, które dziś inwariant 5 zlewa w jedną:
- Retrieval na potrzeby
/search(użytkownik, faza 5 synteza odpowiedzi) — tu wiki powinna wchodzić do kaskady (inwariant 5 ma rację: skompilowana wiedza jest cenniejsza niż surowy chunk dla kogoś, kto pyta "co wiem o PZU"). - Retrieval na potrzeby kompilacji nowej/aktualizowanej strony (sesja
CC/API pisząca
kb-wiki) — tu retrieval musi wykluczaćsource='wiki'(parametrexclude_sources=('wiki',)wcascade_retrieve/hybrid_retrieve, jedna linia zmiany analogiczna do dzisiejszegosummaryless_sources). Kompilacja zawsze czyta wyłącznie warstwę dowodową (mail, paperless — evidence layer z ustaleń wyjściowych operatora), nigdy inne strony wiki jako źródło faktów. Strony mogą linkować się nawzajem przez[[...]](graf, nawigacja) — ale to nie jest to samo co "cytowanie jako dowód faktu"; link[[pzu]]w treści stronypolisa-oc-autoto odsyłacz do powiązanej strony, nie przypis źródłowy — przypisy źródłowe ([^...]) zawsze wskazująenvelope_id, nigdywiki:....
Ten podział jest tani do wymuszenia (jeden parametr) i eliminuje ryzyko przy źródle, zamiast polegać wyłącznie na lincie żeby je złapać po fakcie. Rekomendacja: dopisać to jako inwariant 7 przy zatwierdzaniu planu, nie jako implementacyjny szczegół — to jest decyzja architektoniczna tej samej wagi co inwarianty 1–6 z faza3 §8.1.
8. Punkt 7 — Zależności i kolizje
Multiagent recon / dyspozytor
Sprawdzone bezpośrednio w kb/subsystems/recon-multiagent.md i potwierdzone
przez kb/audits/mail-sync-2026-08-06.md §5 (który zrobił dokładnie to samo
ćwiczenie dla przyrostówki): dyspozytor subsystemu B nie istnieje jeszcze w
kodzie — jest zdefiniowany jako osobny projekt w
kb/decisions/architektura-2026-07-28.md („B — do-the-work: dyspozytor zadań
(agent)… Osobny wysiłek, osobny projekt"), planowany na PIHA. kb-query
występuje w reconie multiagentowym wyłącznie jako wiersz inwentarza, poza
zakresem control-plane/Telegram.
Wniosek: zero zależności blokujących w żadną stronę, z tym samym
zastrzeżeniem, jakie mail-sync-recon już zanotował dla siebie: nowy automat
(tu: ewentualny periodyczny lint albo — gdyby kiedyś powstał — pipeline
eskalacji z §4) dokłada się do „shadow set" bytów poza GitOps-ową detekcją
dryfu (kb-ingest, stability-agent, teraz kb-mail-sync, potencjalnie
kb-wiki-lint). Nie blokuje nic dzisiaj; warto, żeby trafiło świadomie do
otwartego pytania nr 5 tamtego reconu, a nie przez przeoczenie — dokładnie tak
samo jak zanotował to mail-sync-recon dla siebie.
Telegram/approval flow (CLAUDE.md „Action approval flow") dotyczy
wyłącznie akcji container_restart/redeploy/disk_cleanup/alert_only z
control-plane. Kompilacja wiki nie generuje żadnej z tych akcji — nie ma i nie
powinno być punktu styku. Jedyny sensowny alert, gdyby faza 5 dostała
automatyzację (§4 tryb B, poza zakresem tej fazy), byłby analogiczny do
KbMailSyncStale: "kompilator/lint nie chodzi", nie coś wymagające approvalu
operatora.
kb-site publish
Rozstrzygnięte w §2: kb-wiki leży poza kb/**/*.md, więc gen_pages.py/
publish.sh nie widzą go w ogóle — zero kolizji, bo zero styku. Gdyby w
przyszłości ktoś położył treść kb-wiki wewnątrz kb/ (odwrotnie od
rekomendacji §2), wtedy powstałaby realna kolizja: gen_pages.py --check
skanuje wygenerowany output pod kątem wycieków (IP, tokeny, ścieżki hosta) —
ale nie skanuje pod kątem danych osobowych (PESEL, adresy, numery umów),
bo nie taki był jego cel. To jest dodatkowy, mocny argument za §2 (osobne
repo): trzymanie wiki-encji poza kb/ eliminuje całą tę klasę ryzyka
strukturalnie, zamiast polegać na tym, żeby nikt nigdy nie oznaczył strony o
PZU jako visibility: public przez pomyłkę.
Follow-upy fazy mailowej — czy brudne chunki psują kompilację
Z kb/incidents/2026-08-26-mail-sync-20-dni-ciszy.md §6 (Nie w zakresie tej naprawy, bez zmian od 08-06): charset/mojibake w co najmniej 12 kopertach
oraz NUL w nagłówkach jsonb pozostają otwarte. Oceniam wpływ na
wiki-kompilat:
- Skala jest znikoma — 12 kopert na 227 576 (≈0,005%). Statystycznie prawdopodobieństwo, że pierwsza fala 17 stron z §3 natrafi akurat na jedną z tych 12, jest bliskie zeru (żadna z zidentyfikowanych encji §3 nie pochodzi z okresu/nadawcy powiązanego ze znanymi przypadkami mojibake wg audytu 08-06).
- Mechanizm szkody, gdyby trafiła: kompilująca sesja CC dostaje chunk z zepsutym kodowaniem jako "dowód" — najgorszy scenariusz to nie błędny fakt (model raczej rozpozna nieczytelny tekst i pominie/zaznaczy niepewność, patrz §6 wyżej), tylko marnotrawstwo — chunk wygląda jak szum, model go ignoruje, dowód dla realnego faktu ginie z pola widzenia.
- NUL w
entitiesjsonb jest poważniejszy strukturalnie — jeśli sesja kompilująca odpytujeentitiesbezpośrednio (nie tylkodocument_chunk.text), NUL bajt w jsonb może wywrócić parser po stronie klienta (Pythonowyjson/asyncpgróżnie reaguje naw zależności od ścieżki). To nie zostało zweryfikowane w tym reconie (nie testowałem odczytu takiego wiersza) — flaguję jako[do weryfikacji], nie jako potwierdzony problem.
Rekomendacja: nie blokować pierwszego etapu na R1–R3 z §6 incydentu
(charset/NUL) — skala nie uzasadnia opóźnienia PoC. Warto natomiast, żeby
lint (inwariant 3) przy pierwszym uruchomieniu zrobił jednorazowy skan
document_chunk/envelope.entities pod kątem znaków zastępczych
(<EFBFBD>) i w źródłach, które faktycznie zasiliły PoC (17 stron
§3) — tanie zabezpieczenie, żeby nie odkryć problemu dopiero przy spot-checku
tygodnie później.
9. Punkt 8 — Plan iteracji
Wzorzec: faza mailowa (kb-m5-faza-mailowa.md §10 „Plan implementacji" +
§12 kryterium ukończenia per krok) i mail-sync-recon (§6 „Podsumowanie i zakres
pracy" — tabela kroków z rodzajem zmiany). Stosuję ten sam format: kroki z
zależnościami, DoD per krok, pierwszy etap ograniczony do 1–2 sesji.
Etap 0 — Zamknięcie decyzji (ten dokument + zatwierdzenie, 0 sesji kodu)
Operator przyklepuje §11 (Decyzje) poniżej. Bez tego nic dalej nie rusza —
identyczny wzorzec jak Decyzje (a)-(g) w mail-sync-recon, które zatwierdzono
w całości przed implementacją (kb-m5-faza-mailowa.md nagłówek statusu).
Etap 1 — Szkielet kb-wiki + 3 strony proof (cel: 1 sesja)
Zakres, celowo mniejszy niż faza3 §8.2 (3–5 stron) i mniejszy niż lista z §3 (17 encji) — pierwszy etap ma zweryfikować mechanizm, nie pokryć korpus:
| # | Element | DoD |
|---|---|---|
| 1 | Repo kb-wiki (git, poza homelab-codex-ws), struktura katalogów wg faza3 §8.2, _meta/conventions.md (format frontmattera + inline-przypisów z §5, w tym reguła fallback z §5, sekcja „Niepewne/sprzeczne" z §6, rozdział retrievalu z §7 inwariant 7) |
Repo istnieje, conventions.md kompletny, czytelny bez kontekstu tej sesji |
| 2 | Walidator kb-wiki/check_okf.py — wariant lekki, wzorowany na ~/narty-2027/saalbach-kb/check_okf.py (frontmatter parsowalny + type niepuste), rozszerzony o sprawdzenie bloku sources (niepusty, każdy envelope_id istnieje w bazie — może wymagać KB_DSN) |
python3 check_okf.py PASS na repo z krokiem 3 |
| 3 | 3 strony proof, kompilowane ręcznie sesją CC z wyników hybrid_retrieve/cascade_retrieve na encjach #1 (fll-2025-26), #5 (mbank), #9 (pawel-cesar-sanjuan-szklarz) z §3 — świadomie zróżnicowane typy (sprawa/podmiot/osoba-z-aliasami) i źródła (paperless/gmail-długi-ciąg/gmail-multi-adres) |
Każda strona: frontmatter zgodny z konwencją, ≥1 przypis inline, sources: niepuste, przechodzi walidator |
| 4 | Ręczny spot-check (inwariant 3, wersja manualna — pełny lint to Etap 2) — operator albo agent czyta 3 strony vs źródłowe chunki, potwierdza brak halucynacji | Zapisany w _meta/lint-reports/2026-08-XX.md — pierwszy raport, nawet jeśli ręczny |
Dlaczego te trzy, nie 17: pawel-cesar-sanjuan-szklarz (#9) testuje
entity resolution na aliasach — jeśli to zawiedzie, cała reszta listy z §3
(gdzie kilka pozycji ma podobny problem, np. cosmose↔#7/#8) wymaga
przeprojektowania konwencji zanim zainwestuje się w kolejne 14 stron.
Trzy strony, świadomie różne, są tańszym testem niż siedemnaście podobnych.
Etap 2 — Lint automatyczny + rozszerzenie do pełnej listy §3 (2. sesja)
Zależy od Etapu 1 (mechanizm zweryfikowany). Zakres:
kb-wiki/lint.py— implementacja inwariantu 3 w kodzie (nie ręcznie): linki[[...]]do nieistniejących stron, strony-sieroty, spot-check N losowych przypisów (zapytanie dodocument_chunkpoid, fallback doenvelope_idz §5 gdyidmartwy — z metryką degradacji), sprzeczności między stronami (heurystyka: te same encje wsources:różnych stron z rozbieżnymi liczbami przy tym samym typie faktu — pełna detekcja semantyczna to zadanie dla CC, nie dla skryptu; skrypt robi tylko pre-filtr kandydatów).- Rozszerzenie o pozostałe encje z §3 (do 17), plus jednorazowy skan pod
kątem
<EFBFBD>/(§8 „follow-upy fazy mailowej") na źródłach, które faktycznie zasiliły te strony. - DoD etapu:
lint.pyuruchamiany ręcznie (nie timer — zgodnie z §4, automatyzacja poza zakresem), raport w_meta/lint-reports/, zero krytycznych znalezisk nierozwiązanych (martwe linki, sieroty) — degradacje chunk-id i sekcje „niepewne" to oczekiwany, nie błędny stan.
Poza zakresem pierwszych dwóch etapów (świadomie odłożone)
| Temat | Gdzie wraca |
|---|---|
Integracja source='wiki' w packages/kb-retrieval (§7, inwariant 5 + 7) |
Etap 3 — wymaga działającego korpusu wiki (≥Etap 2) zanim ma sens dodawać go do retrievalu produkcyjnego |
Synteza odpowiedzi (/search → odpowiedź w naturalnym języku) |
Osobna faza, kb-m5-faza-mailowa.md §11 już to tak kotwiczy |
| Pipeline eskalacji per-query (tryb B z §4) | Po syntezie odpowiedzi — bez niej nie ma sygnału do eskalacji |
| Automatyzacja lintu (timer) | Po Etapie 2, gdy wiadomo ile realnie kosztuje jeden przebieg |
Ewentualny hosting/publikacja kb-wiki |
Nie zaplanowane — patrz §2, dziś brak potrzeby |
Druga tura encji (#18-20 z §3, outbox.pl/dawny pracodawca) |
Po ustaleniu kontekstu firmy — osobne mini-śledztwo |
10. Punkt 9 — Decyzje operatora
Wzorzec (a)-(g) z kb/audits/mail-sync-2026-08-06.md §4.
(a) Wersja OKF dla kb-wiki: pin v0.1 (jak pilot) vs start od razu na v0.2
Rekomendacja: pin v0.1, z migracją zaplanowaną, nie natychmiastową.
- Pilot narty27 potwierdził w praktyce, że pinowanie v0.1 działa i że
zmiana jest tania:
docs/sessions/2026-07-31-kb-f4-final-narty27.md— „OKF v0.1 działa w praktyce, a pinowanie wersji okazało się słuszne — spec ewoluuje (v0.2:timestamp→generated: {by, at}, provenance first-class). Przy fazie 5 rozważyć start od razu na v0.2 albo pin v0.1 z zaplanowaną migracją." To jest bezpośrednia rekomendacja z pilota, cytowana w zleceniu tego reconu. - Ale:
kb-wikima silniejszą potrzebę provenance niż narty27 (który jest planowaniem wyjazdu, nie audytowalnym kompilatem nad wrażliwym korpusem). Provenance first-class w v0.2 (generated: {by, at}) pokrywa się częściowo z tym, co faza3 §8.2 już projektuje osobno (compiled_by/compiled_atwsources-owym frontmatterze) — czyli potrzeba, którą v0.2 adresuje, została już zaadresowana lokalną konwencją, niezależnie od wersji OKF. To osłabia argument "musimy mieć v0.2 od razu", bo polecompiled_byrobi tę samą robotę. - Decydujący argument za v0.1:
homelab-codexsamo jest dziś na v0.1 (scripts/kb/check_okf.py,PINNED_OKF = "0.1"). Gdybykb-wiki(osobne repo, ale koncepcyjnie ta sama rodzina dokumentów cokb/) startował na v0.2, powstałyby dwie różne wersje specyfikacji w tym samym ekosystemie narzędzi — dwa parsery, dwie reguły walidacji, mylące przy przenoszeniu wzorców między repo (dokładnie to, co uzasadnia rekomendację pilota "pin + zaplanowana migracja" zamiast "zawsze najnowsza wersja"). Spójność z resztą ekosystemu waży więcej niż wyprzedzenie o jedną wersję specyfikacji, którą i tak trzeba będzie kiedyś zmigrować wkb/też. - Migracja zaplanowana: gdy
homelab-codex/kb/migruje na v0.2 (osobna decyzja, poza zakresem tego reconu),kb-wikimigruje w tym samym oknie — jedna zamiana pola (timestamp→generated: {by,at}), zgodnie z oceną pilota że to tania zmiana.
(b) Repo kb-wiki — potwierdzenie D7 z faza3
Rekomendacja: potwierdzić bez zmian (§2). Jedyne doprecyzowanie: kompilacja
nie idzie przez agent.sh-owy worktree — osobny tryb pracy z dwoma klonami
obok siebie, do zapisania w kb-wiki/_meta/conventions.md.
(c) Tryb kompilatora — potwierdzenie batch/hybryda, pipeline eskalacji poza zakres
Rekomendacja: (§4) batch (CC/API, ręczny trigger) dla bootstrapu i
utrzymania w tej fazie; pipeline eskalacji per-query (tryb B) świadomie
odłożony do momentu, gdy istnieje synteza odpowiedzi w kb-query — bez niej
nie ma sygnału, który miałby eskalować.
(d) Fallback chunk-id → envelope_id przy re-chunkingu
Rekomendacja: (§5) dwupoziomowy link z degradacją do envelope_id, lint
raportuje liczbę zdegradowanych przypisów jako osobną metrykę, re-chunking
traktowany jako trigger do ręcznego przeglądu, nie do automatycznej naprawy.
(e) Sekcja „Niepewne/sprzeczne" i polityka aktualizacji — dopisać do konwencji
Rekomendacja: (§6) sekcja jako konwencja treści (nie pole frontmattera), domyślna polityka „dopisz, nie nadpisuj" przy sprzecznym nowym dowodzie, wyjątek dla jawnych aktualizacji tego samego faktu, rozróżnienie robi sesja kompilująca.
(f) Inwariant 7 — rozdział retrievalu kompilacji od retrievalu zapytań
Rekomendacja: (§7) dopisać do inwariantów faza3 §8.1 jako inwariant 7:
kompilacja strony wiki nigdy nie czyta source='wiki' jako dowód
(exclude_sources=('wiki',)), tylko /search (warstwa użytkownika, po
zbudowaniu syntezy odpowiedzi) widzi wiki w kaskadzie. Mitygacja
self-citation/citogenesis przy źródle, nie tylko przez lint po fakcie.
(g) Zakres i kolejność Etapu 1 — 3 strony proof, nie 17
Rekomendacja: (§9) Etap 1 = mechanizm (3 strony celowo zróżnicowane:
sprawa/podmiot/osoba-z-aliasami), Etap 2 = skala (do 17) + lint w kodzie.
Rozszerzenie listy encji (#18-20, outbox.pl) odłożone do osobnego
mini-śledztwa kontekstu firmy.
(h) Follow-upy fazy mailowej (charset/NUL) — nie blokują, jednorazowy skan przy Etapie 2
Rekomendacja: (§8) nie opóźniać PoC na R1–R3 z incydentu 20-dni-ciszy;
dopisać jednorazowy skan <EFBFBD>/ do zakresu Etapu 2 (lint), nie jako
osobny, wcześniejszy krok.
11. Podsumowanie
Korpus mailowy dogonił dziś — blokada z kb-m5-faza3.md §8.1 jest zdjęta
(§1). Architektura wiki-kompilatu jest w dużej mierze już zaprojektowana i
zatwierdzona (kb-m5-faza3.md §8, decyzja 2026-07-15/17) — ten recon
weryfikuje ją na aktualnym stanie repo, dociąga trzy realne luki, których
tamten szkic nie adresował (chunk-id vs re-chunking §5, self-citation
przy retrievalu kompilacyjnym §7 — nowy inwariant 7, sekcja
niepewne/sprzeczne §6), i daje 17-pozycyjną listę encji zalążkowych
wyprowadzoną z realnych SELECT-ów na żywym korpusie zamiast z trzech
przykładów w szkicu (§3). Rekomendowany pierwszy etap to 3 strony proof w
1 sesji (świadomie mniej niż faza3 §8.2 sugerowała, bo pierwszy test ma
zweryfikować mechanizm entity-resolution na trudnym przypadku — aliasach —
zanim zainwestuje się w skalę), z jawnym odłożeniem pipeline'u eskalacji i
integracji retrievalu produkcyjnego do kolejnych etapów.
Do decyzji operatora: (a)-(h) w §10.