Skip to content

Releases: mtsle/ai-faq-generator

AI FAQ Generator 1.1.0

Choose a tag to compare

@mtsle mtsle released this 09 Sep 19:00

Wydanie po zamkniętym audycie wieloagentowym. Naprawione wszystkie znalezione błędy.

Co się zmieniło dla właściciela witryny

  • Dziennik pytań przestał gubić najnowsze wpisy. Sprzątanie starych rekordów liczyło granicę po numerze wpisu, a nie po dacie, więc przy włączonej retencji potrafiło usunąć wpisy nowsze zamiast najstarszych. To jedyna naprawiona usterka powodująca nieodwracalną utratę danych.
  • Aktualizacja bazy jest bezpieczniejsza. Numer wersji struktury rośnie dopiero po udanej migracji. Wcześniej przerwana migracja zostawiała wtyczkę w stanie, w którym uważała się za zaktualizowaną.
  • Odinstalowanie sprząta całą sieć witryn. Na instalacji wielowitrynowej dane były usuwane tylko z tej witryny, w której akurat trwało odinstalowywanie.
  • Uszczelnione bramki uprawnień, limity i obsługa błędów w wielu miejscach.

Dla informatyka

Runner testów: 62 zestawy, 0 niezaliczonych. Każda naprawa ma strażnika w testach oraz dowód, że po jej cofnięciu ten strażnik czerwienieje.

Opis audytu i pełna lista napraw: katalog audyt/.

Załącznik ai-faq-generator.zip to gotowa paczka instalacyjna (103 pliki), bez testów i dokumentacji źródłowej.

AI News Portal 1.1.0

Choose a tag to compare

@mtsle mtsle released this 09 Sep 19:01

Wydanie po zamkniętym audycie wieloagentowym. Naprawione wszystkie znalezione błędy.

Co się zmieniło dla właściciela witryny

  • Wtyczka wie teraz, w jakiej wersji ma bazę. Nie miała tego wcale: po zmianie struktury tabel nie istniała żadna ścieżka aktualizacji. Wersja rośnie dopiero po przebudowie potwierdzonej odczytem z bazy.
  • Limit długości materiału obowiązuje bezwzględnie. Wcześniej kilka ścieżek awaryjnych omijało sufit 20 000 znaków i do modelu trafiał materiał dowolnej wielkości.
  • Odstęp między zapytaniami do tego samego serwera. Nie istniał w produkcie. Wtyczka przestaje uderzać w jedno źródło kilka razy pod rząd.
  • Odinstalowanie sprząta całą sieć witryn, a nie tylko bieżącą.
  • Lista artykułów przestała czytać dysk cztery razy na każdą kartę. Koszt rósł liniowo z liczbą kart; teraz pierwsza karta wykonuje trzy odczyty, a kolejne zero.

Dla informatyka

Runner testów: 29 zestawów, 2306 asercji, liczonych co do jednej. Każda naprawa ma strażnika w testach oraz dowód, że po jej cofnięciu ten strażnik czerwienieje.

Opis audytu i pełna lista napraw: katalog audyt/.

Załącznik ai-news-portal.zip to gotowa paczka instalacyjna (45 plików), bez testów i dokumentacji źródłowej.

AI News Portal 1.0.0 — Domknięcie

Choose a tag to compare

@mtsle mtsle released this 23 Aug 14:55

Krok 8 z 8 — ostatni. Wtyczka jest ukończona: audyt całości przeszedł, dokumentacja mówi to samo co kod, paczka dla klienta stoi na pulpicie.

Co weszło w Kroku 8 (Domknięcie)

Etapy 8.1–8.3: naprawa zamka zdejmowanego bezwarunkowo, wydzielenie ekranów kokpitu do traitu, RWA (kontrast 4,63:1, cele dotykowe 24 px) — oraz naprawa runnera testów, który od Kroku 7 stawiał ✓ przy zerze wykonanych asercji. Kryterium od tamtej pory: liczba asercji === N, nie kod wyjścia.

Etapy 8.4–8.6, 8.9: dokumentacja klienta w repo (5 PDF, 4 schematy z jednego opisu .drawio+.svg), README.md i readme.txt pilnowane testem zderzającym każdą liczbę z kodem, odchudzenie instrukcji 30 MB → 8,5 MB bez utraty treści, sufity wagi w audycie PDF.

