# HANDOFF 2026-08-31 — fabryka wzorców RepoChad (stan pełny)

> Poprzednia historia: `HANDOFF.md` (długi, chronologiczny). Ten plik = pełny
> obraz na dziś + co dokładnie jest uruchomione i jak to wznowić.

## 1. Gdzie jesteśmy — jedna akapitowa prawda

Po pięciu falach przebudowy silnika deterministycznego (typy → relacje →
choreografia → moduły → tablice) user orzekł, że idziemy w ślepą uliczkę:
**silnik radzi sobie z pojedynczym elementem, ale kompozycji wielu elementów
per plansza nie da się zamknąć w schemacie JSON — to musi pisać model.**
Pivot: architektura V2, w której **agent LLM pisze KOD planszy** (`plansza.mjs`),
a silnik daje mu runtime (seek-safe opy), harness (render+podgląd) i wiedzę
(VADEMECUM). Pilot 12 reżimów to potwierdził; **kluczowe odkrycie: model bez
wzorca improwizuje słabo, z 4–10 klatkami wzorca „dostaje skrzydeł" i czasem
przebija oryginał.** Stąd obecna operacja: wzorcownia (automatyczne cięcie
kanału na sceny-wzorce z TTS) + masówka naśladowań (SDK claude) + przyszła
katalogizacja kodów przez codex w bazę elementów.

## 2. Pilot architektury V2 — wyniki (zamknięty)

29 plansz, 12 reżimów. Metryka usera: **ŚWIEŻE = out + in + cache_w**
(dolarów nie liczymy — subskrypcja).

| reżim | protokół | świeże/plansza | werdykt |
|---|---|---|---|
| A | sam + pętla ≤4 rund (Sonnet dom.) | ~298k | jakość top, za drogi |
| B | wzorzec + pełna pętla | ~272k | jakość top |
| C / C2 / E | low effort, 1–2 rundy | 82–86k | **zdyskwalifikowane** (bohomazy) |
| D | Sol one-shot (codex) | 31–47k | statyczny plakat |
| H | low + wzorzec + 2 rundy | ~105k | wzorzec przywraca choreografię |
| **I** | **medium + wzorzec + 2 rundy** | **~121k** | przełom: klasa A/B za 40% ceny |
| J / K | SDK medium 1 runda (z/bez wzorca) | 131k / 124k | klasa I jedną rundą |
| **M** | **SDK high 1 runda, bez wzorca** | **~126k** | najdojrzalsze; cena płaska |
| L | SDK high 2 rundy + wzorzec | ~204k | bez zysku ponad M |

**Wnioski twarde:** (1) cena świeżych jest PŁASKA przy 1 rundzie niezależnie od
effortu — high kosztuje CZASEM (6–8 min), nie tokenami; (2) 2. runda się nie
zwraca; (3) low effort psuje wykonanie (martwe liczniki, białe boxy poza skinem);
(4) klatki wzorca dają sekwencję/choreografię za darmo.
**LEKCJA METODYCZNA (user, dwukrotnie): werdykty jakości TYLKO z przebiegu
wideo lub gęstej sondy faz — stille zawyżają oceny.**

Artefakt przeglądowy pilota (11 reżimów, wideo + wzorce):
https://claude.ai/code/artifact/09f53439-2751-4916-9727-6e2d322748c7

## 3. Wzorcownia — zbudowana (fala 1)

