Commit Graph

11 Commits

Author SHA1 Message Date
gitea 8cc329ab17 feat(prezentacja): zapamiętane predykcje okresowe (PRE-22) + wymaganie o cache-bustingu
build / build (push) Successful in 1m4s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 12m9s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Failing after 1m6s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 38s
Testy / Kontrola składni wszystkich warstw (push) Successful in 20s
Piata wskazowka partnerow: Kalendarz ma pozwalac liczyc predykcje dla KILKU
okresow i je zachowywac, zeby wszystkie trafily potem do raportu („Skompiluj",
PRE-23/24).

Nowy predictions.js — magazyn w localStorage, tak jak wspolne dane formularza
(PRE-21): serwer zostaje bezstanowy, zadne dane urodzeniowe ani tresci z baz nie
laduja po stronie uslugi. Zakladka „Skompiluj" odczyta to samo miejsce przez
window.astrololoPredictions (jedno zrodlo prawdy).

Decyzje projektowe:

- KLUCZEM TOZSAMOSCI JEST OKRES. Ponowne policzenie tego samego zakresu podmienia
  wpis zamiast dokladac duplikat — inaczej lista puchlaby przy kazdej probie
  z innym modelem albo budzetem. Dzieki temu zapis jest idempotentny, wiec dziala
  tez wariant bez strumienia (zapis przy wczytaniu strony z gotowym wynikiem)
  i odswiezenie niczego nie mnozy.
- progress.js OGLASZA gotowy horoskop zdarzeniem `astrololo:horoscope` z profilem,
  zamiast sam zapisywac. To okno postepu, a nie magazyn — zapisywanie zostaje
  odpowiedzialnoscia predictions.js. Filtr po profilu pilnuje, zeby interpretacja
  natalna nie trafila na liste predykcji okresowych.
- Przepelniony magazyn (horoskopy bywaja dlugie) jest ZGLASZANY uzytkownikowi,
  a nie polykany — inaczej wynik znikalby po cichu.

UI: lista zapamietanych predykcji na Kalendarzu — okres, data zapisu, objetosc
i przycisk usuwania. Skrypt podpiety w timeline.html (nie w base.html), zeby nie
kolidowac z rownolegle otwartym #29.

PRE-26 — dopisane wymaganie o wersjonowaniu plikow statycznych. Przy PRE-25
przegladarka podala STARY styles.css i powiekszanie kosmogramu „nie dzialalo",
mimo ze klasa byla nakladana. Objaw jest zdradliwy: szablony sa nowe, wiec strona
wyglada na zaktualizowana, a funkcja po prostu milczy. Po wdrozeniu moze to
spotkac uzytkownikow.

Weryfikacja na zywej aplikacji: dwa okresy zapisane; powtorzenie tego samego
zakresu podmienilo wpis (dalej 2, tekst zaktualizowany); lista posortowana po
dacie; predykcje przetrwaly przejscie na inna zakladke i powrot; interpretacja
natalna NIE wpadla na liste; usuwanie zmniejszylo licznik 2 -> 1 i przerysowalo
liste. Testy: 14 nowych. Calosc: prezentacja 101 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:57:24 +02:00
gitea 76fbdefeaa feat(prezentacja): kliknięcie powiększa kosmogram na pełne okno (PRE-25)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 11m52s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m57s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 46s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 19s
build / build (push) Successful in 1m10s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m59s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m50s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 42s
Testy / Kontrola składni wszystkich warstw (push) Successful in 19s
Ósma wskazówka partnerów, jako małe QoL przed PRE-22. Koło rysujemy w kolumnie
tekstu, więc na mniejszym ekranie glify i stopnie robią się nieczytelne.
Kliknięcie rozciąga wykres na całe okno, ponowne wraca do strony. SVG skaluje
się bez utraty jakości, więc nie potrzeba drugiej wersji rysunku ani biblioteki.

Wyjście z powiększenia na trzy sposoby: klik w wykres, klik w tło, Esc.
Dostępne też z klawiatury (Enter/Spacja, focus-visible), bo inaczej obejrzenie
szczegółów wymagałoby myszy.

Dwie decyzje warte odnotowania:

