Compare commits

..

No commits in common. "8af8c2eeab324604e7938e4f61726c74ec8a36b6" and "a97cec0819c26ce60c128a12e234a9ab6123ef74" have entirely different histories.

4 changed files with 7 additions and 100 deletions

View file

@ -3,7 +3,7 @@ okf: "0.1"
type: audit type: audit
visibility: private visibility: private
status: active status: active
updated: 2026-08-27 updated: 2026-08-26
as_of: 2026-08-26 as_of: 2026-08-26
links: links:
- ../phases/kb-m5-faza3.md - ../phases/kb-m5-faza3.md
@ -663,7 +663,7 @@ wiki-kompilat:
- **NUL w `entities` jsonb jest poważniejszy strukturalnie** — jeśli sesja - **NUL w `entities` jsonb jest poważniejszy strukturalnie** — jeśli sesja
kompilująca odpytuje `entities` bezpośrednio (nie tylko `document_chunk.text`), kompilująca odpytuje `entities` bezpośrednio (nie tylko `document_chunk.text`),
NUL bajt w jsonb może wywrócić parser po stronie klienta (Pythonowy NUL bajt w jsonb może wywrócić parser po stronie klienta (Pythonowy
`json`/`asyncpg` różnie reaguje na `` w zależności od ścieżki). To `json`/`asyncpg` różnie reaguje na `` w zależności od ścieżki). To
**nie zostało zweryfikowane w tym reconie** (nie testowałem odczytu takiego **nie zostało zweryfikowane w tym reconie** (nie testowałem odczytu takiego
wiersza) — flaguję jako `[do weryfikacji]`, nie jako potwierdzony problem. wiersza) — flaguję jako `[do weryfikacji]`, nie jako potwierdzony problem.
@ -671,7 +671,7 @@ wiki-kompilat:
(charset/NUL) — skala nie uzasadnia opóźnienia PoC. Warto natomiast, żeby (charset/NUL) — skala nie uzasadnia opóźnienia PoC. Warto natomiast, żeby
lint (inwariant 3) przy pierwszym uruchomieniu zrobił **jednorazowy skan** lint (inwariant 3) przy pierwszym uruchomieniu zrobił **jednorazowy skan**
`document_chunk`/`envelope.entities` pod kątem znaków zastępczych `document_chunk`/`envelope.entities` pod kątem znaków zastępczych
(`<60>`) i `` w źródłach, które faktycznie zasiliły PoC (17 stron (`<60>`) i `` w źródłach, które faktycznie zasiliły PoC (17 stron
§3) — tanie zabezpieczenie, żeby nie odkryć problemu dopiero przy spot-checku §3) — tanie zabezpieczenie, żeby nie odkryć problemu dopiero przy spot-checku
tygodnie później. tygodnie później.
@ -721,7 +721,7 @@ Zależy od Etapu 1 (mechanizm zweryfikowany). Zakres:
semantyczna to zadanie dla CC, nie dla skryptu; skrypt robi tylko semantyczna to zadanie dla CC, nie dla skryptu; skrypt robi tylko
pre-filtr kandydatów). pre-filtr kandydatów).
2. Rozszerzenie o pozostałe encje z §3 (do 17), plus jednorazowy skan pod 2. Rozszerzenie o pozostałe encje z §3 (do 17), plus jednorazowy skan pod
kątem `<60>`/`` (§8 „follow-upy fazy mailowej") na źródłach, które kątem `<60>`/`` (§8 „follow-upy fazy mailowej") na źródłach, które
faktycznie zasiliły te strony. faktycznie zasiliły te strony.
3. **DoD etapu**: `lint.py` uruchamiany ręcznie (nie timer — zgodnie z §4, 3. **DoD etapu**: `lint.py` uruchamiany ręcznie (nie timer — zgodnie z §4,
automatyzacja poza zakresem), raport w `_meta/lint-reports/`, zero automatyzacja poza zakresem), raport w `_meta/lint-reports/`, zero
@ -743,11 +743,6 @@ Zależy od Etapu 1 (mechanizm zweryfikowany). Zakres:
## 10. Punkt 9 — Decyzje operatora ## 10. Punkt 9 — Decyzje operatora
> **Status: (a)-(h) ZATWIERDZONE przez operatora w całości 2026-08-27, bez
> zmian** — wzorzec identyczny jak decyzje (a)-(g) w `mail-sync-2026-08-06.md`
> (zatwierdzone 2026-08-06 w całości, patrz `kb-m5-faza-mailowa.md` nagłówek
> statusu).
Wzorzec (a)-(g) z `kb/audits/mail-sync-2026-08-06.md` §4. 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 ### (a) Wersja OKF dla `kb-wiki`: pin v0.1 (jak pilot) vs start od razu na v0.2
@ -827,7 +822,7 @@ mini-śledztwa kontekstu firmy.
### (h) Follow-upy fazy mailowej (charset/NUL) — nie blokują, jednorazowy skan przy Etapie 2 ### (h) Follow-upy fazy mailowej (charset/NUL) — nie blokują, jednorazowy skan przy Etapie 2
**Rekomendacja:** (§8) nie opóźniać PoC na R1R3 z incydentu 20-dni-ciszy; **Rekomendacja:** (§8) nie opóźniać PoC na R1R3 z incydentu 20-dni-ciszy;
dopisać jednorazowy skan `<60>`/`` do zakresu Etapu 2 (lint), nie jako dopisać jednorazowy skan `<60>`/`` do zakresu Etapu 2 (lint), nie jako
osobny, wcześniejszy krok. osobny, wcześniejszy krok.
--- ---
@ -848,5 +843,4 @@ zweryfikować mechanizm entity-resolution na trudnym przypadku — aliasach —
zanim zainwestuje się w skalę), z jawnym odłożeniem pipeline'u eskalacji i zanim zainwestuje się w skalę), z jawnym odłożeniem pipeline'u eskalacji i
integracji retrievalu produkcyjnego do kolejnych etapów. integracji retrievalu produkcyjnego do kolejnych etapów.
Decyzje: (a)-(h) w §10 — **ZATWIERDZONE przez operatora w całości 2026-08-27, Do decyzji operatora: (a)-(h) w §10.
bez zmian.**