### Skrypty `fabryka/wzorcownia/`
- **`02_granice.py`** — detektor granic scen przez OCR kickera.
  `ffmpeg crop górnego pasa 14% → negate,gray,×2 → tesseract --psm 7`, 8 procesów,
  ~9 s/film. Grupowanie fuzzy (difflib ≥0.80), crossfade buforowany (granica na
  ostatniej sekundzie pustki), scalanie <3 s, flagi `ocr_slaby|bez_kickera|
  przejsciowka`, `--waliduj` vs MAPA_TABLIC.
  **WALIDACJA BAo5: recall 0,89 · precision 0,87 · kickery 0,83 (tol. ±3 s).**
  DWA ODKRYCIA: (a) różnica pikselowa NIE działa (mediana 0,01 na granicy —
  kicker to mały tekst + crossfade ~4 s rozmywa sygnał); (b) **detektor jest
  DOKŁADNIEJSZY niż ręczna MAPA_TABLIC** (GT ze zwiadu co 4 s zaniża granice:
  „REAL WORLD ENGINEERING TASKS" stoi do 230 s, mapa mówi 226).
- **`03_tnij.py`** — sceny samowystarczalne: klatki co 2 s (max 10), wycinek mp4,
  linie lektora (pokrycie ≥40% segmentu), `meta.json`, `BRIEF.md`, `KATALOG.jsonl`.
- **`04_szkielety.py`** — TTS + pełny projekt HyperFrames bez `plansza.mjs`.
  **REGUŁA TTS (user): sumarycznie <1 h → lokalny Kokoro na Macu; powyżej →
  kanoniczny moduł `:8772`.** Fala 1 = 39,7 min audio → Mac. Zmiana silnika
  zmienia barwę głosu → jeden silnik na falę.
- **`06_masowka.py`** — orkiestrator: claim `mkdir` (atomowy), dziennik per
  worker, konto per worker, regex limitu z `llm_most`, `--wznow` ze sprzątaniem
  osieroconych claimów, timeout 45 min, domykający harness.
- **`07_strona.py`** — strona-artefakt (base64) — ZASTĄPIONA przez `08_www.py`.
- **`08_www.py`** — **generator lokalnego serwisu** `www/`: index → film → scena
  (wzorzec obok naszego renderu, klatki wejściowe, raport agenta, pełny kod).
  Uruchomienie: `python3 fabryka/wzorcownia/08_www.py --serwuj --port 8899`
  → `http://localhost:8899/www/`. Wideo prosto z dysku, zero limitów.
- **`PROMPT_NASLADOWANIE.md`** — szablon z «REPO»/«PROJEKT»/«BLOK_WZORCA».

### PATCH `fabryka/pilot/harness.mjs`
korzeń repo szukany w górę (masówka trzyma projekty głębiej niż pilot) ·
clamp `words` do `dur-0,2` (znalezisko pilota: ogon ASR poza końcem wav) ·
f6@98% (finałowy beat wypadał poza siatkę) · semafor renderu (`HF_SLOTY`,
mkdir-lock w `.sloty/`) · pin `HF_BIN` (N równoległych `npx` biło się o cache).

### Struktura i konwencja (wymóg usera: segregacja SCEN)
```
wzorcownia/<VID>/tNN/{meta.json,BRIEF.md,wzor/z*.jpg+wycinek.mp4,szkielet/}
wzorcownia/KATALOG.jsonl                    # indeks wszystkich scen
przebiegi/<RUN>/<TID>/{plansza.mjs,renders/,podglad/,uzycie.json,raport.md}
przebiegi/<RUN>/{_kolejka/*.zajete|*.gotowe, _dziennik/wNN.jsonl, PRZEBIEG.json}
www/                                        # serwis przeglądowy
```
`TID = <VID>-tNN` (np. `BAo5dTyPxwg-t07`) — ten sam identyfikator we wzorcowni,
w każdym przebiegu i w przyszłej bazie. Worker pisze WYŁĄCZNIE do swojego
katalogu; wzorcownia read-only; brak wspólnych plików zapisu.

### Stan danych
- Segmenty (words): **14/14** (6 dociągniętych z workera mini,
  `GET /api/channels/repochad/artifact/{ID}/segments_json`, bez ruszania YouTube).
- Granice: **14/14 filmów**. Triaż po czytelności OCR:
  ≥0,95 → OXZ14(59) BAo5(32) psNf(75) MHsO(38) uaIL(32) q_gMB(17, podejrzany:
  śr. 54 s/scenę); 0,76–0,84 → EbQ7, 9CAZ; <0,65 → 8dXVf, bfdvv, IY5Fm, 7H6RH,
  FJKiX, kLar1 (screencasty/inny layout — poza falą 1).
- **Fala 1 = 4 filmy** (BAo5, MHsO, OXZ14, psNf) → 204 sceny, **173 do masówki**
  (≥6 s + lektor), wszystkie ze szkieletem i TTS.

## 3b. DOROBEK SPRZED PIVOTU — nadal żywe zasoby (nie kasować!)

Silnik deterministyczny został porzucony jako *droga do celu*, ale wiedza
i narzędzia z tamtych fal są fundamentem, na którym stoi V2:

- **`fabryka/pilot/VADEMECUM.md`** (13,6k zn.) — kontrakt `plansza.mjs` +
  gramatyka stylu + katalog form. **To jest jedyna wiedza, którą dostaje każdy
  agent-projektant w masówce.** Generowany częściowo z warsztatu.
- **`fabryka/e2/warsztat/*.yaml` — 49 kart modułów** (kiedy użyć / kształt
  danych / anty-użycie / anatomia / `rozstrzyga` dla bramek) + `warsztat.py`
  (renderuje `karty_typow()` do promptów, `warsztat_md()`, `progi_bramek()`,
  `lint()` z budżetem ≤12k zn.) + `WARSZTAT.md` (sekcje ręczne: FAKTURY,
  IDIOMY KONTRASTU, GRAMATYKA, ANTY-WZORCE + sekcja AUTO).
  **Nazwy kanoniczne stąd MUSZĄ być użyte przy katalogizacji codexem.**
- **`fabryka/e2/kampania/BAo5/`** — kampania W1: **29 kart tablic wzorca**
  (sekwencja wejść co do słowa lektora, geometria, faktura, reflow, złoty
  przykład, fixture_stub), `MAPA_TABLIC.yaml` (ground truth detektora),
  `MAPA_LINIE.txt`, `AGREGAT.md`, `STATY.json`, `RECENZJA.md`, arkusze klatek.
  Statystyki wzorca: 188 wejść / 29 tablic (śr. 6,5), 103 reflowy, no-dim 26/29.
- **`fabryka/e2/DYDAKTYKA.md`** — 20 reguł, w tym **R1′ + R14–R18** z fali
  tablic (podmiot = tablica, role podmiot→mechanizm→liczba→puenta, no-dim,
  reflow, zapełnienie ~85%, semantyka faktur solid/dashed/hatch).
- **`fabryka/e2/analiza_*.md`** — 14 analiz filmów kanału (inwentarze modułów).
  **`ANALIZA_CODEX_2026-08-30.md`** — audyt zewnętrzny (26/32 scen słabszych,
  ranking przyczyn, plan 10 kroków) — to on wskazał bug „drugi pop = ukrycie".
- **Silnik deterministyczny** (dalej działa, obsługuje stare filmy): 33 typy
  plansz w `plansze-v2.schema.json`, buildery `komponenty{,-extra,-oxz,-f2,-d,
  -tablica}.mjs`, `generuj.mjs` (composer + bramki audytu), `przeglad.py`
  (bramka ciszy), `test-rozmiary.mjs` (podłoga typograficzna).
  `komponenty-tablica.mjs` = fala tablic (moduły dokładane na kotwicach,
  reflow `shift`, tryb FRAG hostujący dowolny builder jako moduł).
- **Prompty produkcyjne** (`fabryka/prompty/{REZYSER,SCENOGRAF_V2,REDAKTOR}.md`)
  pisane WYŁĄCZNIE przez codex1 z briefów `BRIEF_*_dla_codex1.md` — żelazna
  zasada projektu; ostatni regen z placeholderami «KARTY_TYPOW»/«ZLOTE_TABLICE».
- **`videos/r04-BAo5dTyPxwg/`** — pełny film referencyjny w wersjach
  (`film.v5.json`, `film.rerun3.json`) do A/B.

## 3c. Plany i artefakty (ślad decyzyjny)

Plany (zatwierdzone, w `~/.claude/plans/`):
- `we-wzorcu-ja-widze-precious-mountain.md` — fala TABLIC (diagnoza „wzorzec
  dokłada moduły", 29 tablic × 5,5 modułu vs nasz 1 typ/scena).
- `go-i-poukladaj-to-woolly-emerson.md` — **bieżący**: wzorcownia + masówka.
- starsze: `dobra-skoro-juz-znasz-*`, `skonczylo-mi-sie-chyba-*`.

Artefakty przeglądowe (canvas — zastąpione lokalnym `www/`):
- pilot 11 reżimów: https://claude.ai/code/artifact/09f53439-2751-4916-9727-6e2d322748c7
- pierwsza strona masówki (statyczna, 130 kart): https://claude.ai/code/artifact/87ba7a73-d2c7-41fa-a74b-8156c1a8c2db

## 3d. Materiał źródłowy — stan kanału

14 mp4 w `fabryka/e2/media/` (532 MB, 7983 s). **Kanał ma teraz 15 pozycji** —
nowy `vW0KY_8z4q0` („I Tested Every Qwen3.8-27B Quant…", 601 s) NIE jest jeszcze
pobrany: `POST /api/channels/repochad/ensure {"video_ids":["vW0KY_8z4q0"],
"want":"video_everything"}` na workerze mini (budżet pobrań 5000/dobę, zużyte 0).
Klatki 1 fps wygenerowane dla wszystkich 14 (`media/klatki1s_<VID>/`).

## 4. Masówka — fala 1 DOMKNIĘTA

`przebiegi/20260831-sonHI-1r-wzor`, reżim **MW** (high + wzorzec, 1 runda).
- Etap 1: 12 workerów na 3 kontach → 128 scen, ~9,6 min/scena, 72 sceny/h.
- **Etap 2 (decyzja usera): 40 workerów WYŁĄCZNIE na `claude2`**,
  wznowione po ubiciu (`--wznow` zwolnił 12 osieroconych claimów).
- **DOMKNIĘTA: 173/173 · 0 awarii · 0 flag · 25,81M świeżych (śr. 149k/scenę)
  · mediana 550 s/scenę (max 1161 s).** Per film: psNf 61, OXZ14 55, MHsO 33,
  BAo5 24. Produkt: 173 × `plansza.mjs` (mediana 6,4 kB, 3,5–11,4 kB, razem
  1,1 MB) + 173 renderów. Zero flag oznacza, że każdy agent sam napisał kod,
  sam uruchomił harness i sam domknął render — orkiestrator nie ratował ani raz.
- Wznowienie: `HF_SLOTY=8 python3 fabryka/wzorcownia/06_masowka.py --run
  20260831-sonHI-1r-wzor --rezim MW --workerow 40 --konta claude2 --wznow`

### Jakość (zweryfikowana na wideo, nie klatkach)
Naśladowanie działa i **miejscami przebija wzorzec**: przy krzywej kwadratowej
wzorzec mówi „both of these explode", nasza plansza POKAZUJE to dwiema kartami
4× MEMORY / 4× LATENCY. Próbki z trzech różnych filmów: odometr 742→770B
z chipami i tagiem „THE CATCH"; licznik 298→512 GB z paskiem 1229 GB/s;
wykres słupkowy $4 800 → $7 200 → $12 000 budowany progresywnie. Zero martwych
liczników i białych boxów, które psuły tanie warianty pilota.
Defekt zauważony: sporadyczne nakładki etykiet (1 na 3 próbki).

### DEFEKT OCR ZNALEZIONY PO FALI: M czytane jako H

Tesseract systemowo myli **M z H** w kondensowanym wersaliku kickera
(„HIXTURE OF EXPERTS", „HEHORY SCALING REBUILT", „PARAHETER ACCOUNTING").
Kicker wchodzi do `BRIEF.md`, więc **agenci dostali zepsuty tekst i wypisali go
dosłownie na ekranie w 26 z 173 scen (15%)**.

Pomiar rozstrzygnął, że to jedyna systemowa pomyłka: na 204 kickerach fali 1
para H→M wystąpiła **×34**, a każda inna (W→T, G→D, O→I …) ×1–5 i przy
oględzinach okazywała się przypadkową zbieżnością prawdziwych słów.

**`fabryka/wzorcownia/kickery.py`** (NOWY) — naprawa wysokiej precyzji, trzy
źródła dowodu w kolejności malejącej siły:
1. transkrypt TEGO filmu (ASR, niezależny od OCR) — jedyny dowód mocny na tyle,
   by nadpisać słowo poprawne po angielsku („HOE" jest słowem, ale w tym filmie
   mowa o MOE);
2. słowo znane w angielskim LUB padające gdziekolwiek na kanale → zostawiamy
   (bez tego wychodziło „HAS"→„MAS", „HE"→„ME" na filmach ze słabym OCR);
3. dla reszty: słownik kanału, potem `/usr/share/dict/words` z obcinaniem
   końcówek (web2 nie zna odmian — ma MAX i MAC, nie ma MAXED ani MACS).

Świadomie NIE zgadujemy przy dwóch podmianach naraz (HOBEL→MODEL wymaga H→M
i B→D): próba takiej heurystyki psuła tyle samo, ile naprawiała
(HAXED→MIXED zamiast MAXED). Reszta nietknięta: `BAo5-t10 HOBEL`, `MHsO-t38 HYS`.

Zastosowane: **44 kickery w 231 plikach wzorcowni** (granice.json/yaml,
meta.json, BRIEF.md, szkielet/{film.json,STORYBOARD.md,frames/01-*.html})
+ przebudowany `KATALOG.jsonl`. Wywołanie: `python3 fabryka/wzorcownia/kickery.py`
(podgląd) / `--zastosuj`. Wpięte w `02_granice.py`, więc fala 2 jest czysta
u źródła. Surowe `odczyty[]` w `granice.json` zostają nietknięte — to ślad
dowodowy OCR.

**Przebiegów NIE ruszaliśmy** (wyjścia pipeline'u są append-only). Żeby
naprawić 26 scen, trzeba je przepuścić od nowa — lista TID w
`www/` i w poleceniu niżej.

### Serwis www — nazewnictwo po ludzku i przewijanie wideo

**`00_filmy.py`** (NOWY) — tytuły z manifestu workera
(`GET /api/channels/repochad/manifest`) → `wzorcownia/FILMY.json`
(`tytul`, `krotki`, `data` dla 15 pozycji). VID zostaje kluczem maszynowym
(katalogi, claimy, przyszła baza), ale w UI nie pokazujemy go jako nazwy.

Zamiast `BAo5dTyPxwg-t10 · 11s · 166k świeżych · kod 7 KB` jest teraz:
`HOW THE MODEL READS TEXT` (nagłówek) · `Qwen3.8-Flash-Next is Here · scena 10
z 24 · 1:17–1:28 w oryginale ↗ · 166k świeżych · kod 7 KB · BAo5dTyPxwg-t10`.
Timecode jest linkiem do YouTube z `?t=`, więc wzorzec porównuje się jednym
kliknięciem. TID został jako dyskretna plakietka `.id` (`user-select:all`) —
dalej trzeba go kopiować do komend.

**PRZEWIJANIE WIDEO — przyczyna i lek.** `python3 -m http.server` **nie
obsługuje nagłówka `Range`**: na `Range: bytes=1000-2000` odpowiada `200`
z całym plikiem zamiast `206`, i nie wysyła `Accept-Ranges`. Przeglądarka nie
ma wtedy jak poprosić o kawałek od n-tej sekundy, więc pasek postępu `<video>`
jest martwy. To NIE jest wina generatora strony — to brak w bibliotece
standardowej Pythona. W `08_www.py` jest własny handler `Zakresy`
(206 + `Content-Range`, ogon `bytes=-N`, 416 poza zakresem, `Accept-Ranges`
na każdej odpowiedzi, `HTTP/1.1` + `ThreadingHTTPServer` dla keep-alive).
Zweryfikowane w przeglądarce: seek na 75% trafia co do 0,01 s w obu wideo.
`.claude/launch.json` → wpis `wzorcownia` uruchamia `08_www.py --serwuj`,
NIE `http.server`.

### Poprawki `08_www.py`
- **brak `<meta charset>`** → cała strona szła w mojibake („ŚWIEŻE" jako
  „Å›WIEÅ¼E"); dodane razem z `viewport`;
- `<title>` brał surowy HTML nagłówka (`Fabryka <b>Wzorców</b>` w zakładce) →
  tagi obcinane regexem;
- podstrona sceny: `preload="metadata"` zamiast `none` (2 pliki na stronę), żeby
  wideo pokazywało długość i pierwszą klatkę, a nie czarny prostokąt ze spinnerem.
  Siatka filmu zostaje na `none` — tam plików jest kilkadziesiąt.

## 5. Co dalej (kolejność)
1. ~~Dokończyć falę 1~~ — ZROBIONE, 173/173.
2. ~~Odświeżyć serwis~~ — ZROBIONE. Serwis stoi: `http://localhost:8899/www/`
   (wpis `wzorcownia` w `.claude/launch.json`, port 8899, katalog = korzeń repo).
2b. **Decyzja: czy przepuścić 26 scen z zepsutym kickerem** (~4M świeżych,
   ~15 min przy 26 workerach). Wzorcownia jest już naprawiona, więc wystarczy
   usunąć ich `.gotowe`/`.zajete` + katalogi i puścić `--wznow`.
3. Werdykt usera → ewentualna fala 2 (uaIL + 9CAZ/EbQ7) lub drugi przebieg
   innego reżimu (np. M bez wzorca) dla różnorodności kodu.
4. **Katalogizacja codexem** (`zbierz.py` — DO NAPISANIA): paczki po ~10 kodów
   (`plansza.mjs` + `karta.yaml`) → `baza/ELEMENTY.jsonl` + `MODULY/<nazwa>.yaml`
   + `ALIASY.tsv`. Nazwy kanoniczne MUSZĄ zgadzać się z 49 kartami
   `fabryka/e2/warsztat/`. Sugestia z projektu: niech agent-projektant zapisuje
   `karta.yaml` już w masówce (ma render przed oczami — taniej niż odgadywanie
   z kodu przez codexa).

## 6. Pułapki (potwierdzone empirycznie)
- `pgrep -fc 'claude.*--model sonnet'` NIE łapie workerów (długi prompt przed
  flagą) — sprawdzać `ps -ef | awk '$3==<PID orkiestratora>'`.
- `xargs -I{}` z długimi ścieżkami → „command line too long"; używać pętli
  Pythona/ThreadPoolExecutor.
- `timeout` nie istnieje na macOS.
- CSP artefaktów blokuje `data:` dla WIDEO (obrazy przechodzą) → blob URL albo
  lokalny serwer (obecne rozwiązanie).
- Limit artefaktu 16 MB: 135 scen w base64 = 15,4 MB → nie mieści się z HTML.
- Kokoro przy >3 równoległych procesach gubi linie (bramka audio w generuj.mjs
  retry ×3, potem twardy stop).

## 7. Powiązania z kanonem zewnętrznym (`www_new/external_connections/`)

- **Wzorce przejęte z `misc/wytwornia/`** (projekt nietykalny — importujemy,
  nie kopiujemy): `wspolne/ledger.py` (LEDGER.jsonl, md5-idempotencja, statusy
  OK z `flagi[]` / AWARIA = transport → „uruchom później") oraz `wspolne/
  llm_most.py` (regex limitu konta, parsowanie koperty `--output-format json`).
  Doktryna „flagi zamiast stopów treści" pochodzi stamtąd i obowiązuje u nas.
- **Worker YT (mac mini `:8782`)** — źródło mp4 i transkryptów kanału
  `repochad`; użyte: `GET /api/channels/repochad/artifact/{ID}/segments_json`
  (6 filmów, bez ruszania YouTube). Dokumentacja: `komputery/mac_mini/API.md`.
- **ZAKTUALIZOWANE PRZEZ NAS 2026-08-31** (reguła zwrotna z CLAUDE.md):
  w `external_connections/MODELE-ENDPOINTY.md` statusy dwóch usług TTS
  zmienione z `?` na `●` po weryfikacji na żywo — moduł TTS `:8772` (Mac Studio,
  kanoniczny punkt wejścia) i OmniVoice Ryzen `:8770`. GPU box `.25:8003`
  pozostaje zgaszony.
- **W rezerwie, nieużyte**: vLLM na GPU boxie `192.168.0.24:8010`
  (Qwen3.8-27B-FP8 z obsługą obrazu) jako mocniejszy OCR/VL, gdyby tesseract
  zawiódł na innym layoucie; wybudzenie `llmctl start qwen38-27b-fp8-g0`
  (sprawdzić wcześniej `llmctl status`, żeby nie ubić cudzej pracy).
- **Konta SDK**: `claude1/2/3` (KONTA.md) — masówka jedzie obecnie wyłącznie na
  `claude2` (decyzja usera). Kody wyjścia: 75 = limit, 78 = konto martwe.

## 8. FAZA 0 — naprawy P0 (2026-08-31, po dwóch audytach codex Sol xhigh)

Dwa niezależne audyty (`codex1` — prompt/runtime/protokół, `codex2` — zakotwiczenie
w kanonie) + własna weryfikacja na danych. Naprawione:

### `fabryka/komponenty.mjs`
- **`kotwica()` była prefiksowa w OBIE strony** (`target.startsWith(norm(w.text))`),
  więc kotwica `"agent"` łapała pierwsze `"a"` w lektorze. Pomiar na 1022 kotwicach
  fali 1: **28/173 plansz miało kotwicę mylącą się o >0,5 s** — skrajnie `"Alibaba"`
  o **12,75 s** (3,83 zamiast 16,58). Teraz exact-first, potem stem TYLKO w jedną
  stronę i od 4 znaków, plus jawny 5. argument `odCzasu` zamiast ukrytego kursora
  (kursor mylnie przesuwałby kod pisany nie po kolei). **Po naprawie: 0/173 pomyłek,
  1016/1022 kotwic rozstrzyga się na słowie dokładnym.** `znajdzWord()` miał ten sam
  błąd w fallbacku — poprawiony tak samo.
- `dziennikKotwic` — każde rozstrzygnięcie z trybem `EXACT|STEM|FALLBACK` ląduje
  w `harness.json`.
- **`walidujOps(ops, dur)`** → `{bledy, ostrzezenia}`. Błąd: op kończy się PO `dur`,
  drugie wejście na tym samym selektorze, `NaN`/`Infinity`, op nieznany albo zakazany
  (`cam`/`dim`/`blink`/`glitch`), pusty selektor, `at < 0`. Ostrzeżenie: op w ostatnich
  0,15 s (`count`: 0,25 s). Rozdział jest wyliczony: z 77 przekroczeń fali 1 **53 to
  sam margines**, więc twarde blokowanie ich wywaliłoby zdrowe sceny. Bramka
  `wrapFrame({rygor:true})` — silnik deterministyczny woła bez rygoru i dalej działa.
  Fala 1 przez ten filtr: **150/173 czysto, 23 z realnym błędem** (24 opy ucięte,
  10 drugich wejść).
- Timeline rejestrowany w `window.__timelines` **po** pętli opów (błąd w połowie
  zostawiał częściowy timeline: początek sceny grał, reszta znikała bez śladu).
- `el()` zgłasza selektor trafiający liczbę elementów różną od 1.

### `fabryka/pilot/harness.mjs`
- **kod wyjścia 1** przy błędzie kontraktu, nieczystym `check` albo padniętym renderze
  (wcześniej wszystko było tylko drukowane, a scena dostawała status OK).
- **`harness.json`** — kotwice z trybami, `bledy_ops`, `ostrzezenia_ops`, `zakazy`,
  `check`, `check_findings`, `render`, `podglad` z sekundami. Zero nulli.
- Zakazy skanowane na CSS **i** HTML, case-insensitive: `@keyframes`, `animation*:`,
  `<script>`, handlery `on*`, `.animate(`.
- Semafor obejmuje `check` **i** render (`check` też startuje Chromium).
- Mozaika **2×3, kafelki 940×529** (było 1×6 po 768×432 — drobne kolizje ginęły).
  Bez podpisów w obrazie: **ten build ffmpeg nie ma filtra `drawtext`** — sekundy faz
  są w `harness.json` i w wypisie konsoli. `final.png` = kopia `f6` (było 97%, czyli
  kadr SPRZED ostatniego wejścia).

### `fabryka/wzorcownia/06_masowka.py` — przepisany
`--model` (Opus 5 **nie ma aliasu**: `--model 'claude-opus-5[1m]'`), `--tury 1|2`,
`--wiedza pelna|slim`, `--tidy <plik z TID>`. Protokół 2-turowy przez
`claude -p --resume <session_id>`: T1 ślepa → orkiestrator **zamraża** artefakty
(`plansza.t1.mjs`, `renders/plansza.t1.mp4`, `podglad_t1/`, `harness.t1.json`) → T2
ogląda własny podgląd i wybiera `KEEP_T1` / `ACCEPT_T2` / `ROLLBACK_T1`; rollback
przywraca zamrożone bez ponownego renderu. **Zero retry**: limit konta ucisza workera,
ale scena dostaje status `INCOMPLETE_LIMIT` i NIE wraca do puli. `MANIFEST.json`
niezmienny (model, wiedza, tury, lista TID, md5 promptów/wiedzy/runtime); `--wznow`
dopisuje zdarzenie. Sprawdzanie `returncode` i żywotności mp4 przez `ffprobe`.
Kopia BRIEF-u sanityzowana w wariancie `slim` — **wzorcownia zostaje bajt w bajt**.

### Prompty i wiedza
- `PROMPT_NASLADOWANIE.md` → **`PROMPT_T1.md` + `PROMPT_T2.md`** (z draftu codexa,
  gniazda `«WIEDZA»`, `«KANON»`, `«BLOK_WZORCA»`). Historia fali 1 zachowana
  w `przebiegi/20260831-sonHI-1r-wzor/PROMPT.md` i 173 `_prompt.md`.
- **`fabryka/pilot/VADEMECUM_V3.md`** (7,2 kB, napisany przez codex1) — bez katalogu
  38 form, bez nakazu „5–8 dokładek" i „puenta = dashed tag". Dowód, że ten nakaz
  działał: **`dashed` w 173/173 planszach fali 1, „puenta" w 162 (94%)**, a według
  codexa `dashed` bezpośrednio przy tagu puenty w 147/173.
- **`fabryka/wzorcownia/09_podobienstwo.py`** — automatyczna miara wierności:
  `0,6 × Layout-IoU + 0,4 × Addition-F1` na maskach 64×36 z pominięciem pasa kickera.
  Zweryfikowana syntetycznie: identyczne 1,000 · rozłączne 0,000 · **nadmiarowy
  element karany (0,796)**.
- `08_www.py --runy A,B,C` — porównanie wielu przebiegów obok źródła w jednym wierszu.

### Czego audyt NIE potwierdził
Plansze masówki nie są uboższe od pilota: **0,91 op/s** wobec 0,85–0,88 w dwóch
wariantach pilota uznanych za „jakość top". Surowa różnica (12 vs 21 opów) to
wyłącznie długość sceny (mediana 10 s vs ~26 s). Kontaminacja między scenami
marginalna: 6/173 (3%). Klatki wzorca bez wady (jasność 22,4 → 23,9 po pozycjach).


## 9. PAUZA 2026-08-31 wieczorem — stan zamrożony, wszystko wznawialne

**Bieg główny `20260901-opus5-2t-pelna`** (Opus 5 · 2 tury · wiedza pełna,
wszystkie 14 filmów): **264/355 scen z renderem**, 54,8M świeżych, decyzje
ACCEPT_T2 191 (74%) · KEEP_T1 46 · ROLLBACK 6 · T1_LIMIT_W_T2 14. Zatrzymany
CZYSTO (STOP-flaga, zero sierot w kolejce). Zostało 91 scen ≈ 17M.
`claude1` zdławiony tygodniówką (reset wt. 01.09). **Wznowienie:**
`export HF_SLOTY=10 AI_WAIT_MAX_S=0 && python3 fabryka/wzorcownia/06_masowka.py
--run 20260901-opus5-2t-pelna --model 'claude-opus-5[1m]' --effort high --tury 2
--wiedza pelna --tidy fabryka/wzorcownia/sceny_wszystkie.txt --workerow 20
--konta claude1 --wznow` (najpierw `rm przebiegi/20260901-opus5-2t-pelna/STOP`).

**Nowe mechanizmy z 31.08 (po drugim audycie kosztów):**
- `INCOMPLETE_LIMIT` NIE stawia `.gotowe` — limit zwalnia scenę do puli
  (wcześniej jedno wyczerpanie okna po cichu zjadło 233 sceny);
- **STOP-flaga** (`touch przebiegi/<RUN>/STOP`) = drain bez sierot; NIGDY pkill
  (audyt: kille wyrzuciły 33,4M/dzień = 29% quoty, niewidoczne w ledgerze);
- pomiar kosztu Z TRANSKRYPTÓW, dedup po `message.id` (po `uuid` zawyża ~2×);
  szczegóły: `external_connections/claude_code_sdk/03-claude-p-cli.md`;
- znany wyciek na później: agent czyta 48KB `komponenty.mjs` w 98% scen
  (~25k/scenę) — po biegu wzbogacić tabelę opów w VADEMECUM (ręką codexa).

**Odrzucone po testach:** mapa ruchu + op `flow` (regres: ruch dokładany do
statycznych słupków — review usera negatywny; op został w runtime, nieudokumentowany).
Wiedza slim odrzucona wcześniej. Werdykt usera: **Opus 5 · 2 tury · pełna wygrywa**
i to jest standard produkcyjny.

**Kanał `co_kraj_to_obyczaj`** (133 filmy, 40,5h): job 969 na mini w toku
(faza topics ~50%), pliki na NAS `channels/co_kraj_to_obyczaj/`. Detektor plansz
gotowy: `fabryka/wzorcownia/10_hyperframes.py` (kryterium: udział NIERUCHOMYCH
pikseli w oknie 4s — plansza stoi, wstawka filmowa zmienia wszystko; zwalidowany:
MHsO 89% pokrycia, IY5Fm 32%). Progi stroić na nowym kanale przez `--raport`.
Egress mini przestawiony na Ethernet/Funbox (user); powrót na hotspot:
`networksetup -ordernetworkservices "Wi-Fi" "Ethernet" ...` na mini.

**Serwis www**: `http://localhost:8899/www/` (wpis `wzorcownia` w launch.json) —
przegląd wierszowy, 4 kolumny, syncowane odtwarzanie, jeden głos (domyślnie nasz
render, bo źródła RepoChada są bez audio — worker MA audio, nasze lokalne mp4 nie;
ewentualny re-fetch = decyzja usera). TTS wzorcowni: 355/355. Tailscale SSH do
mini re-autoryzowany przez usera 31.08 (działa).


## 10. BIBLIOTEKA ELEMENTÓW — zbudowana (2026-08-31 wieczór, całość na codexach)

Cel usera: z przerobionych scen wyłuskać TYPY elementów, zdeduplikować i zrobić
bazę wzorców dla przyszłych agentów („aha! to się nadaje do tego slajdu").
Nazwy i karty opisują FORMĘ — treść instancji to wymienne wypełnienie (lorem
ipsum); ta zasada jest wpisana w prompty, karty i nagłówki egzemplarzy.

**Potok** `fabryka/biblioteka/{01_inwentarz,02_identyfikuj,03_synteza,05_wytnij,04_www}.py`:
inwentarz lokalny (złoto: blok `WEJŚCIA:` w 243 raportach agentów) → identyfikacja
per scena (codex Sol medium, wizja: kadr f6 + mozaika; 80 równoległych na
codex1+codex2 — decyzja usera „40/konto") → scalenie 232 propozycji NOWY (jedno
wywołanie) → karty + wybór egzemplarzy z OGLĄDANIEM cropów → wycinki kodu → www.

**Stan `baza/`**: 1468 instancji (ELEMENTY.jsonl) · **126 typów po scaleniu**
(46 kanonicznych / 36 nowych ≥2 inst. / 44 pojedyncze w poczekalni) · **82 karty**
MODULY (kanoniczne przepisane z warsztatu + nowe pisane przez codex w tym samym
formacie) · **285 egzemplarzy** przyklady/<typ>/ (85 częściowych — kod z pętli;
6 bez HTML) · ALIASY.tsv · INDEKS.md z zasadą NA ŻĄDANIE (anty-menu, lekcja
173/173). Koszt Claude: ~0 (tylko próba ognia 34k na claude3).

**Próba ognia (zaliczona)**: świeży sonnet, temat spoza korpusu (Hetzner vs AWS),
8 tur / 34k. Wybrał bar-rows + hero-stat, a **compare ODRZUCIŁ cytując
anty_uzycie z jego własnej karty** („Dwie liczby → bar-rows") — karty działają
jako logika doboru, nie tylko opis. Wziął formę i choreografię, treść własna.

**Pułapki naprawione po drodze** (dla przyszłych biegów):
- kroki łańcucha bash bez `|| exit` LECĄ DALEJ po padzie pythona — scal padł
  na timeoucie i wynik zbudował się bez mapy (278 typów-śmieci); scalenie 232
  slugów = effort medium + timeout 1500, wtedy przechodzi;
- codex zwraca klucze mapowania BEZ prefiksu `NOWY:` — dopasowywać obie formy;
- B1 zwraca selektory ROZWIĄZANE (`#tb-x`), kod bywa szablonowy (`${P}-x`) —
  ekstrakcja wymaga normalizacji `${…}`→`__V__` i dopasowania po sufiksie;
- cropy trzeba generować PRZED wyborem egzemplarzy (kolejność kroków).

**Ogony**: FJKiX-t02 nie przechodzi identyfikacji (2× timeout; domiar w tle);
po dokończeniu masówki (91 scen) pipeline jest przyrostowy — `02 → 03 --elementy
→ 03 --karty → 05 → 04` doliczy nowe sceny. Przegląd: `www/biblioteka_pilot.html`
(126 typów, ★ = egzemplarz wybrany).


## 11. ZAMROŻONE OGONY (decyzja usera 2026-08-31 wieczór) + CHRZEST BIBLIOTEKI

**Zamrożone na kiedyś** (nic nie robić bez decyzji):
- masówka 91/355 scen do dokończenia (`--wznow` na claude1 po resecie tygodniówki);
- `FJKiX-t02` — identyfikacja pada 3× na timeout;
- 44 typy z poczekalni biblioteki (pojedyncze instancje, bez kart);
- kanał `co_kraj_to_obyczaj` — job 969 mieli na mini (topics ~50%), detektor
  plansz `10_hyperframes.py` gotowy i zwalidowany, strojenie progów po pobraniu.

**CHRZEST BOJOWY biblioteki (w toku)**: `przebiegi/20260901-opus5-biblio-BAo5` —
całe wideo jak kiedyś r04: 24 sceny BAo5, Opus 5 · 2 tury · wiedza pełna,
**BEZ klatek wzorca** — zamiast nich `--biblioteka`: baza/INDEKS.md na żądanie
(2–4 typy, karty + po 1 egzemplarzu z cropem). To jest docelowy tryb produkcji
własnych materiałów. Konto claude3, 20 workerów. Po biegu automat skleja
`FILM.mp4` (concat po numerach scen, każda z własnym TTS) i buduje www
z kolumnami: biblio ↔ opus-pełna (z wzorcem) ↔ fala 1. Ocena: czy biblioteka
zastępuje klatki wzorca przy zachowaniu jakości.


## 12. WORKFLOW V3 — tekst wchodzi, film wychodzi (spięty i zwalidowany)

`fabryka/prompty/REZYSER_V3.md` (autor: codex1, 2 erraty) + `fabryka/biblioteka/
06_produkcja.py` + `06_masowka.py --zrodlo produkcje --biblioteka`.
Rurociąg: scenariusz_<VID>_czasy.txt → REŻYSER_V3 (codex2, strict-schema; dzieli
na tablice z kickerami, wagami, relacjami) → TTS per tablica (Kokoro) → drzewo
`produkcje/<PID>/` w formacie wzorcowni → masówka Opus 2t pełna z biblioteką
(bez klatek wzorca) → sklejka FILM.mp4. Porównanie: `www/produkcja_MHsO.html`
(oryginał z audio | V3 | V3B) — MHsO wybrane, bo jedyne z lokalnym audio.

**Pętla werdyktów usera (obie iteracje tego samego wieczoru):**
1. V3 (`PMHsO`, 22 tablice): działa, ALE „zalewamy slajdy wszystkim, co mówi
   TTS" + cięcie w ułamek sekundy po ostatnim wejściu.
2. Poprawka nr 1 (kwota `informacje` 2–4) — user skorygował: nie liczba,
   tylko OSĄD ważności per slajd.
3. V3B (`RMHsO`): kontrakt **dominanta + wsparcie(0–3, pusta lista legalna)**
   z testem „czy teza stoi na samej dominancie?"; brief sekcje DOMINANTA/
   Wsparcie NADRZĘDNE nad kanonowym „5–8 dokładek"; **`hold_s: 2.2`**
   w film.json → harness wydłuża scenę o ciszę na doczytanie (zweryfikowane:
   lektor 22,6 s → wideo 24,8 s). Efekt: 22/22, opy/planszę 19→15 (mediana),
   5/22 tablic na samej dominancie.

Strict-schema codexa: additionalProperties=false wszędzie i KAŻDE pole w
required — inaczej 400. Pułapka zapisana też przy okazji B1 biblioteki.

## 13. BUG SILNIKA ZNALEZIONY PRZY RESKINIE (naprawiony 2026-09-01 ~2:00)

Tło klatki NIGDY się nie malowało: frameShell stylował `#01-p1-bg`, a selektor
id od CYFRY jest w CSS nieważny — reguła z `background:${skin.ground}` była
po cichu odrzucana od początku projektu. Niewidoczne, bo koperta projektu
(index.html z generuj) ma kolor #0A0E1A ≈ bg ciemnego skina. Jasny skin
(paper-cartesian) zdjął maskę: karty jasne, tło czarne. Fix: selektory
atrybutowe `[id="…"]` dla bg/stage/world/domslot w `fabryka/komponenty.mjs`.
KONSEKWENCJA DLA CIEMNYCH RENDERÓW: dotąd pokazywały płaską kopertę zamiast
pełnego groundu (winiety radialne!); przyszłe rendery będą wierniejsze wzorcowi.
Reskin całości: `przebiegi/20260901-opus5-v3d-MHsO-jasny/` (22/22, zero LLM);
produkcyjny film w innym skinie = bieg agentów w tym skinie od startu
(kontrast per skin pilnuje bramka). Skiny na półce: 9 w `fabryka/skiny/`.

## 14. WARSTWA STYLÓW — nadpisy_css i doktryna „tylko farba" (2026-09-01 rano)

User: „style mało się różnią" → pomiar: 22/22 plansz hardkoduje border-radius
i box-shadow, sylwetka siedzi w kodzie agentów. Dodane do silnika: pole skina
**`nadpisy_css`** wstrzykiwane PO stylach agenta (frameShell) — skin włada
geometrią/teksturą, nie tylko kolorem. Charaktery: swiss (ostre rogi, zero
glow), terminal-crt (scanlinie ::after + fosfor), broadside (ziarno druku SVG),
candy-pop (radius 2.2cqw + twarde cienie na div[id]).

**DOKTRYNA po wpadce „rozjeżdża się i nachodzi":** nadpisy przy reskinie
gotowych scen wolno robić WYŁĄCZNIE farbą (radius, cienie, tekstury, poświaty,
kolory). ZAKAZ zmian metryk: font-family/letter-spacing/text-transform/
border-width globalnie rozwalają layout wymierzony pod inne litery. Zmiana
typografii = pełna produkcja w danym skinie (`06_produkcja.py --skin`), gdzie
agent sam wymiaruje boksy, a bramka kontrastu pilnuje odcieni.

Narzędzia: `fabryka/biblioteka/07_style.py` (macierz scen×skinów, --force,
strona `www/style_<RUN>.html` z sync-odtwarzaniem) · 9 skinów w `fabryka/skiny/`
· HyperFrames z pudełka ma tylko caption-skiny (napisy) i rejestr bloków —
palety plansz to nasza warstwa.

## 15. ARSENAŁ BLOKÓW ZAINSTALOWANY LOKALNIE (2026-09-01 rano)

Cały rejestr HyperFrames w repo: `bloki/` — **356/357 pozycji** (139 bloków →
`compositions/`, 217 komponentów → `compositions/components/`; 32 MB z modelami
glb/sfx/lib). Padła 1: `lt-neon-border` (błąd po stronie rejestru). Spis z tagami:
`bloki/KATALOG.md` (generator `fabryka/biblioteka/09_bloki.py`); przeszukiwarka:
`www/bloki.html` (filtr tekst+tagi, snippety data-composition-src). Agenci:
sekcja ARSENAŁ w `baza/INDEKS.md` — zasada NA ŻĄDANIE (1–2 pozycje po tagu,
nigdy hurt). Mapy: us-map/bubble/flow/hex, spain-map, world-map+globus.

## 16. Prezentacja arsenału dla modela — protokół drzewiasty (2026-09-01)

Problem: agent dostawał płaskie spisy (`bloki/KATALOG.md` 66 kB ≈ 15k tokenów,
`baza/INDEKS.md` 18 kB z ścieżkami egzemplarzy w tabeli) — „przejrzenie wszystkiego"
oznaczało hurtowe ładowanie. Przebudowa na drzewo, do kontekstu wchodzi tylko wybrana gałąź:

- **Poziom 0** (czytany zawsze): `baza/INDEKS.md` (~9 kB: 82 typy jedną linią
  [klasa·instancje·kiedy], poczekalnia, wskaźnik na arsenał) oraz `bloki/INDEKS.md`
  (~2 kB: 13 kategorii z licznikami scen/składników i „kiedy sięgnąć").
- **Poziom 1** (po wyborze): karta typu `MODULY/<typ>.yaml` LUB jedna kategoria
  `bloki/kategorie/<kat>.md` (jedna linia na pozycję, ≤8,6 kB, worek „Różne" 7 poz.).
- **Poziom 2** (przy wpinaniu): jeden egzemplarz `przyklady/<typ>/` lub plik bloku
  `bloki/compositions/…`.

Generatory: `05_wytnij.py` (INDEKS poziom-0 biblioteki), `09_bloki.py` (drzewo
arsenału: stałe `KATEGORIE` z regułami po tagach/nazwie, pierwsza wygrywa; sprzątanie
gałęzi-sierot po zmianie reguł). Metadane rejestru przeniesione ze scratchpada
(ginął z sesją!) do `bloki/_katalog.json`. Blok `--biblioteka` w `06_masowka.py`
jawnie dopuszcza arsenał tym samym protokołem (wcześniej „niczego więcej nie czytaj"
mogło go blokować). KATALOG.md zostaje jako widok dla ludzi — INDEKS zakazuje go agentom.

Test dymny nawigacji (agent read-only, tylko punkt wejścia + 2 potrzeby sceny):
przeszedł 0→1 poprawnie, załadował 20 kB / ~5k tokenów (1,7% wagi samego
ELEMENTY.jsonl), trafnie wybrał `bar-chart-race` + `sdf-iris` z rezerwami
i uzasadnionymi odrzuceniami. Zwrócił 6 luk protokołu — wszystkie wszyte
w generatory: (a) jawne „ścieżki względem korzenia repo" (szukał bloki/ w baza/),
(b) ELEMENTY.jsonl/ALIASY.tsv „tylko grep, nigdy Read w całości" (1 MB pokusy),
(c) wybór 2–4 typów NA OPISACH poziomu 0, karta dopiero po wyborze,
(d) limit = 1 kategoria na 1 potrzebę (N potrzeb → N kategorii),
(e) reguła remisu przy briefie „forma A albo B" (drugą kategorię otwórz
tylko bez trafienia w pierwszej), (f) ROUTING arsenał↔biblioteka (gotowa
forma → bloki/, narracja autorska → MODULY/).

## 17. Poziom 0 sekcjami + test bojowy „obcy TTS" (2026-09-01)

**Kategorie poziomu 0 biblioteki**: 82 typy pogrupowane w 9 sekcji tematycznych
(otwarcia-i-werdykty, liczby-i-metryki, porównania, listy-i-karty, procesy,
narracja-autorska, kod, media-i-tła, drobnica) — przypisania z jednego wywołania
codex2 (strict enum) w `baza/_kategorie.json`; `05_wytnij.py` renderuje sekcje
z „kiedy tu zajrzeć", typy sortowane po liczbie instancji.

**Test bojowy na obcym materiale**: wytwórnia (`misc/wytwornia`) →
`biologia_2011_rozszerzony_1__z7-w1` „Jak inhibitory hamują aktywność enzymów?"
(7 scen, 229 słów, polski). Łańcuch: scenariusz → REŻYSER_V3 (codex1: 5 tablic,
dominanta+wsparcie OK; SKAZA: kickery po angielsku przy polskim lektorze) →
szkielety → **10_polski_glos.py** (Kokoro nie zna PL: omnivoice `:8772` głos m01
+ words z faster-whisper venv scratchpad + normalizacja czasów; oryginalne audio
zostaje jako `01.kokoro.wav`) → masówka `20260901-wytwbio-test` (Opus 5 · 2 tury
· pełna · --wzorzec nie --biblioteka, claude1). Wytwórnia ma własny `film.mp4`
tego zadania — porównanie head-to-head na www.

## 18. Infografiki na żądanie agenta sceny (2026-09-01, eksperyment — wdrożony)

Plan: `~/.claude/plans/immutable-pondering-metcalfe.md` (z tabelą walidacji).
Mechanika: agent w T1 woła `node fabryka/pilot/infografika.mjs --scena «PROJEKT»
--opis … --etykiety "a;b" [--aspekt 3:2|16:9|1:1] [--styl papier|skin]` →
krok A: codex2 (gpt-5.6-sol, low, strict schema, `AI_WAIT_MAX_S=0`) pisze prompt
rysownika z `INFOGRAFIKA_REGULY.md` + BRIEF; CLI dokleja twarde ograniczenia
(etykiety = jedyny tekst) → krok B: `python3 -m imagegen render` (gpt-image-2,
orkiestrator gpt-5.4-mini, ~$0.01) → `<scena>/assets/ig/NN.png` + `NN.prompt.md`
+ `infografiki.jsonl`; agent dostaje gotowy snippet `<img src="assets/ig/NN.png">`
(goła ścieżka = jak fonty; runtime przepisuje we frame'ach tylko `../`).
Limity: 2 obrazy / 3 próby na scenę; semafor `.sloty_ig` (2 sloty, rekultywacja
po 15 min); numer rezerwowany atomowym `NN.lock`. Masówka: `--infografiki`
wstrzykuje blok «INFOGRAFIKA» (T1) i «INFOGRAFIKA_T2» (wolno usunąć wrapper).
Test dymny (`przebiegi/_test-ig/PMENDb-t01`): papier 90 s, skin 60 s, oba
1536×1024 z etykietami dosłownie; render check CZYSTY; piksel: przed kotwicą
regiony = tło (mean ≈10), po — treść (153/72 i 55/80); negatywy LIMIT/walidacja OK.
Biegi porównawcze: `20260901-mendel-base` (bez) vs `20260901-mendel-ig` (z) — werdykt niżej.

## 19. Polskie glify w fontach skinów (2026-09-01) — skaza systemowa naprawiona

W renderach Mendla (baseline) słowa odręczne z ą/ż/ź rozjeżdżały się („RÓŻ NICE",
„wciąż"): WSZYSTKIE 12 fontów w `fabryka/fonty/` było subsetami `latin` bez
`latin-ext` — każdy polski znak leciał do fontu systemowego. Naprawa: pełne TTF
z `google/fonts` → instancje zmiennych (wght/opsz) → `fontTools.subset`
latin+latin-ext → woff2 (te same nazwy plików, frameShell bez zmian). Stare pliki
w `fabryka/fonty/_latin_only/`. **Gochi Hand nie ma polskich glifów u źródła** —
skiny `blackboard` i `repochad-hand` nie nadają się do polskich tekstów bez zmiany
fontu odręcznego. **PUŁAPKA**: sceny mają WŁASNE kopie fontów — `generuj.mjs:59` kopiuje `fabryka/fonty`
do `<szkielet>/assets/fonts/` przy budowie; podmiana w repo NIE dosięga istniejących
scen ani szkieletów (pierwszy re-render baseline'u nic nie zmienił — md5 w scenie = stary
subset). Naprawa = wgranie nowych woff2 do `assets/fonts/` każdej sceny/szkieletu
porównywanego biegu + re-render harnessem (bez LLM). Nowe szkielety dostają dobre fonty
automatycznie. Szczegóły: `fabryka/fonty/README.md`.

Adopcja infografik: bieg `20260901-mendel-ig` (blok v1 „opcjonalny" za «KANON»)
= **0/7 wywołań, 0 wzmianek w transkryptach** — blok niewidzialny. Wariant v2
(codex1 z briefu): decyzja OBOWIĄZKOWA w nagłówku plansza.mjs
(`// infografika: TAK — … | NIE — …`), krok 0 w „Zadanie" i pozycja 4 w „Wejście"
(tokeny «INFOGRAFIKA_KROK»/«INFOGRAFIKA_WEJSCIE», aktywne tylko z `--infografiki`).
Bieg `20260901-mendel-ig2` na claude3 — werdykt niżej.

### Werdykt eksperymentu infografik (Mendel, 3 biegi × 7 tablic, Opus 5 · 2 tury · pełna · biblioteka)

| bieg | blok | wywołań | użytych w kodzie | koszt świeże | czas | decyzje T2 |
|---|---|---|---|---|---|---|
| `mendel-base` | brak | — | — | 2,10M | 18 min | 7× ACCEPT_T2 |
| `mendel-ig` (v1) | „opcjonalna" sekcja za «KANON» | **0/7** (0 wzmianek w transkryptach) | 0 | 1,54M | 22 min | 7× ACCEPT_T2 |
| `mendel-ig2` (v2) | decyzja OBOWIĄZKOWA + krok 0 + wejście 4 | **1/7** (t03, 84 s, papier 3:2) | 1 | 1,50M | 20 min | 6× ACCEPT_T2, 1× KEEP_T1 |

Wnioski: (1) narzędzie „opcjonalne" w prompcie = narzędzie nieistniejące — agent
go nawet nie rozważa; wymuszona jedna linia decyzji daje mierzalny sygnał i zero
kosztu; (2) przy decyzji jawnej model jest konserwatywny i uzasadnia rzeczowo:
6× NIE („scena to relacja danych / diagram procesu / definicja"), 1× TAK tam, gdzie
scena opisuje czynność fizyczną (kastracja kwiatu + pędzelek) — obraz trafił do
WNĘTRZA karty-dominanty jako jej lewa połowa, wsparcie orbituje; (3) narzędzie
nie zwiększa kosztu tokenowego biegu (1,50M vs 1,54M vs 2,10M — szum), obraz ~$0,01
i +84 s w sesji; (4) jakość obrazów (4 testowe + 1 produkcyjny): etykiety dosłownie
z diakrytykami, zero watermarków, styl papier = wklejka podręcznikowa, styl skin =
spójny z planszą; obie ścieżki zdatne. Nie zmierzone: czy widz woli wersję z obrazem
(to werdykt usera z www: `produkcja_PMENDb.html`).
Skazy do osobnych briefów: kickery po angielsku przy polskim lektorze (REŻYSER_V3 —
codex1); długie tablice (3–4 min) mają długie przebiegi statyczne — tam obraz
albo drugi „takt" planszy miałby największy sens.
Strony (serwer :8899): `www/produkcja_PMENDb.html` (3 kolumny: baseline / ig-v1 / ig-v2 +
tabela tablic), `www/produkcja_PWYTB.html` (enzymy: film wytwórni vs V3). Wszystkie
filmy przerenderowane fontami latin-ext. Generator: `fabryka/biblioteka/11_porownanie.py`.

## 20. Tryb „infografika-first" (2026-09-01) — eksperyment po werdykcie usera

User: model nie rozumie potencjału gpt-image-2 (schematy, tekst literalny) — moje reguły
trybu pojęciowego wprost mu tego zakazywały; woli dobrą infografikę od wstawek HF.
Zapis: tryb „dowolny" (§18) zostaje jako workflow. NOWE:
- CLI `--tryb bogaty`: reguły `INFOGRAFIKA_REGULY_BOGATE.md` (co model potrafi: schematy
  z calloutami, przekroje, procesy, porównania A|B, rzędy pokoleń; nagłówek ≤6 słów + ≤8
  etykiet/haseł ≤4 słowa; liczby tylko z briefu); guard odwrócony (wymagane etykiety agenta
  muszą być, projektant może dodać do 10 łącznie; liczby w napisach sprawdzane w briefie/opisie);
  snippet 60cqw „gospodarz kadru".
- masówka `--infografiki zawsze`: blok v3 (codex1 z briefu) „Infografika — nośnik treści
  planszy": 1 obraz na planszę PRZED kodem, 55–65cqw na osi, wchodzi po kickerze; elementy
  HF wyłącznie OMAWIAJĄ obraz na kotwicach (chipy, dashed-tagi, zdanie-token, karty), nie
  zasłaniają, nie dublują napisów; T2 nie wolno usunąć obrazu. `--infografiki` bez wartości
  = `dowolne` (v2). Stałe `*_ZAWSZE` w 06_masowka.py; hash reguł bogatych w MANIFEST.
Bieg: `20260901-mendel-ig3` — werdykt niżej.

### Werdykt ig3 (infografika-first, `20260901-mendel-ig3`, claude3)
7/7 OK · 1,98M świeżych · 17 min · ACCEPT_T2 4, KEEP_T1 3. **Obraz w kodzie: 4/7**
(t01 rzędy pokoleń „Teoria mieszania cech", t02 proces „Kiedy wynik znaczy", t03 przekrój
po kastracji, t05 porównanie A|B). Trzy braki = limity narzędzia, nie modelu: t04 i t06
padły na semaforze (7 agentów zamawia w tej samej minucie; tryb bogaty trwa 98–204 s;
2 sloty × 180 s czekania za mało), t07 odrzucił walidator (agent podał >8 etykiet).
Naprawa w CLI: 4 sloty (max kontraktu imagegen), czekanie do 600 s, nadmiar etykiet
w trybie bogatym przycinany do 8 z ostrzeżeniem (zamiast odmowy). Dogrywka t04/t06/t07:
bieg `20260901-mendel-ig3b` (`--tidy`); film końcowy = ig3 (t01,t02,t03,t05) + ig3b.
Integracja: agenci stawiają obraz na osi (55–65cqw) zaraz po kickerze i omawiają go
kartami/chipami/słupkami na kotwicach — format „infografika + omówienie HF" działa
z pierwszego strzału; tekst na obrazach literalny, polskie znaki OK.
Skaza obrazów (do obserwacji): w t05 gpt-image-2 zgubił diakrytyki w nagłówku wersalikami
(„CIAGLA" zamiast „CIĄGŁA") i w jednej etykiecie („posrednie"), choć w pozostałych
obrazach polskie znaki są poprawne — najsłabiej w KAPITALIKACH. Mitygacja do sprawdzenia
w regułach bogatych: nagłówek zapisywany zwykłą pisownią (nie wersalikami) albo bez liter
z ogonkiem w nagłówku; ewentualnie kontrola OCR po generacji (CT108 ma tesseract? —
tu wystarczy sonda wizyjna codexa na cropie nagłówka).
Dogrywka: `ig3b` (t04 ✓106 s, t06 ✓101 s; t07 ✗ — strażnik „brak wymaganych etykiet"
odrzucił obraz, bo agent podał „wyglada" bez ogonka, a projektant napisał „wygląda").
Poprawka CLI: porównanie etykiet bez diakrytyków (NFD, ł→l); w trybie bogatym brak
wymaganej etykiety = OSTRZEŻENIE, obraz powstaje (w trybie pojęciowym nadal twardy
podzbiór). t07 trzeci raz: bieg `ig3c` (`--tidy`, 1 worker). Film końcowy trybu
infografika-first = ig3 (t01,t02,t03,t05) + ig3b (t04,t06) + ig3c (t07) — sklejka
mieszana, nazwa `przebiegi/20260901-mendel-ig3/FILM.mp4` (źródła w LEDGER poniżej).
**Werdykt usera (twardy): „nie było odrzucania obrazów, tylko flagi".** CLI przerobione:
zły --aspekt/--styl/--tryb → domyślne + flaga; nadmiar etykiet → przycięcie + flaga (oba
tryby); etykiety spoza listy / pominięte / >10 / liczby spoza briefu → FLAGI, obraz
powstaje; awaria codexa w kroku A → prompt awaryjny z opisu agenta + flaga. Flagi w
`infografiki.jsonl` (`flagi: [...]`) i na stdout (`FLAGA: …`, licznik w linii GOTOWA).
Bez obrazu zostaje tylko: brak sceny/opisu, LIMIT budżetu (2 obrazy / 3 próby),
semafor >600 s, brak PNG z gpt-image-2. Zasada wpisana do README („Zasady twarde").

## 21. R&D: odsłanianie fragmentów infografiki po kolei (zlecone agentowi, 2026-09-01)

Pomysł usera: obraz = „100 słów", ale wchodzi cały naraz; HF powinien odsłaniać
jego części (Rodzice → F1 → F2) na kotwicach lektora. Trzy drogi: (1) mapa regionów
po fakcie z modelu wizyjnego (qwen-flash :8020 / codex -i) + K kopii `<img>` w wrapperach
z `clip-path: inset()` wchodzących istniejącymi opami — bez zmian silnika; (2) bboxy
deklarowane przez projektanta promptu (weryfikowane wizją); (3) dekompozycja HF-natywna
(gpt-image-2 rysuje części bez tekstu, HF składa strukturę i napisy). Poligon:
`przebiegi/_test-regiony/PMENDb-t07/` (kopia t07 z ig3c). Wynik agenta → §21 cd.

### Werdykt końcowy trybu infografika-first (`--infografiki zawsze`)
| bieg | tablice | obrazy w kodzie | świeże | czas |
|---|---|---|---|---|
| ig3 | 7 | 4/7 (t04,t06 semafor; t07 walidator) | 1,98M | 17 min |
| ig3b (dogrywka, `--tidy`) | t04,t06,t07 | 2/3 (t07 strażnik diakrytyków) | 0,57M | 14 min |
| ig3c (dogrywka) | t07 | 1/1 | 0,17M | 13 min |
| **razem film** | 7 | **7/7** | 2,72M | — |
Film: `przebiegi/20260901-mendel-ig3/FILM.mp4` (783 s) sklejony z trzech biegów wg
`FILM.LEDGER.json`. Strona: `www/produkcja_PMENDb.html` — 4 kolumny (baseline / ig-v1 /
ig-v2 / infografika-first). Wszystkie 3 dogrywki wynikały z limitów NARZĘDZIA (semafor,
walidatory) — po doktrynie „flagi, nie odrzucenia" i 4 slotach/600 s powinny zniknąć.
Formy obrazów użyte przez agentów: rzędy pokoleń (t01), proces (t02), przekrój (t03),
przełącznik P0/F1/F2 w stylu skin (t04), porównanie A|B (t05), oś z flagą P0 (t06),
droga do rozstrzygnięcia z „?" (t07). Integracja: obraz = gospodarz na osi, HF omawia.

## 22. Głos lektora: m01 → m04 + loudnorm (werdykt usera „upośledzony", 2026-09-02)

Diagnoza: użyłem głosu banku `m01` („Enceladus — Breathy", zdyszany); standard polskich
produkcji usera (wytwórnia, DECYZJE.md) to **`m04` „Charon — Informative" + loudnorm
EBU R128** (I=-16, TP=-1.5, LRA=11). Karta była właściwa: ryzen CT111 widzi JEDNĄ
kartę — RTX 5060 Ti = `gpu0`/:8002 (doc fractal_server/GPU.md opisuje inny stan: tam
gpu0 = 5080); `tts-omni-gpu1` nie ma GPU (`CUDA_VISIBLE_DEVICES=1` nie istnieje) —
wystartowany przeze mnie wg runbooku działał jako zombie bez karty → zatrzymany.
Moduł `:8772` przy jawnym `gpu` potrafi dać 503 (stałe mapowanie starego boxa) →
`auto`. `10_polski_glos.py`: domyślnie m04, loudnorm, `--force --znacznik` zachowuje
poprzednie audio obok (`01.m01.wav`, `01.kokoro.wav`), loguje nagłówki X-Engine/X-Voice/X-GPU.
Po regeneracji: wgranie audio+audio_meta+czasów do WSZYSTKICH scen porównywanych
biegów (jak z fontami — sceny mają własne kopie) + re-render + sklejki.
Uzupełnienie: moduł `:8772` dał 503 „tunel nie wstał" (idzie przez jumphost z hasłem
z sejfu), a Mac widzi CT111 po LAN — `10_polski_glos.py --backend box` (domyślnie) woła
`http://192.168.0.45:8770/v1/audio/speech` z tym samym itemem, jaki składa moduł
(`ref_audio=/opt/models/refs/bank_gemini/m04_pl.wav` + `ref_text` z voices.json);
`--backend modul` zostaje opcją. Pułapka skryptu: awaria TTS po `rename` zostawiała
szkielet bez `01.wav` (przywrócone ręcznie) — przy kolejnej edycji: rename dopiero PO
udanej syntezie. Nowy skrypt `12_propaguj_audio.py`: wgrywa audio/audio_meta/czasy do
istniejących scen przebiegów i przerenderowuje równolegle (sceny mają własne kopie).

## 21. Odsłanianie infografiki REGIONAMI na kotwicach lektora (2026-09-02, prototyp działa)

Cel: obraz z gpt-image-2 („Rodzice → F1 → F2") omawiany częściami jak elementy HF. Mechanizm
BEZ zmian silnika: K kopii tego samego `<img>` w wrapperach `position:absolute;inset:0` z `clip-path`
(`inset()` dla jednego prostokąta, `polygon(nonzero,…)` z mostkami do (0,0) dla unii), pod nimi „reszta"
= ten sam obraz z dziurami (`polygon(evenodd, …)`, dziury ROZŁĄCZNE — nakładające się odwracają
parzystość) + podkład w kolorze tła obrazu (kolor z brzegu PNG). Każda warstwa wchodzi zwykłym opem
wejścia (fadeIn/pop/fadeUp) na własnej kotwicy, „wskazanie" = `pulse` (transform-origin = środek
regionu). Nic nie znika, plansza kończy jako kompletny obraz. Walidator przepuszcza (opy istniejące,
jedno wejście na warstwę), `check` CZYSTY, render OK, 12/12 kotwic EXACT.
- Narzędzie: `fabryka/pilot/regiony.py --png <scena>/assets/ig/NN.png [--nazwy "a;b"] [--model auto|qwen|codex|brak]
  [--snippet --prefix pl] [--gt] [--surowe log]` → `NN.regiony.json` (lista `{nazwa,bbox_pct,kolejnosc,wycinki_pct…}`),
  `NN.regiony.png` (ramki do oka; kropkowana = surowa ramka modelu), `NN.regiony.log.json` (model, czas, tokeny, flagi).
  Metoda: model wizyjny NAZYWA regiony i daje ramki z grubsza (obraz 1024×576 JPEG, koordynaty w px) → „snap"
  każdej krawędzi do najbliższej pustej linii (rynna <0,8 % tuszu, okno ±4 %) → składowe spójne tuszu:
  każda do JEDNEJ warstwy (≥50 % pola w ramce albo jedyny sąsiad → region poszerza się o jej ramkę;
  sporna między dwoma = szkielet w „reszcie": linie działowe, strzałki, łączniki) → unie prostokątów
  rozłącznych. Zero retry; walidacja = flagi (krawędź w tuszu, nakładanie, brak regionu, model padł → piksele).
- Trafność na t07 (7 regionów: nagłówek/Rodzice/F1/podpis F1/F2/podpis F2/koperta vs prawda ręczna z projekcji
  tuszu): **qwen-flash 7/7, średnie IoU 0,92** (surowe ramki modelu 0,59–0,95; snap+składowe podnoszą do 0,77–0,98),
  10–27 s, 0 $; **codex2 gpt-5.6-sol low 7/7, IoU 0,89**, 43 s; segmentacja pikselowa bez modelu: 11 anonimowych
  składowych (etykieta oddzielona od obiektu) — tylko awaryjna. Domyślnie `auto` = qwen, gdy żyje (◐ start ręczny).
- Prototyp: `przebiegi/_test-regiony/PMENDb-t07/` (kopia sceny; `plansza.mjs` = prototyp, `plansza.agent.mjs` = oryginał
  agenta). Kolejność: papier+szkielet („lekcja") → nagłówek („rozstrzygnęła") → Rodzice („Gdybyśmy") → F1 („F1")
  → dashed tag HF („kłopot") → pulse F1 (2. „F1") → podpis F1 („przewiduje") → F2 („Rozstrzygnięcie") → pulse F2
  („F2" po 30 s) → podpis F2 („znaczyć") → koperta („widać") → puenta HF („zabija", koniec 47,39 < 47,91).
  Dowód pikselowy (`dowod/dowod_pikselowy.py`, klatki z renders/plansza.mp4): przed kotwicą region = płaski papier
  (std 0,0–2,7, Δ od podkładu 7), po — treść (std 37–66, Δ 62–129); 7/7 (koperta „SPRAWDŹ" tylko przez zadeklarowane
  nakładanie z F2). Klatka końcowa vs źródło: różnice wyłącznie na krawędziach kreski (resampling), pas ±2 px wzdłuż
  szwów CZYSTSZY niż reszta (|Δ| 14,7 vs 26,6) — szwy leżą w rynnach koloru papieru, mostki polygon bez artefaktów.
  Podgląd bez renderu: `dowod/scrub.mjs <scena>` → `podglad_scrub.html` (ten sam RUNTIME + suwak; serwer :8899).
- Generator „z pudełka": `infografika.mjs … --regiony [--prefix pl]` = krok D po obrazie: woła regiony.py
  (nazwy = etykiety_finalne) i wypisuje blok CSS+HTML+ops (kontener 56cqw/aspect-ratio, warstwy, sugerowane opy).
  Parser argumentów: flaga bez wartości nie zjada następnego `--` (reszta zachowania bez zmian).
- Ograniczenia: regiony = prostokąty/unie prostokątów (obiekt nieprostokątny ciągnie kawałek sąsiada — pokazuje
  się z WCZEŚNIEJSZĄ warstwą, flagowane); strzałka w rynnie między dwoma regionami zostaje w szkielecie od
  początku (F1→F2 poszło do F2, bo ramka modelu ją objęła — niespójne, ale nieszkodliwe); nagłówek = osobny region
  (tekst); kolor podkładu = brzeg obrazu (obraz bez jednolitego tła → szwy widoczne; wtedy pomiń podkład, dziury
  pokażą tło skina); `polygon(evenodd)` wymaga dziur rozłącznych (narzędzie rozkłada); K kopii `<img>` = K dekodowań
  tego samego pliku (cache przeglądarki, 7 warstw bez wpływu na render).
Wynik: 12 tablic zsyntezowanych m04 przez box wprost (Mendel 668 s zamiast 783 s — m04
mówi ~15 % szybciej; enzymy 123 s), loudnorm R128; propagacja + re-render **37/37 scen
CZYSTY+OK** (plansze kotwiczą się dynamicznie na `words`, `WE()` przycina do strefy
ciszy); kotwice: 20 FALLBACK + 2 STEM na kilkaset (m.in. literówka ASR „poszmyślimy" —
whisper small; przy większej skali rozważyć `medium`). Filmy i strony przebudowane:
`produkcja_PMENDb.html` (4 kolumny), `produkcja_PWYTB.html`. Poprzednie audio zachowane
obok jako `01.m01.wav` / `01.kokoro.wav` w szkieletach.

## 23. BUG harnessa: mozaika 2×3 miała kafle f5/f6 NA WIERZCHU rzędu 1 (2026-09-02)

`xstack … layout=…|0_2*h0|w0_2*h0` — ffmpeg 8.1 nie liczy `2*h0`; f5/f6 lądowały na
y=2 px na kaflach f1/f2 (canvas 1880×1058 zamiast ×1587). Objaw: „poszatkowane" karty
w kaflach 1–2 (nałożenie klatek). Od zmiany na 2×3 KAŻDA mozaika w fabryce była tak
zepsuta; tura 2 czyta mozaikę + f1/f4/f6 osobno, więc widziała też poprawne klatki, ale
kafle 1–2 mozaiki kłamały. Poprawka: `0_h0+h2|w0_h0+h2` (suma wysokości). Wszystkie
istniejące mozaiki przebudowane z zachowanych f1..f6 (bez re-renderu). Lekcja: nowy
układ mozaiki sprawdzać PIL-em (rozmiar canvasu = kolumny×szer, rzędy×wys).

## 24. Tryb `--infografiki warstwy` (infografika-first + regiony) — bieg ig4 (2026-09-02)

User: „no czekam" → wpięcie R&D z §21 w masówkę. Blok v4 (codex1 z briefu): jak v3 +
`--regiony --prefix «P»` (+ `--nazwy` dla części bez etykiety), czekanie na `REGIONY GOTOWE`,
wklejenie CSS/HTML dosłownie, `#P-ig-baza` po kickerze, `#P-ig-r1..rK` po jednym opie wejścia
na kotwicach w kolejności z OPS, `pulse` = wskazanie, flagi informacyjne, awaria mapy →
snippet całościowy. T2: nie usuwać obrazu ani warstw, wolno poprawiać kolejność/kotwice.
Stałe `*_WARSTWY` w 06_masowka.py; hash `regiony.py` w MANIFEST. Bieg: `20260902-mendel-ig4`.
Werdykt ig4 (`20260902-mendel-ig4`, claude1): **7/7 OK · 1,43M świeżych · 21 min · ACCEPT_T2 6,
KEEP_T1 1**. Każda scena: obraz (103–239 s) + mapa regionów (8–12 regionów) + WSZYSTKIE
warstwy wpięte (regiony+1 baza), check CZYSTY, kotwic 18–32 na scenę (warstwy dodają kotwice);
flagi mapy 0–2 na scenę (informacyjne). Zero awarii narzędzia po doktrynie flag + 4 slotach.
Film: `przebiegi/20260902-mendel-ig4/FILM.mp4`; strona `produkcja_PMENDb.html` — 5 kolumn;
przegląd `przeglad_ig.html` (13_przeglad.py). Koszt tokenowy niższy niż baseline (1,43M vs 2,10M).

## 25. Werdykt usera po ig4: kierunek dobry, wykonanie słabe — „dziury creepy" (2026-09-02)

Diagnoza (user + mapa t01): wycinacz „rzeźbi w tym, co jest" — model wizyjny ramkuje
ETYKIETY (np. „Rodzic wysoki" = 10 %×9 %: głowa + podpis), reszta postaci idzie do szkieletu
albo jest cięta prostokątem → rozdarty papier. Potrzebna współpraca OBU stron:
1. **Strona wycinająca — REFLEKTOR** (wdrożone, domyślne): nic nie jest wycinane; baza =
   cały obraz przyciemniony (`brightness(.34) saturate(.35)`), regiony = kopie w pełnej
   jasności z `inset(… round 1.2cqw)`. Niedokładna ramka = nieostra granica światła.
   `regiony.py --warstwy reflektor|wycinanie`, `infografika.mjs --warstwy …`. Próbki:
   `przebiegi/_test-reflektor/PMENDb-t01|t03` (ten sam kod plansz ig4, tylko CSS).
2. **Strona generująca — kompozycja pod odsłanianie** (do zaprojektowania w prompcie,
   OSTROŻNIE — user: może obniżyć jakość obrazów): gdy zamawiany jest obraz z regionami,
   projektant promptu ma planować obraz jako SIATKĘ komórek: każda nazwana część w
   osobnej komórce z własną etykietą W ŚRODKU komórki, puste rynny między komórkami,
   strzałki/łączniki tylko w rynnach (osobna warstwa „szkielet"), nagłówek w pasie u góry;
   plan siatki (`komorki: [{nazwa, wiersz, kolumna}]`) wychodzi z projektanta i jest
   ŹRÓDŁEM regionów (wizja tylko weryfikuje/snapuje do rynien). Ryzyko: sztywna siatka
   = mniej „bogate" obrazy; dlatego wariant promptu do osobnego testu A/B na 2–3 tablicach
   zanim wejdzie do trybu warstwy.
3. **Strona wycinająca — reguła składowych** (do zrobienia w regiony.py): region nigdy
   nie tnie spójnej składowej tuszu — jeśli ramka modelu obejmuje tylko część składowej
   (etykieta bez obiektu), region rośnie do bboxu składowej; gdy dwie ramki dzielą jedną
   składową → scalenie regionów (grubsze odsłanianie zamiast rozdarcia); flaga.
Przyczyna strukturalna wycinania (t01): „reszta" = obraz MINUS PROSTOKĄTY wszystkich
regionów, więc każda składowa szkieletu, która wchodzi w cudzą ramkę (nogi Rodzica w ramce
„Pokolenie 1"), znika do czasu odsłonięcia tamtego regionu → rozdarcie. Reguła składowych
(§25 p. 3) tego nie naprawi, bo dziury są prostokątne z definicji `clip-path`.
**Wycinanie v2 (jeśli reflektor nie wystarczy):** maski pikselowe — regiony.py ma już
składowe spójne (scipy.ndimage); eksport PNG-masek per region (`NN.maska-rK.png`, alfa =
składowe przydzielone do regionu, lekko rozdmuchane) + `mask-image:url(...)` na warstwach
i maska odwrotna na reszcie → cięcie dokładnie po tuszu, nigdy przez składową; koszt:
K dodatkowych PNG (małych) na obraz, zero zmian silnika (CSS mask jest w Chromium).
**Werdykt usera: reflektor ODRZUCONY** („nieostre drażni widza — widzi, że coś tam jest, a
jeszcze tego nie widzi"); nieodsłonięte ma nie istnieć na ekranie. Wdrożone „wycinanie v2"
= **maski pikselowe** (domyślne `--warstwy maski`): w `dolacz_skladowe` obiekt dzielony
między ≥2 ramki idzie W CAŁOŚCI do regionu o największym pokryciu (składowe liniowe —
strzałki/linie — zostają w szkielecie); region „sama etykieta" (tusz < 0,4 %) scalany
z regionem obiektu obok; `maski()` zapisuje `NN.maska-rK.png` (alfa = składowe regionu
rozdmuchane o 0,6 % W) i `NN.maska-reszta.png` (dopełnienie); snippet: `mask-image` na
`<img>` warstw i reszty (podkład bez zmian). Test: `przebiegi/_test-maski/PMENDb-t01|t03`
(plansze ig4 przepięte skryptem: numery regionów mapowane po nazwach, opy scalonych
etykiet → pulse).
Pułapka masek (zmierzona w przeglądarce): CSS `mask-image` czyta KANAŁ ALFA obrazu;
PNG w trybie „L" (jasność) ma alfę 255 wszędzie → brak maskowania (wszystkie warstwy
widoczne naraz; check CZYSTY nie wykryje). Zapis masek jako „LA" (alfa = maska).
Weryfikacja: w panelu przeglądarki `fetch()` PNG + `createImageBitmap` → próbka RGBA.
Pułapka `regiony.py --surowe`: bieg z `--surowe` nadpisywał `NN.regiony.log.json` BEZ surowej
odpowiedzi modelu → kolejny bieg wpadał w segmentację pikselową („region-1…") i maski
nie pasowały do warstw planszy (wszystko widoczne od razu). Poprawka: surowa odpowiedź
przenoszona do nowego logu. Scalanie etykiet: preferuj region, którego ramka pokrywa się
z podpisem w poziomie (obiekt pod/nad), a nie najbliższą ramkę z boku.
Render masek v2 (t01): dziury zniknęły, obiekty całe, klatka końcowa kompletna. Skazy:
strzępy etykiet w szkielecie („Rodzic", „Potomek poś") — litery/wyrazy to osobne składowe
bez przydziału → reguła: małe NIEliniowe składowe bez przydziału idą do regionu z najbliższą
składową (≤4 % W); scalanie etykiety po najbliższej SKŁADOWEJ regionu (nie ramce).
Test przepinania plansz ig4 (mapowanie starych numerów po nazwach) ma artefakt: kotwica
scalonej etykiety steruje całą grupą (prawa grupa weszła wcześniej) — w prawdziwym biegu
agent kotwiczy już scalone regiony, artefakt nie występuje. Poligon: `_test-maski2/`.

## 26. Maski pikselowe — komplet reguł (2026-09-02)

`regiony.py --warstwy maski` (domyślne; CLI przekazuje). Reguły przydziału składowych tuszu:
1. składowa w ≥50 % w ramce → region; obiekt (nieliniowy) dzielony między ≥2 ramki → W CAŁOŚCI
   do największego pokrycia; składowe LINIOWE (wydłużone ≥8:1 albo wypełnienie <6 %) sporne →
   szkielet (strzałki, linie działowe, klamry);
2. składowe bez przydziału, nieliniowe, ≤4 % W od składowej regionu → ten region (strzępy
   etykiet, kawałki kreskowej grafiki; bez limitu rozmiaru);
3. ciągłość linii tekstu: litera/wyraz obok składowej innego regionu na tej samej linii
   bazowej (pion ≥60 %, odstęp ≤0,6 h) → region z większą liczbą znaków w tej linii („M");
4. region „sama etykieta" (tusz <0,4 %) → scalony z regionem posiadającym najbliższą składową
   (obiekt pod podpisem), flaga.
Maski: `NN.maska-rK.png` (LA, alfa = składowe ∪ rozdmuch 0,6 % W), `NN.maska-reszta.png`
(dopełnienie); CSS `mask-image` na `<img>` warstw i reszty; podkład bez zmian. Wynik na
t01 (papier) i t03 (kreska na ciemnym): obiekty całe, zero dziur, klatka końcowa kompletna,
szkielet = papier + nagłówek/strzałki. Podglądy: `assets/ig/NN.maski.podglad.png`.
Poligony: `_test-maski2` (t01/t03), `_test-maski3` (t03 bez limitu rozmiaru).
Bieg `20260902-mendel-ig5` (claude1): tryb `warstwy` z maskami pikselowymi (v2) — ta sama
strona generująca co ig4 (obrazy zamawiane tak samo), zmiana wyłącznie po stronie cięcia.
Cel: film porównawczy ig4 (prostokąty, dziury) vs ig5 (maski) na tych samych 7 tablicach.

## 27. Schematy kompozycji — koordynacja rysownika i wycinacza (propozycja usera, 2026-09-02)

User: „image generator generuje wg określonych schematów (mapa myśli: centrum + zewnętrzne;
stage podzielony na sekcje…), wtedy wycinający wie, jak ciąć". Wdrożone:
- `fabryka/pilot/schematy.py`: katalog slotów w % płótna — `mapa-mysli:N` (centrum + N
  satelitów po okręgu), `rzad:N` / `proces:N` (kolumny, strzałki w rynnach), `pion:N`
  (rzędy), `siatka:RxC`, `porownanie` (A | B + werdykt); slot 0 = nagłówek (pas u góry);
  rynny ≥ 2 % W; `opis_layoutu()` → sekcja „## Layout (MANDATORY…)" z procentami do
  promptu rysownika.
- `infografika.mjs --schemat <s> --nazwy "treść slotów;…"`: layout wchodzi do żądania dla
  projektanta promptu jako OBOWIĄZKOWY (reguły bogate §4a każą przepisać go dosłownie),
  a `regiony.py --schemat` bierze te same sloty jako regiony (model wizyjny pomijany;
  snap do rynien + składowe tuszu + maski bez zmian) → wycinacz zna strukturę z góry.
- Ryzyko (user): sztywny layout może obniżyć jakość/„bogactwo" obrazu → test na
  `przebiegi/_test-schemat/PMENDb-t02` (mapa-mysli:5), potem A/B na 2–3 tablicach zanim
  wejdzie do bloku promptu masówki (to wymaga briefu dla codex1: agent wybiera schemat
  wg formy treści: proces → proces:N, porównanie → porownanie, pojęcie+aspekty → mapa-mysli).
Test schematu (`_test-schemat/PMENDb-t02`, mapa-mysli:5, papier, 16:9): obraz 132 s;
projektant (codex) przepisał layout dosłownie z procentami i rozpisał treść per slot;
rysownik narysował panele DOKŁADNIE w slotach (nagłówek, centrum „?", 5 satelitów);
wycinacz bez modelu wizyjnego (`--schemat`): 7 regionów ze slotów, snap do rynien,
21 strzępów dołączonych, 5 łączników → szkielet; maski całe; render check CZYSTY,
plansza dymna odsłania slot po slocie. To jest „koordynacja obu stron" z §27 —
działa bez LLM po stronie cięcia. Lab wycinek (3 agenty, `przebiegi/_lab-wycinki/`)
mierzy to na kilkunastu obrazach (A: szablon promptu bez LLM + schematy; B: cięcie
pikselowe bez wizji na dowolnym obrazie; C: sędzia bez człowieka — symulator + metryki).
Ustalenie po teście schematu: rysownik rysuje RAMKI paneli wokół slotów; klasyfikacja
„liniowa" wysyła je do szkieletu → od 1. klatki widać puste ramki czekające na treść
(user odrzuca placeholdery jak reflektor). Do rozstrzygnięcia w labie: A — zakaz ramek w
prompcie vs ramki jako część slotu; B — reguła: linia obejmująca tusz jednego regionu →
ten region (w szkielecie tylko łączniki przez rynny); C — defekt „ramka w szkielecie".
ig5: 6/7 OK (ACCEPT_T2 5, ROLLBACK_T1 1), 1,89M, 20 min; t07 = PUSTY_PRODUKT: agent odpalił
wycinacz w tle (run_in_background) i „czekał na powiadomienie", którego w `-p` nie ma →
tura bez planszy. Poprawka (moja, operacyjna, w blokach ZAWSZE/WARSTWY): wywołanie
w pierwszym planie, nigdy w tle. Dogrywka: `20260902-mendel-ig5b` (--tidy t07).

### Werdykt ig5 (maski pikselowe w produkcji, `20260902-mendel-ig5`)
6/7 OK (t07 PUSTY_PRODUKT — tło, patrz wyżej; dogrywka ig5b) · 1,89M · 20 min · ACCEPT_T2 5,
ROLLBACK_T1 1. Każda scena: 5–9 masek = 5–9 warstw w kodzie, check CZYSTY, 14–23 kotwic.
Wizualnie (t02, t06): obiekty całe, brak dziur i strzępów; pozostały defekt = PUSTE RAMKI
paneli w szkielecie widoczne przed treścią (t02 dolny-lewy panel) — w labie (§27).
Strona: `produkcja_PMENDb.html` 5 kolumn (baseline / ig2 / ig3 / ig4 prostokąty / ig5 maski),
`przeglad_ig.html` 76 kafli. Film ig5 tymczasowo 6 scen (t07 po dogrywce).

## 28. Rejestr presetów kompozycji — „byleby to grało ze sobą" (2026-09-02)

User: mapa myśli była tylko przykładem; układ może być liniowy albo dowolny — warunek
jest jeden: rysownik i wycinacz dzielą tę samą definicję. Rodowód: image_generator
`lab/imagegen_lab/slides/prompty.py` + `wr.pola()/wr.granice()` — rejestr WARIANTÓW
slajdu (belka, pole A, pas B/C lub BC scalone; `pion`/`poziom` z granicą kolumn 1/3–2/3;
`wolny`) i matura_PL `2_pola/kompozycja.md` („slajd = plansza z polami-klockami").
Projekt rejestru (schematy.py, właściciel: lab A):
- każdy preset = (a) topologia slotów partycjonująca płótno pod nagłówkiem, (b) kolejność
  odsłaniania, (c) reguła łączników (co wolno rysować w rynnach), (d) szkielet promptu;
- rodziny: `rzad:N` / `proces:N` (liniowo), `pion:N` / `os-czasu:N` (etapy w czasie),
  `mapa-mysli:N` (pojęcie + aspekty), `centrum-boki` (jeden gospodarz + 2 boczne),
  `porownanie` (A|B + werdykt), `siatka:RxC` (równorzędne), `cykl:N` (koło etapów),
  `stos:N` (warstwy jedna na drugiej), **`wolny`** (bez slotów → wizja + maski; dla
  przekrojów, scen, pojedynczych obiektów);
- wybór presetu wg FORMY treści tablicy (tabela decyzyjna w bloku promptu, brief dla
  codex1): proces → proces; A vs B → porownanie; pojęcie i jego aspekty → mapa-mysli lub
  centrum-boki; etapy w czasie → os-czasu/pion; N równorzędnych → siatka/rzad; obiekt
  z częściami → wolny;
- niezmiennik: sloty z rejestru trafiają JEDNOCZEŚNIE do promptu rysownika (layout
  obowiązkowy) i do wycinacza (regiony) — bez zgadywania po fakcie; `wolny` = jedyna
  ścieżka z modelem wizyjnym.
Metryki i decyzja o presetach „bezpiecznych" (rysownik ich nie łamie) — lab A/C.
ig5b: t07 ✓ (740 s, 173k, ACCEPT_T2, 5 warstw, check CZYSTY) po zakazie tła w bloku.
Film ig5 = 7/7 (668 s; LEDGER: t01–t06 ig5, t07 ig5b). Strona `produkcja_PMENDb.html`
5 kolumn (baseline / ig2 / ig3 / ig4 prostokąty / ig5 maski); `przeglad_ig.html`.
Koszt biegu z maskami: 1,89M + 0,17M = 2,06M (vs ig4 1,43M — więcej kotwic i warstw).

## 29. Lab wycinek — raport C (sędzia bez człowieka), 2026-09-02

`fabryka/pilot/lab_wycinki_metryki.py` (0 LLM, ~2 s/obraz; OCR tesseract tylko do nazw
etykiet w werdykcie): symulacja odsłaniania klatkami PIL, M1–M6 na składowych, werdykt
CZYSTY / UWAGI / ODRZUCONY z zarzutami i lokalizacją; orkiestrator `_lab-wycinki/C/bieg.py`,
tabela `C/tabela.md` (94 wiersze: 21 obrazów × warianty), strona `www/lab_wycinki_C.html`.
Kalibracja czysta: ig4 prostokąty (user: creepy) → ODRZUCONY (11 i 4 ciężkie), maski v2
(user-OK) → UWAGI (0 ciężkich). Progi: cięcie ciężkie ≥400 px (mediana cięć prostokątów
2833 px, w maskach 62 px — próg w pustej strefie), strzęp ≥60 px, etykieta bez obiektu.
Liczby: prostokąty ig4 7/7 odrzucone, śr. 4,1 ciężkich, 14 % tuszu w szkielecie; maski
(kod bieżący) 7/21 odrzuconych, 0,0 cięć, 1,2 % w szkielecie; B pikselowo 3/19 odrzuceń
przy 0 wywołań wizji; A szablon bez LLM: M1 7,2/2,4 % vs codex 15,2/10,4 %.
WSZYSTKIE odrzucenia w trybie maski = M4 (etykieta rozcięta / etykieta-region przed
obiektem) → do naprawy w regiony.py (B). Bug: `--schemat` przesuwa nazwy slotów o 1
(porównanie norm vs surowe) → B. Sędzia nie łapie: etykiet nieczytelnych dla OCR,
semantyki, kolejności regionów, obrazu-jednej-składowej, CSS w przeglądarce.
REKOMENDACJA (do wdrożenia po zamknięciu labu): bramka w `infografika.mjs --regiony`
po `regiony.py` → sędzia: CZYSTY/UWAGI (≤6 lekkich) = warstwy; ODRZUCONY = obraz w całości
jednym opem + flaga; tylko maski.

## 30. PAUZA labu na kwotę 5 h (2026-09-02, ~09:00)

Zatrzymani na polecenie usera: agent A (rejestr presetów + prompt bez LLM; ma 7 obrazów w
`przebiegi/_lab-wycinki/A/`, galerię `www/lab_wycinki_A.html`, `fabryka/pilot/prompt_szablon.py`,
geometrię v2 w `schematy.py`; w toku: porównanie codex v3 i preset `wolny`, raport NIE napisany)
i agent B (cięcie pikselowe; iteracja 1 w `_lab-wycinki/B/`, edycje `regiony.py` — bug nazw
slotów `--schemat` i scalanie linii bazowej napisu do zrobienia, raport NIE napisany).
C zakończony (§29). Nic nie biegnie: brak masówek, sloty `.sloty_ig` puste.
WZNOWIENIE (po resecie kwoty): w tej samej sesji — SendMessage do agentów po ich id
(kontekst zachowany); w nowej sesji — nowy agent per lab z briefem
`przebiegi/_lab-wycinki/BRIEF_WSPOLNY.md` + własnym briefem z §27–§29 i poleceniem „dokończ
na podstawie stanu katalogu, oceń sędzią C (`C/bieg.py zewn` + `tabela`), napisz raport".
Po raportach A/B: bramka sędziego w `infografika.mjs --regiony` (§29) i decyzja o presetach.