1. WARSTWA. z-index 1100 CELOWO pomiędzy: ponad kontrolkami Leafleta (1000),
   ale PONIŻEJ okna postępu (1200). Gdy trwa pisanie horoskopu, log operacji ma
   zostać na wierzchu. Test pilnuje tej nierówności, bo to jedyna liczba tutaj,
   którą łatwo zmienić bez zastanowienia i zepsuć coś niewidocznego na oko.

2. ROZMIAR. Koło jest kwadratowe, więc ograniczamy je KRÓTSZYM bokiem okna
   (min(96vw, 92vh)) — inaczej na szerokim ekranie wystawałoby w pionie.

Skrypt podpięty globalnie w base.html i osłonięty sprawdzeniem, czy koło w ogóle
jest na stronie — zadziała też na przyszłej zakładce „Skompiluj" bez zmian.
Przy powiększeniu blokujemy przewijanie strony pod spodem.

Weryfikacja na żywej aplikacji, pomiarami w DOM: po kliknięciu .wheel-fig ma
position:fixed, display:flex, z-index:1100; SVG rośnie z 460×460 do 662×653
przy oknie 1280×720, visibility visible; body dostaje overflow:hidden. Ponowne
kliknięcie wraca do 460×460 i zdejmuje klasę. Zrzutu ekranu stanu powiększonego
NIE mam — panel przeglądarki zaciął się w trakcie (puste klatki, viewport
raportowany jako 0×0), więc opieram się na pomiarach i testach.

Testy: 10 nowych. Całość: prezentacja 87 passed, logika 265 / 1 skip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:22:48 +02:00
gitea f34016a4a5 feat(prezentacja): wspolne dane formularza miedzy zakladkami + imie i nazwisko (PRE-21)
build / build (push) Successful in 58s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m4s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m53s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 38s
Testy / Kontrola składni wszystkich warstw (push) Successful in 25s
Trzecia wskazowka partnerow. Kazda zakladke (Horoskop / Interpretacje /
Kalendarz) wypelnialo sie od nowa — te same imie, data, godzina, strefa
i miejsce. Teraz raz wpisane dane wedruja za uzytkownikiem, a zmiana w jednej
zakladce przenosi sie na pozostale.

Nowy formsync.js trzyma stan w localStorage. Dlaczego nie sesja na serwerze:
serwer zostaje BEZSTANOWY — zadnego magazynu sesji, zadnych danych urodzeniowych
trzymanych po stronie uslugi (spojne z postawa z LOG-32/PRE-16). Przy okazji
dane synchronizuja sie tez miedzy osobnymi kartami przegladarki, bo zdarzenie
`storage` daje to za darmo.

Dolozone pole „imie i nazwisko" (wszystkie trzy zakladki) — potrzebne do
naglowka raportu PDF (PRE-24). Handlery przyjmuja je i oddaja, wiec nie znika
po przeliczeniu.

Dwie rzeczy, ktore trzeba bylo domknac, zeby to dzialalo naprawde:

1. KOLEJNOSC SKRYPTOW. formsync.js ladowany w <head> z `defer` — skrypty defer
   wykonuja sie w kolejnosci dokumentu, wiec ten zdazy odtworzyc wspolrzedne,
   ZANIM geo.js zbuduje mape. Mapa startuje od razu we wlasciwym miejscu,
   zamiast przeskakiwac po chwili.

2. geo.js ustawia pola z KODU (`.value = ...`), co samo z siebie NIE wywoluje
   zdarzen — bez tego synchronizacja przegapilaby kazdy wybor z mapy, z
   wyszukiwarki i z „Tu i teraz". Dolozony setVal(), ktory jawnie zglasza
   `change`.

Zakladka bez danego pola (np. Sygnifikatory) nie kasuje wartosci zapamietanej
gdzie indziej; uszkodzony wpis w localStorage nie blokuje formularza.

Q-14 rozstrzygniete: lancuch LaTeX->PDF stanie jako OSOBNA USLUGA render —
spojne z izolacja swisseph (LOG-27), obraz produktu zostaje maly.