View file

@ -3,7 +3,7 @@ okf: "0.1"
type: phase type: phase
visibility: private visibility: private
status: active status: active
updated: 2026-08-27 updated: 2026-07-17
links: [] links: []
--- ---
@ -628,17 +628,6 @@ Adapter i embed są już idempotentne — nowość to wyłącznie orkiestracja i
> półprodukt kompilacji) i PO filtrze śmieciowych chunków. Pełna wiki po fazie mailowej > półprodukt kompilacji) i PO filtrze śmieciowych chunków. Pełna wiki po fazie mailowej
> (przyrostówka) — wcześniej kompilat byłby fotografią przeszłości. > (przyrostówka) — wcześniej kompilat byłby fotografią przeszłości.
**Inwariant 7 (dodany 2026-08-27 — rozszerzenie, nie zmiana inwariantów 16
powyżej, które pozostają NIE podlega zmianie):** decyzja (f),
`kb/audits/wiki-kompilat-recon-2026-08-26.md` §10, zatwierdzona przez operatora
w całości 2026-08-27. Kompilacja strony wiki **nigdy** nie czyta `source='wiki'`
jako dowodu (`exclude_sources=('wiki',)` w `cascade_retrieve`/`hybrid_retrieve`) —
retrieval na potrzeby kompilacji zawsze wyklucza wiki, czyta wyłącznie warstwę
dowodową (mail, paperless). Tylko `/search` (warstwa użytkownika, po zbudowaniu
syntezy odpowiedzi — inwariant 5, faza 5) widzi wiki w kaskadzie. Mitygacja
self-citation/citogenesis przy źródle retrievalu, nie tylko przez lint (inwariant
3) po fakcie — patrz audyt §7 dla pełnego rozumowania.
### 8.2 Rozwinięcie wykonawcze (szczegóły, decyzje architektoniczne bez zmian) ### 8.2 Rozwinięcie wykonawcze (szczegóły, decyzje architektoniczne bez zmian)
**Repozytorium** (rozstrzygnięcie punktu 6 szkicu): osobne repo `kb-wiki` — decyzja 7, **Repozytorium** (rozstrzygnięcie punktu 6 szkicu): osobne repo `kb-wiki` — decyzja 7,

View file