Etapy 8.7–8.8: przepustowość (sufit materiału 12 000 znaków, własny budżet przycisku „Opublikuj teraz") i trzy warianty zdjęcia na kategorię.

Etap 8.10 — audyt końcowy. Przegląd całego kodu według dziewięciu osi, trzej niezależni krytycy-obalacze, 10/10 mutacji zabitych, odbiór na żywym WordPressie. Naprawy z audytu:

co dlaczego
Zapis Ustawień nie dubluje harmonogramu wp_get_scheduled_event() oddaje zdarzenie najbliższe, więc pojedynczy przebieg „na już" przesłaniał harmonogram i każdy zapis dokładał kolejny tick — podwajając zużycie dobowej puli AI. Teraz sprawdzana jest cała tablica zaplanowanych zdarzeń
Pusta odpowiedź modelu kończy sprawę Była ponawiana w nieskończoność: ta sama pozycja paliła slot na każdym przebiegu i blokowała kolejkę. Teraz: jedno ponowienie, po drugiej pustej próbie status „nieudany"
Budżet przebiegu 20 s → 25 s Ten sam ładunek potrafił liczyć się 9,74 s albo 20,58 s (wariancja myślenia modelu) — poprawna odpowiedź przepalała slot. Odbiór na żywo potwierdził: publikacja zajęła 21,9 s
Dokumentacja uzgodniona z kodem Tabela awarii mówiła „timeout → nieudany", a kod zostawia pozycję w kolejce; poprawione też uprawnienia ról i powody pominięcia

Werdykt krytyka bezpieczeństwa: oś bezpieczeństwa i odinstalowanie czyste — próba obalenia się nie powiodła. Odinstalowanie zweryfikowane na żywym WordPressie: zero śladu w ośmiu kontrolach (opcje, transienty, tabela, wpisy, metadane, terminy, cron).

Stan końcowy

  • Runner: 2083 asercje, 15 segmentów, 29 zestawów, komplet zielony.
  • Audyt PDF: 20/20 stałych kodu zacytowanych zgodnie, sufity wagi dotrzymane.
  • Paczka: ZIP z białej listy (45 plików) + 5 PDF instrukcji, wersja podstawiana z nagłówka wtyczki — dokumenty nie mogą skłamać numeru.

🤖 Generated with Claude Code

AI News Portal 0.7.0 — Zabezpieczenia wtyczki

Choose a tag to compare

@mtsle mtsle released this 16 Aug 16:12

Krok 7 z 8. Wtyczka wysyła własne nagłówki bezpieczeństwa — ale tylko tam, gdzie nikt ich jeszcze nie ustawił.

Nagłówki bezpieczeństwa

Do tej pory wtyczka nie wysyłała ani jednego nagłówka: wszystko, co widać było w odpowiedzi na poligonie, pochodziło z motywu. Na motywie bez własnej polityki — a to większość motywów — strony Centrum Wiedzy szły bez żadnej ochrony.

Nowa klasa Security na template_redirect z priorytetem 0. Obejmuje także kanał RSS i ramkę oEmbed, a kokpitu nie dotyka, bo ten hook w wp-admin nie chodzi. Trzy widoki traktowane osobno i świadomie:

widok co dostaje
strona Referrer-Policy, X-Content-Type-Options, X-Frame-Options, Permissions-Policy, CSP frame-ancestors 'self'
embed to samo bez X-Frame-Options i bez CSP — ramka oEmbed ma się dać osadzić
feed tylko nosniff i Referrer-Policy — reszta dla XML-a nic nie znaczy

Zasada: uzupełniamy, nigdy nie nadpisujemy. Nagłówek już obecny zostaje nietknięty, a wysyłka idzie z replace = false, bo nagłówków dokładanych przez serwer WWW headers_list() nie pokazuje.

Pełnego CSP wtyczka nie narzuca. Front renderuje motyw klienta: polityka bez 'unsafe-inline' zabija typowy motyw, a z nim daje bezpieczeństwo pozorne. Gdy motyw ma własne CSP z frame-ancestors, wtyczka milczy także o ramkach; gdy ma CSP bez frame-ancestors — zostawia X-Frame-Options i zatyka dziurę.

Dwie ścieżki wyłączenia: filtr ainp_security_headers oraz stała AINP_NO_SECURITY_HEADERS w wp-config.php.

Materiał z cudzej strony

Ogrodzenie promptu chroniło dotąd wyłącznie treść. Tytuł i adres źródła szły do modelu surowe i poza ogrodzeniem — czyli tam, gdzie widzi on nasze instrukcje. Wystarczyło opublikować w obserwowanym kanale wpis o tytule ze znacznikiem zamykającym. Teraz wszystkie trzy pola przechodzą przez czyszczenie nieczułe na wielkość liter, z sufitami długości.

Pierwsza rezerwacja slotu AI

Szła przez add_option(), a ta funkcja robi INSERT ... ON DUPLICATE KEY UPDATE — przy kolizji nadpisuje cudzy wiersz i mimo to zwraca prawdę. Dwa przebiegi startujące naraz zapisałyby oba „zużyto 1", a wywołania poszłyby dwa. Teraz INSERT IGNORE, tak jak zamek przebiegu od Kroku 5.

Fraza wyszukiwania

ainp_s szło wprost do zapytania bez górnej granicy, a WordPress robi z każdego słowa osobny warunek LIKE. Sufit 120 znaków, cięty po znakach, nie bajtach.

Zamknięte samym pomiarem, bez zmian w kodzie

Klucz API ma w bazie autoload = off. Opcja Ustawień nie zawiera promptu. Transport chodzi na wp_safe_remote_get we wszystkich trzech miejscach, więc rdzeń odrzuca loopback, sieć prywatną, 169.254 i porty spoza 80/443/8080.

Liczby

Runner 27/27 zestawów. Nowe zestawy Kroku 7: 70 asercji o nagłówkach, 22 o materiale wejściowym. Odbiór po HTTP na żywej instalacji: 31/31, dwa razy pod rząd, sześć ścieżek — archiwum, kategoria, artykuł, embed, feed, kokpit.

AI News Portal 0.6.0 — Centrum Wiedzy

Choose a tag to compare

@mtsle mtsle released this 09 Aug 18:54

Krok 6 z 7. Portal ma wreszcie front: artykuły, które wtyczka publikuje sama od Kroku 5, mają teraz własne, czytelne miejsce na stronie.

Co doszło

Archiwum /centrum-wiedzy/ — lista kart od najnowszych, po 10 na stronie, z paginacją numeryczną. Karta pokazuje zdjęcie kategorii, kategorię, tytuł, lead ucięty do dwóch linii i datę.

Zdjęcia kategorii jadą w paczce wtyczki — siedem plików w assets/kategorie/, po jednym na kategorię domyślną. Nic nie jest pobierane z sieci: zdjęcia ze źródłowych artykułów to cudze pliki bez zgody, a CSP motywu i tak blokowałby obce domeny. Gdy klient dopisze własną kategorię, karta rysuje kafelek z inicjałem.

Wyszukiwarka na własnym parametrze ainp_s — zwykłe ?s= porwałoby routing do search.php motywu, bo is_search() jest w hierarchii szablonów sprawdzane przed is_post_type_archive(). Przy ainp_s wynik zostaje na szablonie portalu, a adres pozostaje /centrum-wiedzy/?ainp_s=karma.

Kategorie jako prawdziwe linki do archiwów taksonomii, nie filtr JS. Pokazywane są wyłącznie te, w których coś jest.

Szablon artykułu — kolumna tekstu ok. 70 znaków, metryczka, ramka źródła z rel="nofollow noopener", powrót do archiwum.

Motyw ma pierwszeństwo. locate_template() pytany jest o nazwy szczegółowe (archive-ainp_article.php, taxonomy-ainp_topic.php, single-ainp_article.php), a fragment karty da się podmienić plikiem ai-news-portal/card.php w motywie. Arkusz wtyczki nie ustawia kroju pisma, tła ani koloru tekstu — wnosi układ i jeden akcent, żeby Centrum Wiedzy nie wyglądało jak obce ciało.

Zero JavaScriptu, jeden breakpoint. Na telefonie jedna kolumna, pole szukania na całą szerokość, cel dotyku 44 px.

Naprawione

Goły /centrum-wiedzy/kategoria/ zwracał 404 — dług z Kroku 1. Teraz 301 na archiwum.

Dowody

Runner: 25 zestawów, wszystkie zielone. Nowe zestawy Kroku 6: krok6-portal-test.php (31 asercji) i krok6-karty-test.php (90). Odbiór po HTTP na żywym dworek.local: 30/30, dwa razy pod rząd.

AI News Portal 0.5.0 — Krok 5: Automatyzacja

Choose a tag to compare

@mtsle mtsle released this 09 Aug 16:54

Portal pracuje sam. Zdarzenie ainp_tick chodzi co godzine i prowadzi trzy fazy — pobierz, przygotuj, opublikuj — pod jednym zamkiem, w budzecie czasu, ktory pilnuje, zeby przebieg nie zginal na limicie hostingu.

Co doszlo w Kroku 5

  • Harmonogram ainp_tick (hourly) zakladany przy aktywacji i domykany na init, wiec aktualizacja wtyczki nie zostawia klienta bez automatu.
  • Przejecie pozycji przez baze: new → processing → new, atomowo w klauzuli WHERE, z odzyskiem porzuconych po 15 minutach.
  • Budzet czasu dzielony na fazy, z timeoutem kazdego zadania przycinanym do tego, co zostalo. Ponizej 3 sekund zadanie nie startuje wcale — porazka po dwoch sekundach nie jest wina serwisu i nie ma prawa podbijac licznika prob.
  • Reczne wznowienie nieudanych z panelu, z licznikiem kosztu: klient widzi nie tylko ile pozycji wroci do kolejki, ale ile z nich zajmie wywolanie z dobowej puli.
  • Ekran Materialy pokazuje ostatni automatyczny przebieg jako stan, nie jako jednorazowy komunikat. Automat, ktoremu skonczyla sie pula, przestal byc nieodrozninalny od automatu, ktory nie dziala.
  • Zamek przebiegu to opcja ainp_run_lock zakladana przez INSERT IGNORE, z przejeciem po trupie przez CAS. Dawny transient ainp_prepare_lock nie istnieje.

Dowody

  • runner 23/23 zestawow, asercje Kroku 5: 163
  • seria mutacyjna kodu po naprawach poaudytowych: 44/44, proba kontrolna 0/23
  • odbior na zywej witrynie: 48/48, dwa razy pod rzad, baza niezmieniona przed i po

Uwagi

Bez migracji bazy — Krok 5 nie zmienil schematu. Wtyczka 1 (AI FAQ Generator) pozostaje zamrozona na v1.0.0.

AI News Portal v0.4.0 — Krok 4: AI i publikacja

Choose a tag to compare

@mtsle mtsle released this 07 Aug 01:11

Krok 4 z 7 domkniety. Portal przestaje byc kolekcjonerem linkow: pozycja z kanalu RSS przechodzi teraz przez model i konczy jako opublikowany artykul z kategoria.

Co doszlo

Wywolanie modelu (Gemini) — atomowa rezerwacja slotu z dobowej puli PRZED zadaniem (timeout w polowie wywolania zuzywa pule po stronie Google tak samo jak sukces), timeout dobierany do pozostalego budzetu czasu, wymuszony schemat odpowiedzi z topic jako enum.

Bramka slow wymaganych przed modelem — jedyne miejsce, przez ktore przechodzi kazda droga do Gemini. Powod jest strukturalny: odcisk tresci dziala jak znacznik "juz przetworzona", wiec kazda zmiana listy przez klienta uniewaznia wiersze przygotowane wczesniej i zaden filtr wczesniejszy juz ich nie dosiegnie. Zmierzone na zywym materiale: 9 z 34 gotowych pozycji bylo poza tematem.

Kontrakt odpowiedzi (Validator) — title 5-140, lead 20-400, tresc min. 800 znakow TEKSTU (nie HTML-a), kategoria dokladnie z listy, porownywana bez ogonkow i wielkosci liter, ale zapisywana zawsze w pisowni z Ustawien.

Publikacja (Publisher) — jeden wpis, jedna kategoria przez wp_set_object_terms() po insercie, obowiazkowy link do zrodla, idempotencja pytajaca o post_status => 'any'. Nieudane przypisanie kategorii NIE kasuje wpisu, tylko przestawia go na szkic: tresc kosztowala wywolanie z puli. Artykul demo znika po pierwszej prawdziwej publikacji, ale tylko jesli nikt go nie edytowal.

Panel — pole na klucz API (osobna opcja, bez autoladowania, nigdy nie renderowana z powrotem), edytowalny prompt z czterema znacznikami, przycisk "Opublikuj teraz" z licznikiem "Wywolan AI dzis: N z M", i natychmiastowy pierwszy przebieg po zapisaniu Ustawien.

Dowody

  • runner 19/19 zestawow, 406 nowych asercji w Kroku 4,
  • test mutacyjny 49/49 przy zielonej probie kontrolnej na kopii calego katalogu,
  • odbior na zywej instalacji 60/60, przy powtorce 57/57 — idempotentny.

Co odbior zlapal, a atrapy nie

Pierwszy prawdziwy przebieg skonczyl sie HTTP 400: Schema w Gemini nie jest pelnym JSON Schema i nieznane pole additionalProperties wywracalo cale zadanie. Naprawa poszla razem z asercja na biala liste pol schematu.

Tabela testow w planie: 20 → 22 (bramka wariantu C i bramka przed modelem).

AI News Portal v0.3.0 — Krok 3: Filtr i treść

Choose a tag to compare

@mtsle mtsle released this 06 Aug 21:47

Krok 3 z 7 domknięty. Wtyczka 2 potrafi teraz odsiać nietrafiony materiał bez jednego żądania sieciowego, dobrać pełną treść, gdy kanał podał samą zapowiedź, i rozpoznać ten sam tekst pod dwoma adresami.

Co przybyło

Filter (3.1) — słowa wykluczające z granicą słowa opisaną przez \p{L}, nie \b; remove_accents() po obu stronach porównania. Wejściem jest wyłącznie to, co przyszło w kanale, więc odrzucenie kosztuje zero żądań HTTP i zero wywołań AI.

Powód w tabeli (3.2) — pozycja odsiana trafia do bazy ze statusem skipped i czytelnym powodem w kolumnie note, widocznym na ekranie Materiały. Zapisujemy ją, zamiast pomijać: klucz UNIQUE na url_hash sprawia wtedy, że kanał nie podaje jej w kółko.

Article (3.3–3.5) — scraping, gdy treść z kanału ma mniej niż 1200 znaków gołego tekstu; ekstrakcja, która wycina to, co powtarza się na każdej podstronie, i wybiera blok z największą ilością tekstu w akapitach; wp_kses_post() przy zapisie; próg 500 znaków, poniżej którego pozycja idzie do skipped; budżet pamięci 80% limitu, sprawdzany przed żądaniem.

Odcisk treści (3.6)Runner::prepare_item() prowadzi pozycję przez filtr, scraping, canonical i odcisk treści. O kolizję pyta baza: UPDATE IGNORE na kolumnie z kluczem UNIQUE przy konflikcie nie zmienia wiersza, więc duplikat kończy jako skipped z powodem, nigdy jako błąd MySQL.

Panel — przycisk „Przygotuj treści" (partia 10 pozycji). W Kroku 5 tę samą pracę przejmie cron.

Zmierzone, nie zadeklarowane

  • runner: 11 zestawów, wszystkie zielone; 249 asercji w samym Kroku 3
  • test mutacyjny: 71 z 72 mutacji zabitych, jedna odrzucona jako równoważna z dowodem
  • odbiór na żywej instalacji: 49/49, powtarzalny; na 70 prawdziwych pozycjach 34 z gotową treścią, 36 odsianych, zero błędów MySQL, zero żądań sieciowych tam, gdzie kanał podał pełną treść

Naprawione po teście mutacyjnym

Kanał z popsutym kodowaniem przechodził filtr w całości: wyrażenie z modyfikatorem u na tekście z błędnym bajtem nie zgłasza błędu, tylko zwraca „nie ma". Dedup::valid_utf8() naprawia tekst na początku normalizacji.

AI News Portal 0.2.0 — Krok 2: Pobieranie

Choose a tag to compare

@mtsle mtsle released this 06 Aug 20:41

Drugi z siedmiu Krokow wtyczki AI News Portal. Wtyczka pobiera kanaly RSS, rozklada je na pozycje, odsiewa duplikaty i zapisuje material do wlasnej tabeli. Panel pokazuje zebrane pozycje i pozwala pobrac je recznie.

Co doszlo

  • Http — timeouty 10/15/5 s, sufity 4 MB / 1 MB / 64 KB, 3 przekierowania, wykrywanie uciecia, blankietowy robots.txt w transiencie per host (12 h). Zadania prosza o Accept-Encoding: identity, wiec sufit pamieci znaczy to samo na kazdym hostingu.
  • Feed — RSS 2.0, Atom i content:encoded; DOCTYPE odrzucany w prologu przed parsowaniem (ochrona przed bomba encyjna), bez LIBXML_NOENT.
  • Dedup — normalizacja adresu i odcisk sha256; 13 parametrow sledzacych i prefiks utm_ zdejmowane przed porownaniem.
  • Runner — polowa zbierajaca: INSERT IGNORE, wp_encode_emoji(), sufit 100 pozycji na kanal, try/catch per zrodlo i per pozycja.
  • Panel — Materialy i Ustawienia, przycisk "Pobierz teraz", cztery domyslne kanaly.

Poprawki po audycie odbiorczym

  • P1 (powazne) — limit odpowiedzi liczyl bajty przed dekompresja, a kod porownywal dlugosc po. Kompletny kanal dostawal falszywy blad, a uciety gzip wracal jako binarna siczka.
  • D1 — bramka DOCTYPE skanowala caly dokument; artykul cytujacy HTML w CDATA kasowal caly kanal.
  • D2guid isPermaLink="false" bral udzial jako adres artykulu, co grozilo druga kopia tego samego materialu.

Zmierzone, nie zadeklarowane

Runner 7/7 zestawow, 426 asercji w Kroku 2, 179/179 zabitych mutacji w siedmiu zestawach. Odbior na zywej witrynie: 40/40 — cztery prawdziwe kanaly, 70 pozycji, drugie pobranie zero nowych i 70 duplikatow, padniete zrodlo nie zatrzymalo reszty.

Wymaga: WordPress 6.5+, PHP 8.1+.

AI News Portal v0.1.0 - Krok 1: Fundament

Choose a tag to compare

@mtsle mtsle released this 05 Aug 18:55

AI News Portal v0.1.0 — Krok 1 „Fundament"

Pierwsze wydanie drugiej wtyczki z paczki dla klienta. Wtyczka instaluje się, zakłada swoją
tabelę, rejestruje typ treści i kategorie, wstawia jeden gotowy artykuł demo i dokłada dwie pozycje
w kokpicie. Nie pobiera jeszcze niczego z sieci — to zakres Kroku 2.

Co wchodzi

  • Plik główny — nagłówek GPLv2 (bez „or later"), Requires at least: 6.5, Requires PHP: 8.1,
    Tested up to: 7.0.2, stałe AINP_*, jawna lista require_once (bez autoloadera).
  • Tabela wp_ainp_itemsdbDelta, get_charset_collate(), LONGTEXT na treść i dwa
    nazwane klucze UNIQUE
    : url_hash (dedup po adresie) i content_hash (dedup po treści,
    z dozwolonym NULL).
  • Typ treści ainp_article + taksonomia ainp_topicshow_ui => true,
    show_in_menu => false, archiwum /centrum-wiedzy/, artykuły /centrum-wiedzy/tytul/,
    kategorie /centrum-wiedzy/kategoria/zywienie/.
  • Cykl życia — aktywacja rejestruje typy PRZED przeładowaniem reguł (adresy działają bez
    ręcznego zapisu Bezpośrednich odnośników), wykrywa kolizję ze Stroną o slugu centrum-wiedzy
    i ostrzega o niej w kokpicie; dezaktywacja wyrejestrowuje typy przed flushem i nie rusza danych.
  • Artykuł demo — tekst wpisany w kod, zero wywołań API, wstawiany dokładnie raz, z kategorią
    i autorem. Dzięki niemu portal nie jest pusty przez pierwsze trzy Kroki.
  • uninstall.php bez śladu — wpisy, meta, powiązania, terminy, tabela, opcje, transienty
    i crony. Dane wtyczki 1 pozostają nietknięte.
  • LICENSE — pełny tekst GPL v2 skopiowany plikowo z rdzenia WordPressa.
  • Testy — 2 zestawy, 99 asercji, własny runner run-tests-ai-news-portal.sh.

Poprawka planu, którą wymusiła żywa witryna

Plan zakładał kategorie pod /centrum-wiedzy/zywienie/, obok artykułów /centrum-wiedzy/tytul/.
W WordPressie to niewykonalne — obie struktury generują wzorzec centrum-wiedzy/([^/]+)/?$,
reguła artykułu stoi wyżej i archiwum kategorii zwracało 404. Kategorie dostały człon
kategoria, a taksonomia jest rejestrowana przed typem treści (reguła załączników CPT
przesłaniała adres kategorii). Adresy artykułów pozostały krótkie i niezależne od kategorii.

Audyt odbiorczy

0 blokerów. 6 znalezisk wagi DROBNE — wszystkie naprawione w tym wydaniu: trzy fałszywe zielenie
w testach (wykryte testem mutacyjnym na kopii kodu), artykuł demo bez autora przy aktywacji spoza
kokpitu, zadeklarowany text domain bez funkcji tłumaczeń, martwy menu_icon. Cztery długi
z przypisanymi Krokami spisane w STAN-WTYCZKA2.md.

Po naprawach: runner 2/2 zestawy, odbiór na dworek.local 39/39, 20/20 mutacji łapanych.

Następny Krok

Krok 2 „Pobieranie": Http, Feed, Dedup, zapis przez INSERT IGNORE, ekran Materiałów
z przyciskiem „Pobierz teraz".