Weryfikacja na zywym stacku (data+logika+prezentacja) w przegladarce: dane
wpisane w Horoskopie pojawily sie w Interpretacjach; zmiana godziny w
Interpretacjach dotarla do Kalendarza; pola nieobecne na zakladce (zodiak,
system domow) przetrwaly; po POST imie zostalo, a horoskop policzyl sie
normalnie. Testy: 22 nowe strukturalne. Calosc: prezentacja 67 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 15:12:49 +00:00
gitea 5c82e8bd9f fix(prezentacja): offset wzgledem GMT + nazwa lokalizacji po „Tu i teraz”
Dwie pierwsze wskazowki od partnerow biznesowych; pozostale piec zapisane jako
wymagania (PRE-21..PRE-24) do zrobienia w kolejnych krokach.

PRE-19 — offset wzgledem GMT. Etykieta mowila „Strefa (offset h)”, czyli nie
bylo jasne, wzgledem czego liczymy przesuniecie. Teraz „Offset wzgledem GMT (h)”
z podpowiedzia. Krok juz byl 15-minutowy (0,25 h) — dolozony zakres −12…+14,
zeby nie dalo sie wpisac strefy, ktora nie istnieje. Zmiana w trzech zakladkach,
ktore maja to pole (Horoskop, Interpretacje, Kalendarz).

PRE-20 — po „Tu i teraz” wspolrzedne i pineska skakaly na biezace polozenie, ale
w polu tekstowym zostawala STARA, wczesniej wpisana nazwa. Formularz pokazywal
jedno miejsce, a liczyl dla innego — cicha pomylka, nic sie nie wywalalo.
Handler zdarzenia astrololo:coords odswieza teraz nazwe przez reverseName.

Przy okazji druga strona tego samego bledu: reverseName czysci pole ZANIM
wysle zapytanie. Gdyby /reverse nie odpowiedzialo (brak sieci), zostalaby stara
nazwa — lepiej puste pole i poprawne wspolrzedne niz nazwa, ktora klamie.

Wymagania: PRE-19/20 (zrobione), PRE-21 wspolne dane miedzy zakladkami wraz
z polem imie i nazwisko, PRE-22 wiele predykcji okresowych w pamieci sesji,
PRE-23 zakladka „Skompiluj”, PRE-24 raport PDF przez LaTeX. Dolozone pytanie
otwarte Q-14 o lancuch LaTeX→PDF (gdzie postawic TeX Live, silnik unicode owy
pod glify, konwersja SVG) — decyzja wplywa na deploy i rozmiar obrazow.

Testy: 12 nowych, strukturalnych na zrodle (JS-a nie uruchomimy, a obie regresje
sa ciche). Sprawdzone sabotazem — po cofnieciu kazdej poprawki czerwienieja.
Calosc: prezentacja 45 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 15:12:49 +00:00
gitea 40c9bf7988 feat(prezentacja): obiekty na kosmogramie — glify, stopnie, retrogradacja (PRE-12)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 11m57s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m55s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 38s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 27s
build / build (push) Successful in 1m4s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m46s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m54s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 33s
Testy / Kontrola składni wszystkich warstw (push) Successful in 25s
Etap 2 rysowania koła (po szkielecie): obiekty na swoich pozycjach.

Każdy obiekt dostaje: kreske na wewnetrznej krawedzi pasa w PRAWDZIWEJ pozycji,
glif, stopien w znaku i znacznik retrogradacji ℞ (dodatkowo kolorem, zeby dalo
sie ja wylapac nie czytajac znak po znaku).

ROZSUWANIE CIASNYCH SKUPISK — sedno tego etapu. W horoskopie referencyjnym
Merkury i Wenus dzieli 0,41°, Wenus i Ksiezyc 3,68°: bez rozsuwania glify
rysuja sie jeden na drugim. Rozsuwamy tylko GLIFY; kreska zostaje w prawdziwej
pozycji, a gdy glif jest odsuniety, laczymy je cienka linia odniesienia — wykres
nie moze klamac o tym, gdzie planeta faktycznie stoi.