@ -18,8 +18,6 @@ reguły tego repo:
10. Wpisy `contradicts` wyglądające jak ścieżka .md też muszą istnieć; 10. Wpisy `contradicts` wyglądające jak ścieżka .md też muszą istnieć;
pozostałe wpisy to wolny tekst. pozostałe wpisy to wolny tekst.
11. `stub` o ile obecne musi być boolem. 11. `stub` o ile obecne musi być boolem.
12. Brak bajtów kontrolnych poza \t \n \r w całym pliku (łapie wklejki NUL/inne
binarne śmieci wklejone z zewnętrznych źródeł, np. wyników SELECT-ów).
Zakres domyślny: kb/ oraz docs/sessions/, z wyłączeniem README-wskaźników Zakres domyślny: kb/ oraz docs/sessions/, z wyłączeniem README-wskaźników
(POINTER_GLOBS) te nawigacją do kb-doca, nie dokumentami KB, i celowo nie (POINTER_GLOBS) te nawigacją do kb-doca, nie dokumentami KB, i celowo nie
@ -73,7 +71,6 @@ POINTER_GLOBS = (
EXCLUDE_DIRS = ("build",) EXCLUDE_DIRS = ("build",)
DATE_RE = re.compile(r"^\d{4}-\d{2}-\d{2}$") DATE_RE = re.compile(r"^\d{4}-\d{2}-\d{2}$")
CONTROL_CHAR_RE = re.compile(r"[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]")
def is_pointer(rel: str) -> bool: def is_pointer(rel: str) -> bool:
@ -235,17 +232,6 @@ def check_file(path: Path, root: Path) -> list[str]:
f"{rel}: `contradicts` wskazuje na nieistniejący plik: {item}" f"{rel}: `contradicts` wskazuje na nieistniejący plik: {item}"
) )
seen_lines: set[int] = set()
for m in CONTROL_CHAR_RE.finditer(text):
line_no = text.count("\n", 0, m.start()) + 1
if line_no in seen_lines:
continue
seen_lines.add(line_no)
errors.append(
f"{rel}: bajt kontrolny {ord(m.group()):#04x} w linii {line_no} "
"(dozwolone tylko \\t \\n \\r)"
)
return errors return errors

View file

@ -1,62 +0,0 @@
"""Tests for check_okf.py — the OKF v0.1 frontmatter validator.
Covers the control-character check added 2026-08-27: a file that otherwise has
valid frontmatter must still fail if its body contains a NUL byte or other
control byte outside \\t \\n \\r (the class of bug found in
kb/audits/wiki-kompilat-recon-2026-08-26.md raw bytes pasted in from a psql
SELECT over the mail corpus).
"""
from __future__ import annotations
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
import check_okf # noqa: E402
VALID_FRONTMATTER = """---
okf: "0.1"
type: decision
visibility: private
status: active
updated: 2026-08-27
links: []
---
"""
def _write(tmp_path: Path, body: str) -> Path:
p = tmp_path / "doc.md"
p.write_text(VALID_FRONTMATTER + body, encoding="utf-8")
return p
def test_clean_file_has_no_control_char_errors(tmp_path):
path = _write(tmp_path, "# Title\n\nZwykła treść z \t tabulatorem i \r\n końcem linii.\n")
errors = check_okf.check_file(path, tmp_path)
assert errors == []
def test_nul_byte_in_body_is_flagged(tmp_path):
path = _write(tmp_path, "# Title\n\nZawiera bajt NUL: \x00 w tym miejscu.\n")
errors = check_okf.check_file(path, tmp_path)
assert any("bajt kontrolny" in e and "0x0" in e for e in errors)
def test_control_char_error_reports_correct_line(tmp_path):
body = "linia 1\nlinia 2\nzepsuta \x00 linia 3\nlinia 4\n"
path = _write(tmp_path, body)
errors = check_okf.check_file(path, tmp_path)
control_errors = [e for e in errors if "bajt kontrolny" in e]
assert len(control_errors) == 1
# Frontmatter occupies 7 lines before the body starts.
frontmatter_lines = VALID_FRONTMATTER.count("\n")
expected_line = frontmatter_lines + 3
assert f"w linii {expected_line}" in control_errors[0]
def test_multiple_control_chars_same_line_reported_once(tmp_path):
path = _write(tmp_path, "para \x00 z dwoma \x00 bajtami na tej samej linii\n")
errors = check_okf.check_file(path, tmp_path)
control_errors = [e for e in errors if "bajt kontrolny" in e]
assert len(control_errors) == 1