Bledy zlapane przy weryfikacji (oba wyszly z pomiarow, nie z „wyglada dobrze"):

1. PODPISY STOPNI zlewaly sie w skupiskach. O ciasnocie decyduje nie glif, tylko
   podpis — lezy blizej srodka (r=130), gdzie ten sam kat to mniej pikseli.
   Stad odstep 8° zamiast 7°, podpis bez „°" (jak w programach astrologicznych)
   i mniejszy font. Teraz: glify min 20,9 px, podpisy 18,1 px (prog 16).

2. ROZSUWANIE NIE DZIALALO na prawdziwych danych — Wenus ladowala DOKLADNIE na
   Ksiezycu (0,3 px). Przyczyna: odstep liczony modulo 360. Przesuniecie, ktore
   przerzucalo obiekt ZA sasiada, dawalo luke ~359,9° zamiast ujemnej, wiec
   algorytm uznawal, ze jest luzem, i konczyl. Poprawka: rozwijamy katy do osi
   MONOTONICZNEJ, gdzie ujemna luka zostaje ujemna i zawsze sie ja wylapie.
   Test regresyjny na dokladnie tych danych; sprawdzony sabotazem (po przywroceniu
   modulo czerwienieje).

Etykiety osi (AC/DC/MC/IC) przeniesione POZA kolo — w srodku wchodzily w pierscien
obiektow i zaslanialy glify (Ksiezyc znikal pod linia MC). ViewBox 440→470, kolo
bez zmian, margines mieści etykiety.

Testy: 11 nowych (regresja rozsuwania, zachowanie kolejnosci, obiekty bez kolizji
nieruszone, zawiniecie przez 0°, awaryjny rowny rozklad, stopien w znaku,
retrogradacja, niekompletny obiekt nie wywala rysunku). Calosc: prezentacja 44,
logika 265 / 1 skip. Potwierdzone wizualnie: cale skupisko Slonce/Ksiezyc/Wenus/
Merkury czytelne i rozdzielone.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 15:49:51 +02:00
gitea 1d7f3e2136 feat(prezentacja): szkielet kosmogramu — koło horoskopowe SVG (PRE-12)
build / build (push) Successful in 1m26s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m10s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m55s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 38s
Testy / Kontrola składni wszystkich warstw (push) Successful in 25s
Pierwszy krok rysowania wykresu (PRE-12): SZKIELET koła — pierścień znaków,
podział na domy i osie. Planety i linie aspektów w kolejnych iteracjach.

Rysowane po stronie serwera jako czysty string SVG (bez zależności zewnętrznych
— spójne z CSP). Ciemny motyw, spójny z paletą aplikacji (kolory z --line,
--accent, --muted; glify znaków barwione wg żywiołu w stonowanych kolorach
czytelnych na ciemnym tle).

Geometria wg konwencji astrologicznej: Ascendent po LEWEJ, długość ekliptyczna
rośnie przeciwnie do ruchu wskazówek zegara. Punkt λ → kąt φ = 180° − (λ − Asc);
w SVG y rośnie w dół, co formuła uwzględnia. Zakotwiczenie sprawdzone testami
liczbowo: Asc po lewej, Dsc po prawej, oś pozioma; Asc+90° (II dom) na dole.

Elementy: dwa okręgi + piasta, podziałki co 5°/10°, granice znaków co 30° z
glifem w środku sektora, szprychy domów od pasa do piasty, numery domów w środku
każdego domu, osie Asc–Dsc i MC–IC wyróżnione akcentem z etykietami AC/DC/MC/IC.

Dane bierzemy WYŁĄCZNIE z wyniku /chart/positions — prezentacja nic nie liczy:
- `sign_glyphs` (pierścień 12 znaków) i glify — z LOG-22,
- `angles` z długością `decimal` — już były,
- `cusps` z `decimal` — DOŁOŻONE w tym PR (jedna linia w build_chart). Bez tego
  domy dało się narysować tylko dla whole sign; z długością cuspu działa dla
  KAŻDEGO systemu. Zweryfikowane na porphyry: cuspy poza wielokrotnościami 30°,
  szprychy odchodzą od granic znaków.

Degradacja: silnik bez osi/domów albo starszy wynik bez `decimal` w cuspach →
brak koła (pusty string), nie wyjątek.

Testy: 8 (poprawność XML, 12 glifów, 4 osie, numery domów, Asc po lewej liczbowo,
CCW, degradacja). Całość: prezentacja 33 passed, logika 265 / 1 skipped. Render
potwierdzony wizualnie na horoskopie referencyjnym (AC=Leo po lewej, MC=Aries
u góry, domy CCW).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 12:32:47 +02:00
gitea 56fdf01d7d feat(bezpieczenstwo): szyfrowanie lacz miedzy warstwami AES-256-GCM (PRE-16)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m45s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m31s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 31s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 15s
build / build (push) Successful in 4m15s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m41s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m36s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 33s
Testy / Kontrola składni wszystkich warstw (push) Successful in 15s
Warstwy rozmawialy ze soba jawnym tekstem wewnatrz klastra. Token
miedzywarstwowy (LOG-32) mowil KTO pyta, ale nie ukrywal CZEGO dotyczy
odpowiedz — a plyna nia surowe wiersze oryginalnych baz interpretacyjnych,
czyli rdzen produktu. Kto podsluchal ruch wewnatrz sieci (drugi pod, mirror
portu na switchu, zrzut z wezla), mial je w calosci.

Nowy modul link_crypto (kopia w kazdej z trzech uslug — nie maja wspolnej
biblioteki; test pilnuje, ze kopie sa identyczne):
- AES-256-GCM na ciele kazdego zadania i odpowiedzi. GCM daje poufnosc I
  uwierzytelnienie naraz, wiec nie ma wariantu „zaszyfrowane, ale podatne na
  modyfikacje".
- DWA niezalezne klucze, po jednym na pare rozmowcow (prezentacja-logika,
  logika-dane). Przejecie klucza prezentacji nie otwiera warstwy danych, gdzie
  leza cale bazy. Z kazdego klucza lacza HKDF wyprowadza osobne podklucze na
  kierunek, wiec zadanie i odpowiedz nigdy nie szyfruja sie tym samym kluczem.
- Do materialu uwierzytelnianego (AAD) wchodza kierunek, sciezka, znacznik
  czasu i numer ramki — wiec ramki nie da sie przekleic na inny endpoint,
  odtworzyc po czasie (okno MAX_SKEW) ani przestawic w strumieniu.
- Strona serwerowa to czyste ASGI: podmienia cialo zanim zobaczy je FastAPI
  i przepuszcza odpowiedz strumieniowa kawalek po kawalku (okno postepu dziala
  dalej). Fail-closed: przy ustawionym kluczu jawne zadanie dostaje odmowe.

Strumien postepu (okno pisania horoskopu) tez idzie przez szyfrowane lacze:
link_crypto.stream_lines() pieczetuje zadanie i odszyfrowuje odpowiedz ramka
po ramce (granice ramek != granice linii NDJSON), zachowujac dostarczanie na
zywo. Bez tego przy wlaczonym LINK_ENCRYPTION_REQUIRED serwer odrzucalby
strumien (400) i okno postepu przestaloby dzialac. Fail-closed obejmuje takze
strumien: klient bez klucza nie wysyla nic, zamiast puscic dane urodzenia
jawnym tekstem, zanim serwer zdazy odmowic.

Najgrozniejszy blad wyszedl z PODSLUCHU prawdziwego gniazda, nie z testow:
klient bez klucza wysylal pytanie jawnym tekstem, ZANIM serwer zdazyl odmowic.
Stad LINK_ENCRYPTION_REQUIRED: klient nie wysyla niczego, a usluga nie wstaje,
jesli klucza brak. Ta sama zasada co przy sekrecie logowania.

Klient prezentacji przepuszczony przez jeden punkt _post()/stream_lines: dopoki
kazda metoda skladala zadanie sama, dolozenie nowej znaczylo, ze latwo zapomniec
o tokenie albo kluczu (401 wyszedl juz raz dopiero na produkcji). Test
strukturalny: kazde wyjscie w dol musi miec i token, i klucz lacza (takze
strumien), a surowe httpx wolno tylko na sciezkach wyjetych spod szyfrowania.

Weryfikacja:
- testy link_crypto (round-trip, brak tresci baz w bajtach na sieci, odrzucenie
  obcego klucza / przestawionego bitu / przekleconej sciezki / przestawionej
  ramki / przeterminowanej koperty / urwanego strumienia; round-trip strumienia
  i fail-closed klienta i serwera dla strumienia),
- e2e na prawdziwym uvicornie z proxy zrzucajacym gniazdo: tresci baz brak na
  kablu w obie strony (grep=0), takze dla strumienia horoskopu; klucz jednej
  pary nie otwiera drugiej,
- calosc: logika 234 passed / 1 skipped, prezentacja 25 passed.

docs/wdrozenie-pre16.md: instrukcja krok po kroku z uzasadnieniem kolejnosci.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 17:06:11 +02:00
gitea 23416cb1f9 fix(prezentacja): limit zadan po adresie klienta, nie proxy (PRE-16)
Po wlaczeniu TLS aplikacja stanie za Ingressem, a wtedy `request.client.host`
to adres POD-a Traefika — jednakowy dla wszystkich. Limiter wrzucalby caly ruch
do jednego wiadra 120/min i pierwsza osoba, ktora go wyklika, odcielaby
pozostalych. Cicha regresja, ktora ujawnilaby sie dopiero na produkcji.

Nowe `client_ip()` czyta adres z naglowka, ale WYLACZNIE przy TRUST_PROXY —
bo inaczej wystarczyloby dopisywac wlasny X-Forwarded-For, zeby przy kazdym
zadaniu wygladac na kogos innego i ominac limit calkowicie. Z tego samego
powodu bierzemy OSTATNI wpis listy: to jedyny, ktory dopisal nasz proxy;
wczesniejsze mogl podstawic klient, wiec nie znacza nic.

Szesc testow, w tym dwa istotne:
- podszycie sie pod X-Forwarded-For NIE resetuje wiadra przy wylaczonym
  TRUST_PROXY (inaczej baze dalo by sie pompowac bez ograniczen),
- za proxy dwa rozne adresy dostaja osobne wiadra i nie odcinaja sie nawzajem.

Oba sprawdzone celowym zepsuciem implementacji (zawsze ufaj naglowkowi +
bierz pierwszy wpis) — testy wtedy czerwienieja. 23 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 16:58:28 +02:00
gitea 163ace4283 feat(ui): interaktywny wybor modelu u dostawcy
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 11m14s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 10m19s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 46s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 27s
build / build (push) Successful in 1m18s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m45s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 10m2s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 36s
Testy / Kontrola składni wszystkich warstw (push) Successful in 23s
Uzytkownik wybiera nie tylko dostawce, ale konkretny model — Fable czy Opus
u Anthropica, gpt-4o-mini czy gpt-5 u OpenAI, cokolwiek ma pobrane lokalnie.

- app/llm/catalog.py: podpowiedzi modeli per dostawca wraz z oknem kontekstu,
  nadpisywalne przez <DOSTAWCA>_MODELS; GET /llm/models wystawia je dla UI.
- Pole modelu w UI jest TEKSTOWE z datalista, nie zamknietym <select> — konto
  moze miec dostep do modeli, o ktorych kod nie wie, a nowe wychodza szybciej,
  niz aktualizuje sie katalog. Puste pole = model domyslny dostawcy.
- static/models.js: zmiana dostawcy przelacza podpowiedzi, podmienia placeholder
  na model domyslny i pokazuje okno kontekstu wybranego modelu.
- build_provider(name, model) — model z zadania wygrywa nad konfiguracja.

WAZNE (znalezione przy tescie e2e): liczenie budzetu „maksymalny kontekst modelu"
szlo przez build_provider(), ktory WYMAGA klucza API — bez klucza budzet cicho
spadal do wartosci zapasowej i byl identyczny dla wszystkich modeli Anthropic.
Budzet zalezy wylacznie od okna kontekstu, wiec doszlo resolve_model(), ktore
rozwiazuje nazwe modelu bez budowania dostawcy. Teraz budzet realnie sie rozni:
Opus/Fable 3,48 mln znakow, Haiku 536 tys., gpt-4o-mini 438 tys., llama3.1 8 tys.

Pewnosc danych w katalogu: modele Anthropic pochodza z oficjalnej dokumentacji
API (okna i limity zgodne z limits.py); modele OpenAI to podpowiedzi, ktorych
nie weryfikowalem; lokalne zaleza od tego, co masz pobrane.

Testy: 174 passed / 1 skipped (logika) + 17 (prezentacja). Nowy test strukturalny
pilnuje, ze KAZDE wywolanie w dol niesie wybrany model i dostawce — dokladnie ta
klasa bledu zlapala brakujacy parametr przy horoskopie okresowym.
Zweryfikowane w przegladarce: przelaczanie dostawcy podmienia liste modeli.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 21:40:19 +02:00
gitea 64d1afc76d fix(presentation): brakujacy token przy /chart/prompt i /chart/horoscope
build / build (push) Successful in 59s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m57s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m52s
Testy / Build obrazu silnika B (swisseph) (push) Failing after 30s
Testy / Kontrola składni wszystkich warstw (push) Successful in 18s
Blad z mergu: _auth_headers() dodano na galezi hardeningu, ktora odbila sie
od mastera ZANIM powstaly metody prompt() i horoscope() (LOG-29/30, LOG-31).
Git zmergowal obie zmiany czysto — byly w roznych liniach — ale semantycznie
nowe metody wyszly bez tokenu i dostawaly 401 przy wlaczonej ochronie.

Skutek dla uzytkownika: przyciski „Generuj prompt (AI)" i „Napisz horoskop"
nie dzialaly po wdrozeniu INTERNAL_TOKEN, mimo ze reszta aplikacji dzialala.

- naprawione oba wywolania,
- nowy test strukturalny (AST): KAZDE wyjscie HTTP w dol musi niesc headers=.
  Test jednej metody by tego nie zlapal — regula musi byc pilnowana calosciowo.

Straznik zweryfikowany sabotazem: po usunieciu naglowka test pada ze
wskazaniem konkretnej linii; po przywroceniu 15/15 przechodzi.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 19:02:40 +00:00
gitea 752f477a27 feat(security): zamkniecie dostepu do baz interpretacyjnych (LOG-32)
build / build (push) Successful in 1m16s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m9s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m51s
Testy / Build obrazu silnika B (swisseph) (push) Failing after 26s
Testy / Kontrola składni wszystkich warstw (push) Successful in 22s
Bazy sa rdzeniem produktu i wlasnie zostaly kupione — a aplikacja nie miala
ZADNEGO uwierzytelniania. Prezentacja to NodePort, wiec kazdy w LAN wchodzil
bez logowania, a `/search` oddawal surowe wiersze do 50 000 na zapytanie.
Bazy mogly wyjsc przez sama aplikacje, bez udzialu jakiegokolwiek LLM.

- prezentacja: HTTP Basic (APP_USER/APP_PASSWORD) + limit zadan na IP
  (RATE_LIMIT_PER_MIN, domyslnie 120/min). Limit dziala TAKZE przed
  uwierzytelnieniem, zeby zgadywanie hasla i sondowanie API nie bylo darmowe.
- logika i dane: token miedzywarstwowy X-Astrololo-Token (INTERNAL_TOKEN) —
  bez niego dalo sie ominac logowanie, uderzajac wprost w warstwe nizej.
  Warstwa danych oddaje surowe wiersze, wiec to najwrazliwszy punkt.
- /search: gorny limit 50 000 -> 5000 (tyle realnie uzywa build_report).
  Publiczne /api/query zostaje na 200.
- /health celowo publiczny (sondy k8s go nie uwierzytelnia).
- swiadomie nie logujemy tresci zadan ani promptow — logi to kolejny nosnik.

Fail-open przy braku konfiguracji (zgodnosc wstecz i dev), ale z GLOSNYM
ostrzezeniem przy starcie, zeby nikt nie wdrozyl tego w przekonaniu, ze jest
chroniony. Wlaczenie w produkcji wymaga ustawienia sekretow w repo deploy.

Testy: 12 (prezentacja, nowy katalog + job w CI) i 5 (logika). Zweryfikowane
na zywym stosie: bez hasla 401, z haslem 200, logika wprost bez tokenu 401,
z tokenem 200, /health 200, limit 50000 odrzucony (422), a prezentacja nadal
liczy horoskop przez logike.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 16:50:18 +00:00