31 Commits

Author SHA1 Message Date
gitea e7b6d5013b feat(astroklient): wersja demonstracyjna o dwóch funkcjach (PRE-28)
Osobna warstwa prezentacji: dodanie pliku bazy i zapytanie o interpretację
urodzeniową. Nic więcej.

OSOBNA USŁUGA, NIE KONTO Z OGRANICZENIAMI. Mechanizm uprawnień z PRE-27 umiałby to
ukryć w pełnej aplikacji, ale ukrycie a nieobecność to dwie różne rzeczy: tutaj
pozostałych funkcji NIE MA W OBRAZIE — nie ma tras, nie ma szablonów, nie ma nawet
metod w kliencie warstwy logicznej. Demo można komuś oddać, nie oddając przy
okazji kodu reszty programu. Test porównuje zbiór tras aplikacji i zbiór metod
klienta z listą dokładną, więc dopisanie czegokolwiek zapala się od razu.

WGRANIE I WŁĄCZENIE TO JEDNA CZYNNOŚĆ. W pełnej aplikacji to dwie osobne decyzje
(DAN-27), bo tam ktoś nad tym panuje. Tutaj „dodać plik do bazy" musi znaczyć, że
plik od razu bierze udział w wyszukiwaniu — inaczej po wgraniu nic by się nie
zmieniło i demo wyglądałoby na zepsute. Walidacja zostaje: plik o złym układzie nie
wchodzi do użytku, ale też NIE JEST tracony, a komunikat nie zdradza reguł, bo te
zna wyłącznie administrator. Osobny test szuka w komunikacie śladów mechanizmu.

KONTO OSOBNE (DEMO_USER/DEMO_PASSWORD), nie współdzielone z główną aplikacją.
Demo pracuje na TEJ SAMEJ warstwie danych co produkcja — świadoma decyzja
właściciela — więc kto ma do niego dostęp, czyta oryginalne bazy, a jego wgrania
trafiają do produkcyjnego zbioru. Własne poświadczenia pozwalają odciąć demo jedną
zmienną, bez ruszania kont głównej aplikacji i bez zmiany hasła komukolwiek.
Zapisane wprost w README usługi i w manifeście, nie tylko w tej wiadomości.

Rozmowa z warstwą logiczną idzie tym samym szyfrowanym łączem (PRE-16) i pod tym
samym tokenem międzywarstwowym (LOG-32) — demo nie jest furtką omijającą ochronę.
Automatyczna dokumentacja wyłączona, jak w pełnej aplikacji: /docs wypisałoby
komplet tras, a demo ma nie zdradzać nawet własnej powierzchni.

Zależności celowo krótsze niż w prezentacji: bez Excela, bez stref czasowych
z lokalizacji, bez niczego pod kosmogram. Każda zbędna zależność w obrazie demo to
kolejna rzecz do pilnowania.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 11:56:45 +02:00
gitea 320a0ab24e PRE-27: pełne ukrycie niedostępnych funkcji (paranoja)
build-render / build (push) Failing after 8s
build-swisseph / build (push) Successful in 9s
build / build (push) Successful in 8s
Testy / Testy warstwy logicznej (silnik) (push) Failing after 5s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Failing after 4s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Failing after 4s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 6s
Testy / Kontrola składni wszystkich warstw (push) Failing after 4s
Ukrywanie jest teraz nadrzędne wobec wygody i czytelności komunikatów.
Persona: konto z uprawnieniami files + files_input, zatrudnione wyłącznie do
wgrywania plików. Nie ma się dowiedzieć, po co je wgrywa ani co program będzie
robił — bo to rozgada.

Audyt sześciu kanałów wycieku (statyki, HTML, sondowanie HTTP, ekran plików,
odpowiedzi JSON i błędy, pozostałe warstwy) potwierdził 26 wycieków, każdy
odtworzony uruchomionym kodem i zweryfikowany adwersarialnie. Ani jeden nie był
przyciskiem.

ZASÓB JEST CZĘŚCIĄ FUNKCJI
/static/ omijało CAŁĄ bramkę (PUBLIC_PREFIXES), więc każdy skrypt i arkusz
pobierał ktokolwiek, także niezalogowany, pod zgadywalnym adresem — a ich treść
wymienia ekrany, dostawców modeli i przeznaczenie plików. Ruch ten nie trafiał
przy tym ani do dziennika, ani pod limit żądań, więc wyciek był niewidoczny.
Zasoby idą teraz trasą z bramką; każdy ma w features.STATIC uprawnienie swojego
ekranu. Publiczny został jeden base.css, bo potrzebuje go ekran logowania.

KOMENTARZ NIE JEDZIE NA DRUT
Komentarze w CSS/JS opisywały funkcje pełnymi zdaniami po polsku — łącznie
z „Wstrzymane widzi tylko administrator", czyli i mechanizmem kwarantanny,
i istnieniem konta o wyższych uprawnieniach. _asset_body() usuwa je przy
serwowaniu; w repozytorium zostają.

styles.css rozbity na base.css + arkusz na ekran + x-ai.css. Jeden plik z
wszystkimi selektorami był spisem treści programu. Podział zrobiony
mechanicznie, z osobnym sprawdzeniem, że żaden ekran nie stracił reguły.

base.html ładował skrypty kosmogramu na KAŻDEJ stronie — konto mające wyłącznie
Pliki pobierało je przy wejściu na swój jedyny ekran, razem ze wzmianką
o „przyszłej zakładce". Teraz dokłada je ekran, który ich używa.

RÓŻNICA JEST INFORMACJĄ
Komunikat po wgraniu pliku różnił się zależnie od wyniku walidacji — czyli był
wyrocznią do odgadywania reguł, które ma znać tylko administrator — i mówił
wprost, że plik „musi zatwierdzić administrator". Teraz jest jeden, ten sam.

_logic_error wypisywał na ekran nazwę trasy, nazwę podsystemu, nazwę gałęzi
rozwojowej i wewnętrzny host:port. Jedno zdanie dla wszystkich awarii, szczegóły
do dziennika. Odsiew w jednym punkcie, nie w siedemnastu wywołaniach.

Ponadto: stopka nie ogłasza architektury, /health nie nazywa warstwy, konto bez
ekranów dostaje 404 zamiast tłumaczenia, ekran plików mówi o plikach zamiast
o „bazach interpretacyjnych", klasy .house-warning i .account-card przemianowane
na neutralne, a logic/data/render/engine-swisseph nie wystawiają już /docs ani
/openapi.json i nie publikują portów na hoście.

ZAPORA SŁOWNIKOWA
test_slownik_zakazany.py nie sprawdza miejsc, tylko przechodzi wszystko, co dane
konto może pobrać, i szuka słów, które nie mają prawa paść (87 pozycji dla tej
persony). Nazwy funkcji, adresy ekranów i nazwy zasobów biorą się wprost
z katalogu, więc nowa funkcja obejmuje się sama. Kontrola pozytywna pilnuje, żeby
test nie przechodził dlatego, że program jest pusty.

Sprawdzone: zapora puszczona na treść sprzed poprawek daje 16 trafień na samym
styles.css i łapie każdy ze zneutralizowanych komunikatów. 358 testów zielonych,
ekrany obejrzane w przeglądarce.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 17:54:03 +02:00
gitea 1d0ff2f72e PRE-27: generowanie tekstu przez model znika bez uprawnienia
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m20s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m25s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 5s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 5s
build / build (push) Successful in 1m39s
Testy / Testy warstwy logicznej (silnik) (push) Failing after 4m45s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m32s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m25s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 7s
Testy / Kontrola składni wszystkich warstw (push) Successful in 6s
Wymaganie było mocniejsze niż schowanie przycisku: po niedostępnej funkcji nie
może zostać śladu w źródle strony. Największy wyciek nie był przyciskiem —
_prompt_block wstrzykiwał w stronę CAŁY katalog modeli jako JSON (dostawcy,
nazwy modeli, rozmiary okien kontekstu), na każdym ekranie z generowaniem,
niezależnie od uprawnień konta.

Druga dziura była głębsza: handlery nie sprawdzały nic. Trasa /interpret musi
być dostępna dla konta z Interpretacjami, więc granica przebiega WEWNĄTRZ niej,
po polu `action` — spreparowany formularz z action=prompt generował tekst, a
action=export pobierał arkusz, mimo że szablon chował oba przyciski.

Akcja bez uprawnienia wraca do akcji domyślnej ekranu zamiast dawać błąd:
komunikat „brak uprawnień do generowania" sam w sobie mówiłby, że taka funkcja
istnieje.

Ślady wycięte także tam, gdzie nie były kontrolką: znaczniki natalNote/
reportNatal, pliki models.js/progress.js/natal.js/predictions.js oraz podtytuł
ekranu Skompiluj, który wymieniał interpretację od AI z nazwy.

12 testów; 9 z nich pada na kodzie sprzed poprawki (sprawdzone przez cofnięcie
zmian w app/). Kontrola pozytywna pilnuje, żeby nie przechodziły dlatego, że
generowanie jest zepsute dla wszystkich.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 13:10:16 +02:00
gitea f0d07ee8c3 feat(bezpieczeństwo): sesje logowania zamiast HTTP Basic (LOG-34)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m17s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m30s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m25s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 5s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 4s
build / build (push) Successful in 7s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m18s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m25s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 6s
Testy / Kontrola składni wszystkich warstw (push) Successful in 4s
Basic nie miał wylogowania i nie dało się tego obejść: przeglądarka zapamiętuje
hasło i dosyła je SAMA przy każdym żądaniu, więc serwer nie ma czego zapomnieć.
Poprzednia próba (LOG-32) opierała się na nakłonieniu przeglądarki, żeby porzuciła
zapamiętane dane — zachowaniu powszechnym, ale nigdzie nie zapisanym. Teraz to
serwer decyduje, czy dana przeglądarka jest w środku, i może to cofnąć.

TRZY POZIOMY UNIEWAŻNIENIA, celowo rozdzielone, bo każdy kosztuje co innego:
  1. wylogowanie = skasowanie ciasteczka. Natychmiastowe, bez magazynu.
  2. zmiana hasła albo skasowanie konta = odcisk poświadczenia wpisany
     w ciasteczko przestaje pasować. Dzieje się SAMO, bez pamiętania o tym.
     Bez tego odebranie komuś dostępu nie odbierałoby dostępu aż do wygaśnięcia.
  3. „zamknij sesje" z ekranu kont = licznik pokolenia. Jedyny wymagający zapisu,
     więc jedyny opcjonalny: gdy licznika nie ma, poziomy 1 i 2 nadal działają.

KONTO ADMINISTRACYJNE ODSEPAROWANE. Sprawdzane pierwsze i BEZ DOTYKANIA pliku
kont, co daje dwie rzeczy naraz: konto z pliku o tym samym loginie nie przesłoni
administratora, a administrator zaloguje się także wtedy, gdy plik jest uszkodzony
— czyli w jedynej sytuacji, w której ktoś MUSI wejść, żeby to naprawić. Trzymanie
jego stanu w tym samym pliku dawałoby zakleszczenie: nie da się naprawić, bo nie
da się wejść. Jego odpowiednikiem „wyloguj zewsząd" jest zmiana APP_PASSWORD.

KLUCZ WYMAGANY, FAIL-CLOSED. Usługa z kontami, ale bez klucza podpisu, nie
odróżniłaby ważnej sesji od podrobionej, więc nie wstaje — i lepiej przy starcie
niż przy pierwszym logowaniu człowieka. Losowanie klucza byłoby wygodne, ale
wylogowywałoby wszystkich przy każdym restarcie poda: wygląda jak awaria i uczy
ludzi ignorować ekran logowania.

Ciasteczko HttpOnly (jeden wstrzyknięty skrypt inaczej wynosi sesję) i
SameSite=Strict (obca strona nie zadziała w imieniu zalogowanego). Wylogowanie
POST-em, nie odsyłaczem: pod adresem GET wystarczyłby obrazek na obcej stronie.
Adres powrotu po zalogowaniu przechodzi przez sito — bez tego `?dokad=https://obcy`
zamieniłby nasz ekran logowania w narzędzie do wyłudzania haseł.

Kres bezczynności 8 h i twardy 30 dni. Znacznik aktywności odświeżany z progiem,
inaczej Set-Cookie leciałby przy każdym obrazku i arkuszu stylów.

Zdarzenia logowania w dzienniku (PRE-17). Nieudane próby są tam ważniejsze od
udanych: pojedyncza nic nie znaczy, ale seria pod jednym adresem to jedyny
widoczny ślad zgadywania haseł. Test pilnuje, że hasło tam nie trafia.

Sprawdzone w przeglądarce: po zalogowaniu ciasteczko jest NIEWIDOCZNE dla
JavaScriptu, a po wylogowaniu wejście na chronioną stronę ląduje na ekranie
logowania — czyli dokładnie to, czego Basic nie potrafił.

Testy: 21 na rdzeń podpisywania (w tym podrabianie ładunku, podpisu i klucza,
ciasteczko z przyszłości, śmieci na wejściu), reszta przepisana z Basic na sesje.
Prezentacja 338 zielonych.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 00:18:15 +02:00
gitea 6466ab89a9 feat(dane): interfejs zarządzania plikami baz — trzy poziomy dostępu (DAN-27)
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m12s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m33s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 19s
Testy / Kontrola składni wszystkich warstw (push) Successful in 8s
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 12m25s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m33s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 16s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 8s
Ekran „Pliki" z trzema poziomami, wpiętymi w kontrolę dostępu z PRE-27:

  „files"        widzi listę i KLIKANIEM decyduje, z których baz program korzysta,
  „files_input"  dokłada wgrywanie i ARCHIWIZACJĘ,
  administrator  kasowanie, przywracanie z archiwum i REGUŁY WALIDACJI.

STAN JEST TERAZ TRWAŁY. DAN-15 trzymał go w zmiennej DISABLED_BASES, bo warstwa
danych nie miała gdzie zapisywać — udział był montowany read-only. Skoro stan ma
być klikany, musi przetrwać restart, więc udział jest zapisywalny, a stan leży
w pliku obok baz (zapis atomowy: plik opisuje CAŁY zbiór, więc obcięcie w połowie
skasowałoby wiedzę o wszystkich naraz). DISABLED_BASES zostaje jako awaryjne
wyłączenie z konfiguracji i odsiewa DODATKOWO — nie odwrotnie, bo inaczej ktoś
z dostępem do ekranu włączyłby bazę wyłączoną świadomie na poziomie wdrożenia.

ARCHIWIZACJA NIE KASUJE. Plik zostaje na dysku, zamrożony, ze znacznikiem czasu;
znika wyłącznie z użytku. To najdalej idąca operacja osoby wgrywającej dane —
kasować może tylko administrator. Test sprawdza, że plik po archiwizacji nadal
istnieje, bo to jest cała istota tej operacji.

WALIDACJA JEST BRAMKĄ DO UŻYTKU, NIE FILTREM NA WEJŚCIU. Plik wgrany zostaje
NIEZALEŻNIE od wyniku — nie tracimy niczego, co ktoś wgrał. Zmienia się tylko to,
czy da się go włączyć. Sprawdzenie biegnie też w chwili włączania, nie tylko przy
wgrywaniu: reguły mogą się zmienić po fakcie.

O WALIDACJI WIE TYLKO ADMINISTRATOR. Pliki wstrzymane są odsiewane W WARSTWIE
DANYCH przy for_admin=False, a nie ukrywane w szablonie — gdyby dochodziły do
przeglądarki, wystarczyłby podgląd źródła, żeby poznać reguły. Odmowa włączenia
wraca do konta bez uprawnień BEZ POWODU, bo powód zdradza regułę. Sekcja reguł
nie trafia nawet do źródła strony. Test parametryzowany po obu niższych poziomach
szuka w odpowiedzi śladów mechanizmu i wymaga, żeby żadnego nie było.

Każdy plik ma policzony sha256 — tożsamość niezależna od nazwy. Wykorzystuje ją
już odrzucanie duplikatów, a w kroku drugim posłuży do pilnowania zgodności
lustra w SQL.

Przy okazji naprawiony błąd, który dopiero co bym wprowadził: Path("") to
Path("."), czyli wartość PRAWDZIWA, więc `Path(os.getenv(...)) or domyślna`
zawsze wybierało pustą zmienną i zapisywało stan do katalogu bieżącego.

Wymaga zapisywalnego udziału — osobny PR w repo deploy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 14:39:42 +02:00
gitea a833965909 feat(bezpieczeństwo): konta z uprawnieniami do zakładek i funkcji (PRE-27)
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m58s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m32s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 3m37s
Testy / Kontrola składni wszystkich warstw (push) Successful in 9s
build / build (push) Successful in 18s
Ekran „Konta" dla administratora: zakładanie, kasowanie i nadawanie uprawnień.
Zestaw funkcji zależy od konta, a konto ograniczone widzi program KOMPLETNY —
tylko mniejszy.

PODZIAŁ NA GRUPY. Ekrany to zakładki (7), bo zakładka jest naturalną jednostką —
to ją widać w nawigacji. Rozszerzenia to POZIOMY ZŁOŻONOŚCI wewnątrz ekranów:
porównanie systemów domów, wykresy dodatkowe, obliczenia zaawansowane, generowanie
tekstu przez model (kosztuje pieniądze) i eksport plików. Konto bez porównania
domów dostaje horoskop w Whole Sign i nie wie, że systemów jest trzynaście.

NIC NIE ZDRADZA, ŻE JEST WIĘCEJ:
- brak pozycji w menu zamiast pozycji wyszarzonej,
- 404 zamiast 403 — odmowa z powodem sama mówi, że coś tam jest,
- rysunki bez uprawnienia w OGÓLE NIE POWSTAJĄ, więc nie ma ich nawet w źródle,
- automatyczna dokumentacja API wyłączona. /docs, /redoc i /openapi.json wypisują
  komplet tras, czyli spis wszystkich funkcji programu — ochrona zakładek nic by
  nie dała, gdyby obok leżał ich katalog. Znalezione TESTEM przechodzącym po
  trasach aplikacji, nie przeglądem kodu.

KONTO ADMINISTRACYJNE zostaje w APP_USER/APP_PASSWORD, jak było. Nie leży w pliku
kont, więc nie da się go skasować ani ograniczyć z ekranu. Konto założone w pliku
o tym samym loginie NIE przesłoni administracyjnego — kolejność sprawdzania jest
odwrotna, inaczej dałoby się odebrać uprawnienia jedynemu, kto może je nadawać.
Uprawnienia administracyjnego nie da się też nadać z formularza: odsiewamy je
w normalise(), a nie w handlerze, więc żadne spreparowane żądanie tam nie sięgnie.

GRANICA JEST W HANDLERZE, NIE W SZABLONIE. Ukrycie pola chroni przed przypadkiem,
nie przed kimś, kto zna nazwy pól — _limit_options() ścina opcje po stronie
serwera i test wysyła spreparowane żądanie, żeby to potwierdzić.

MAPA TRASA→UPRAWNIENIE JEST JEDNA (features.ROUTES). Rozproszenie jej po
dekoratorach kończy się trasą, o której ochronie ktoś zapomniał — a taka dziura
jest niewidoczna, dopóki ktoś jej nie znajdzie. Trasa bez wpisu wymaga
administratora: przeoczenie ma ZAMYKAĆ, nie otwierać. Test idzie po trasach
APLIKACJI, nie po wpisach mapy — inaczej potwierdzałby tylko sam siebie.

Konta w pliku JSON na własnym podkatalogu NFS (nie tam, gdzie bazy — zamontowanie
całego udziału obeszłoby bokiem DAN-25). Hasła wyłącznie jako hash scrypt, tym
samym mechanizmem co APP_USERS. Zapis atomowy, bo przerwanie zapisu na NFS
obcięłoby plik, czyli skasowało wszystkie konta naraz.

Przy okazji przepisane trzy testy, które greppowały nawigację i main.py: menu
powstaje teraz z katalogu funkcji, więc szukanie sztywnych linków w base.html
niczego już nie sprawdzało.

Wymaga wolumenu na konta — osobny PR w repo deploy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 12:18:14 +00:00
gitea 4d1daab35a feat(domy): warianty od Barana i od MC + obrót kosmogramu — LOG-05 zamknięte
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m34s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m28s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 18s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 10s
build / build (push) Successful in 26s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m37s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m33s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m27s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 17s
Testy / Kontrola składni wszystkich warstw (push) Successful in 10s
Ostatnie trzy pozycje z treści LOG-05, których wcześniej nie było:

- whole_sign_aries — znaki jako domy, ale dom I ZAWSZE na 0° Barana, niezależnie
  od Ascendentu (tradycja indyjska i część szkół hellenistycznych),
- equal_mc — równe domy zakotwiczone na MC: dom X zaczyna się dokładnie na
  południku, a nie ma go gdzieś w środku,
- obrót kosmogramu: Ascendent albo 0° Barana po lewej stronie koła. Zmienia
  WYŁĄCZNIE rysunek, żadna liczba nie jest przeliczana. Wariant „od Barana"
  unieruchamia koło względem zodiaku, więc dwa horoskopy da się porównać na oko.

Oba nowe systemy zgodne z wyrocznią co do zera od pierwszego uruchomienia.
Razem 13 systemów: 2 833 424 porównania w przemiale, zero przekroczeń.

PRZY OKAZJI — DWA BŁĘDY, KTÓRE SAM WPROWADZIŁEM I KTÓRYCH TESTY NIE WIDZIAŁY:
- linia zbierająca ostrzeżenia o fallbacku trafiła do handlera strony głównej
  zamiast do compile_pdf: odwoływała się do nieistniejącej zmiennej, czyli 500
  na stronie głównej, a do PDF-a ostrzeżenia nie docierały wcale,
- compile_build używał parametru formularza, którego nie miał w sygnaturze.

Oba przeszły przez komplet zielonych testów, bo żaden nie wywoływał POST-a —
testy prezentacji sprawdzały teksty w szablonach i w main.py. Doszły więc testy
uderzające w prawdziwe trasy (POST / i POST /compile ze stubowaną logiką), które
łapią tę klasę błędu.

Z tego samego powodu przepisane dwa testy PDF-a: greppowały z main.py dokładny
kształt wywołania render(chart, theme="print") i pękały przy dopisaniu argumentu,
mimo poprawnego zachowania. Teraz wołają trasę i sprawdzają, że KAŻDY z czterech
rysunków dostaje motyw druku.

LOG-05 i PRE-05 → Zrobione w docs/astrololo_wymagania.xlsx.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 22:38:43 +02:00
gitea e3114f3e7c docs(bezpieczeństwo): runbook rotacji sekretów + poprawka nieaktualnej treści LOG-33
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m31s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 11s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 8s
build / build (push) Successful in 14s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m31s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m28s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 12s
Testy / Kontrola składni wszystkich warstw (push) Successful in 8s
Wymaganie mówiło o restarcie „WSZYSTKICH TRZECH usług" przy zmianie INTERNAL_TOKEN.
Sprawdzenie żywych deploymentów pokazuje, że token czytają CZTERY: data, logic,
presentation ORAZ render (doszedł przy PRE-24, a wymaganie tego nie nadgoniło).
Kto zrobiłby rotację literalnie, zostawiłby render ze starym tokenem i usługa po
cichu przestałaby się dogadywać — dokładnie ta awaria, przed którą wymaganie
ostrzega. Treść w arkuszu poprawiona.

docs/log33-sekrety-i-rotacja.md:
- MACIERZ zależności wyliczona z deploymentów, nie z założeń. Wniosek praktyczny:
  klucze łącz rotuje się PARAMI usług (logic+data, presentation+logic,
  presentation+render), a nie całą czwórką — restartu wszystkiego wymaga tylko
  INTERNAL_TOKEN.
- Procedury per sekret, od najbezpieczniejszej do przećwiczenia (klucze LLM —
  dotykają tylko logiki, awaria widoczna i nieszkodliwa) po INTERNAL_TOKEN.
  Wszystkie zachowują pozostałe klucze przez odczyt z istniejącego sekretu —
  inaczej rotacja jednego skasowałaby resztę.
- Weryfikacja: sam „Running" NIE wystarcza (pody wstaną, nawet gdy warstwy się nie
  dogadują) — trzeba przeliczyć horoskop i wygenerować PDF, żeby dotknąć wszystkich
  łącz.
- Kroki hartowania z jasnym podziałem: co zrobione (automount tokenów — deploy #13),
  co wymaga węzła (szyfrowanie at-rest), co świadomie odłożone (Sealed Secrets —
  dziś sekrety NIE są w repo GitOps, więc ta zasada już jest spełniona; Sealed
  Secrets dodałyby odtwarzalność kosztem nowego pojedynczego punktu awarii).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 17:10:23 +02:00
gitea bc80745a94 docs(wymagania): DAN-25 rozbite na 25a (zrobione) i 25b (Kerberos, nice to have)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m32s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m28s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 13s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 10s
build / build (push) Successful in 18s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m32s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m28s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 13s
Testy / Kontrola składni wszystkich warstw (push) Successful in 11s
Runbook wykonany na NAS-ie, więc wymaganie rozdziela się na to, co faktycznie
osiągnięte, i to, co zostaje jako opcja na przyszłość — mieszanie obu w jednym
wierszu kazałoby wybierać między „zrobione" a „niezrobione" dla czegoś, co jest
i jednym, i drugim.

DAN-25a (Must, ZROBIONE): udział /mnt/Tank1/astrololo wyeksportowany wyłącznie dla
trzech węzłów k3s, tylko do odczytu, z root_squash. Zamknięta najkrótsza droga
wycieku — wcześniej każdy w LAN mógł zamontować udział i wziąć kompletne bazy
z pominięciem logowania, limitów, audytu i canary. Zawężony TYLKO ten udział, bo
Tank1 obsługuje cały homelab. Procedura: docs/dan25-zabezpieczenie-nfs.md.

DAN-25b (Could, do zrobienia): NFSv4 + Kerberos albo wolumen nieosiągalny poza
klastrem. Uzasadnienie w wierszu: lista adresów IP zatrzymuje dostęp przypadkowy
i oportunistyczny, ale NIE jest uwierzytelnianiem — adres da się podszyć w tej
samej sieci, a przejęcie dowolnego węzła daje udział. Koszt (KDC + keytaby)
uzasadniony dopiero, gdy sieć przestanie być zaufana.

Bilans: 63 Zrobione · 9 W trakcie · 14 Do zrobienia.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 16:46:47 +02:00
gitea 6e7cfcbbd7 docs(bezpieczeństwo): runbook zamknięcia dostępu do baz na NFS (DAN-25)
build / build (push) Successful in 19s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m29s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m28s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 14s
Testy / Kontrola składni wszystkich warstw (push) Successful in 11s
Bazy leżą na udziale osiągalnym z całej sieci — to najkrótsza droga do wycieku,
z pominięciem logowania, limitów, audytu i canary. Runbook zawęża udział
`astrololo` do trzech węzłów k3s, ustawia tylko odczyt i root_squash.

Krok po kroku, komenda po komendzie: rozpoznanie → dowód dziury (montowanie
z maszyny spoza klastra) → kopia konfiguracji → zmiana → cztery testy weryfikacyjne
→ ścieżka wycofania.

Dwie zasady wynikające z tego, że Tank1 obsługuje CAŁY homelab (Proxmox, conjurer
z zapisem, media, LXC-e, stacja robocza):
- ruszamy WYŁĄCZNIE udział astrololo, nigdy globalnych ustawień usługi NFS —
  inaczej padną VM-y, bot i biblioteka mediów;
- w TrueNAS SCALE nie edytuje się /etc/exports ręcznie (middleware nadpisze) —
  wszystko przez midclt albo GUI.

Runbook każe też sprawdzić nazwy pól w API PRZED zapisem, bo middleware zmieniało
je między wersjami SCALE (path vs paths).

Opisane pułapki: hookscript Proxmoxa czekający na showmount przed startem VM;
utrata możliwości wgrywania baz przez NFS po ro=true; lista IP to nie
uwierzytelnianie (docelowo NFSv4+Kerberos, jak mówi samo wymaganie).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 14:43:12 +00:00
gitea 70c83cfc0c docs(wymagania): statusy po serii iteracji „czysto"
build / build (push) Successful in 19s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m35s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m28s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 16s
Testy / Kontrola składni wszystkich warstw (push) Successful in 15s
Aktualizacja kolumny Status wobec stanu faktycznego. Bilans: 62 Zrobione ·
9 W trakcie · 14 Do zrobienia (było 52 · 9 · 24).

Zrobione (zmergowane i działające):
- PRE-03 strefa czasowa z lokalizacji (#43)
- DAN-23 + PRE-10 eksport wyników do Excela (#45)
- PRE-26 cache-busting statyki (#48)
- PRE-06 konfigurowalne aspekty i orby (#49)
- PRE-04 techniki relacyjne — synastria (#51) + Returns w kalendarzu (LOG-12)
- PRE-17 konta imienne i dziennik audytowy (#54)
- PRE-09 + DAN-15 przegląd baz na NFS i ich włączanie/wyłączanie (#55)
- PRE-24 raport PDF — obraz render wreszcie się zbudował, PDF powstaje w produkcji

Świadomie NIE oznaczone jako zrobione:
- LOG-05 / PRE-05 zostają „W trakcie": liczenie kilku systemów domów naraz działa,
  ale egzotyczne (Placidus/Koch/Regiomontanus/Campanus) wymagają silnika swisseph;
- DAN-26 z „Do zrobienia" na „W trakcie": mechanizm rekordów-pułapek jest gotowy
  i przetestowany, ale wstrzyknięcie pułapek do realnych baz i rejestr wariantów
  to krok właściciela, nie kodu.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 09:59:56 +00:00
gitea d3d9b365fe feat(bezpieczeństwo): konta imienne i dziennik audytowy (PRE-17)
build / build (push) Successful in 17s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m29s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m28s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m25s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 11s
Testy / Kontrola składni wszystkich warstw (push) Successful in 8s
Jedno wspólne hasło nie mówiło, KTO sięgał do baz, a odebranie dostępu jednej
osobie wymagało zmiany hasła wszystkim. Przy bazach o realnej wartości handlowej
to za mało.

KONTA IMIENNE: `APP_USERS='alicja:scrypt$…,bartek:scrypt$…'`. Hash liczy scrypt ze
STDLIB — zero nowych zależności; hasła nie ma w konfiguracji jawnie. Zakładanie
konta: scripts/make_user.py (hasło interaktywnie, nie w historii powłoki).
Odebranie dostępu = usunięcie wpisu, reszta nie zmienia haseł.

Gdy APP_USERS jest ustawione, wspólne APP_PASSWORD PRZESTAJE działać (ostrzeżenie
przy starcie) — działające obok kont byłoby tylnym wejściem bez śladu w dzienniku.
Dopóki APP_USERS nie jest ustawione, stary tryb działa jak dotąd (zgodność wstecz).

DZIENNIK AUDYTOWY: każde żądanie zostawia wpis „kto, skąd, co, status, ILE
rekordów, ile ms". Liczba rekordów jest tu sednem — pojedyncze zapytanie wygląda
niewinnie, suma pokazuje powolne wypompowywanie bazy przez osobę uprawnioną.
Liczona dla wyszukiwarki sygnifikatorów, raportu i eksportu do Excela (ten wynosi
najwięcej naraz). W logach NIE MA treści — ani rekordów, ani promptów.

Dwa realne błędy złapane po drodze:
- `secrets.compare_digest` rzuca TypeError na znakach spoza ASCII, więc hasło z
  polskimi literami wywracało logowanie błędem 500 zamiast odmowy (błąd ZASTANY,
  sprzed tej zmiany) — porównujemy teraz bajty;
- dziennik był PUSTY na żywym serwerze: domyślna konfiguracja uvicorna nie
  obsługuje naszych loggerów. Niewidoczny dziennik jest gorszy niż jego brak,
  więc audyt dostał własny handler na stdout. Oba przypadki mają testy regresji.

Instrukcja wdrożeniowa: docs/konta-i-audyt.md. Testy: +15. Prezentacja 243.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 19:57:03 +00:00
gitea 78af6d4755 feat(dane): mechanizm rekordów-pułapek (canary) — wykrywanie wycieku baz (DAN-26)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m29s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 11s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 8s
build / build (push) Successful in 19s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m30s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 11s
Testy / Kontrola składni wszystkich warstw (push) Successful in 7s
Zabezpieczenie DETEKCYJNE (nie prewencyjne): kilka unikalnych, wiarygodnie
wyglądających rekordów-pułapek w bazach. Nie zmieniają interpretacji (odsiewamy
je z wyników), ale jeśli pojawią się w cudzej kopii — są dowodem pochodzenia, a
przy wariancie na kopię — wskazują ŹRÓDŁO wycieku.

`canary.py`: pułapkę rozpoznajemy po MARKERZE (unikalny ciąg z ENV, nieobecny w
realnych danych). `screen(rows, query_value)`:
- ODSIEWA rekordy z markerem z wyników — i to na WYJŚCIU z warstwy danych
  (`/search`), więc nie dotrą wyżej ani do promptu LLM (LOG-30), niezależnie od
  dostawcy (Excel/SQL);
- TRIPWIRE: gdy zapytanie celuje wprost w marker (enumeracja bazy, nie liczenie
  horoskopu) → log warning.
Bez `CANARY_MARKERS` — przezroczyste, zero kosztu dla normalnego ruchu.

Rejestr wariant→kopia (traitor tracing) i wstrzyknięcie do REALNYCH baz to krok
właściciela (poza kodem — nie ruszamy kupionych plików automatycznie);
instrukcja: docs/canary-registry.md. Mechanizm zbudowany i przetestowany na
syntetycznych pułapkach.

Testy: +7 (przezroczystość bez markerów, odsiewanie, tripwire, marker w dowolnym
polu, endpoint odsiewa przed zwrotem). Pierwsze testy w usłudze `data`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 21:15:53 +02:00
gitea 81e09aa6df docs(wymagania): PRE-09/DAN-15 przedefiniowane pod model serwerowy
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m39s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m32s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 19s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 12s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m42s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m27s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 15s
Testy / Kontrola składni wszystkich warstw (push) Successful in 9s
build / build (push) Successful in 17s
Redefinicja uzgodniona z użytkownikiem (2026-07-28), ale do tej pory żyła tylko
w notatkach — w arkuszu wciąż było desktopowe „wskazanie folderu baz + pamięć 3
ścieżek", bezcelowe w modelu serwerowym (bazy na stałym udziale NFS, nie w folderze
wybieranym przez użytkownika).

Nowe brzmienie obu wymagań:
- DAN-15 (dane): warstwa danych wystawia listę baz dostępnych na NFS (nazwa +
  metaopis: rozmiar / liczba rekordów / data) i honoruje globalne włącz/wyłącz
  każdej bazy przy wyszukiwaniu interpretacji.
- PRE-09 (prezentacja): ekran ustawień pokazuje te bazy i pozwala globalnie
  włączać/wyłączać każdą; wyłączona nie jest brana pod uwagę przy interpretacji.

Priorytet/status bez zmian (PRE-09 Must, DAN-15 Should, oba Do zrobienia). Zmiana
tylko tekstu wymagań — plik poza dwoma wierszami nietknięty, bilans statusów ten sam.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 20:37:17 +02:00
gitea 9a5d61b5eb docs(wymagania): PRE-18 → Zrobione (aspektarian + wizualizacje pochodne)
build / build (push) Successful in 43s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m14s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 10m0s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 35s
Testy / Kontrola składni wszystkich warstw (push) Successful in 22s
Audyt kolumny Status wobec kodu. Jedyna realna rozbieżność od ostatniego przeglądu
(PR #24): PRE-18 „Grafika aspektów (aspectarian) i wizualizacje pochodne" wisiało
na „Do zrobienia", a jest dowiezione i zmergowane:
- aspektarian (trójkątna siatka aspektów) — PR #38,
- wizualizacje pochodne: wykres deklinacji z paralelami + oś antyscji — PR #40,
- wpięte też w raport „Skompiluj" i PDF — PR #41.

Bilans: Zrobione 52 · W trakcie 9 · Do zrobienia 24.

Reszta pozostaje bez zmian — zweryfikowane, że statusy są aktualne (m.in.
LOG-05/PRE-05 wiele domów naraz, LOG-17 asp+/-, DAN-08 jako zasób danych wciąż
częściowe). PRE-24 (PDF) celowo zostaje „W trakcie": kod kompletny i przetestowany,
ale usługa render nie składa jeszcze PDF-ów w produkcji (blokada = dysk runnera).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 20:29:20 +00:00
gitea 171deff2d1 feat(prezentacja): linie aspektów na kosmogramie (PRE-12, etap 3)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m36s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m35s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 28s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 21s
build / build (push) Successful in 48s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m34s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m36s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 31s
Testy / Kontrola składni wszystkich warstw (push) Successful in 17s
Trzeci etap rysowania koła: linie aspektów w środku. Domyka rdzeń PRE-12 —
kosmogram ma teraz znaki, domy, osie, obiekty i aspekty.

Linie łączą PRAWDZIWE pozycje obiektów (nie rozsunięte glify — aspekt dotyczy
tego, gdzie planeta faktycznie stoi) na okręgu piasty, w środku koła.

Kodowanie jak w klasycznych programach:
- KOLOR = charakter aspektu: niebieski harmonijny (trygon, sekstyl), czerwony
  napięty (kwadratura, opozycja), zielony koniunkcja. Dwa kolory na środku od
  razu mówią „gdzie łatwo, gdzie tarcie".
- GRUBOŚĆ i JASNOŚĆ = orb: im ciaśniej, tym mocniej. Poniżej 1° wyraźne
  pogrubienie (wprost z wymagania) — najściślejsze aspekty rzucają się w oczy,
  a szerokie ledwo majaczą, żeby nie robić ze środka plątaniny.

Rysowane jako pierwsze, pod resztą: obiekty siedzą na R_PLANET=150, daleko od
piasty (R_HUB=48), więc glify i linie się nie stykają, a osie i szprychy lądują
na wierzchu.

Motyw druku (PDF, PRE-24) dostaje własne, ciemniejsze kolory aspektów bez
zmiennych CSS — samodzielny konwerter SVG arkusza nie widzi.

Weryfikacja na horoskopie referencyjnym: 24 aspekty, 5 ciasnych (<1°) faktycznie
pogrubionych; kolory zgodne z typem (9 czerwonych napiętych, 10 niebieskich
harmonijnych, 5 zielonych koniunkcji); print bez zmiennych CSS. Sprawdzone
wizualnie — pełny aspektarian, czytelny.

Testy: 8 nowych (linie obecne, kolor wg typu, pogrubienie <1°, prawdziwa pozycja
nie rozsunięta, pominięcie aspektu do obiektu bez pozycji, brak aspektów, motyw
druku). Całość: prezentacja 138 passed. PRE-12 -> Zrobione.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 17:44:25 +02:00
gitea f24616d342 feat(render): raport PDF przez LaTeX jako osobna usluga (PRE-24)
build / build (push) Successful in 1m27s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m25s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 10m1s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 33s
Testy / Kontrola składni wszystkich warstw (push) Successful in 27s
Ostatnia z osmiu wskazowek partnerow. Nowa usluga services/render sklada raport:
generuje plik posredni .tex i kompiluje go XeLaTeX-em do PDF.

OSOBNY komponent, nie czesc prezentacji — ta sama zasada co przy izolacji
swissepha (LOG-27). TeX Live wazy setki megabajtow; w obrazie produktu
spowalnialby kazdy build, a tak aktualizuje sie niezaleznie i jego awaria nie
kladzie aplikacji, tylko przycisk „Pobierz PDF".

SZYFROWANIE, o ktore prosiles: lacze prezentacja↔render idzie tak samo jak
pozostale, ale z WLASNYM, TRZECIM kluczem (LINK_KEY_PRESENTATION_RENDER). Osobny,
bo tym laczem plynie CALY raport — dane urodzeniowe i opisy z baz — wiec przejecie
go nie moze otwierac lacza do logiki ani do danych. Fail-closed: bez klucza pod
nie wstaje. Test kopii link_crypto obejmuje teraz cztery uslugi.

Uklad PDF wg prosby: imie i nazwisko -> wprowadzone dane -> RYSUNEK kosmogramu
-> interpretacja natalna -> predykcje okresowe. Test pilnuje kolejnosci.

Dwie rzeczy, ktore wyszly dopiero przy skladaniu tego kawalka:

1. KOSMOGRAM NIE NADAWAL SIE DO PDF. Uzywa zmiennych CSS (var(--line)) i klasy
   .glyph, ktorej font podaje styles.css — a samodzielny konwerter SVG→PDF nie zna
   naszego arkusza. Wyszlyby czarne kreski BEZ SYMBOLI. Stad wariant „print":
   konkretne kolory na bialym tle i font glifow wpisany wprost w rysunek. Przy
   okazji zalatwia to etap 4 planu kola (wariant do druku).

2. UCIECZKA ZNAKOW LATEXA byla zepsuta — i zlapal to moj wlasny test. Zamiana
   „\” na \textbackslash{} szla w tej samej petli co nawiasy, wiec kolejne
   podmiany ucieklyby nawiasy dopiero co wstawione: wychodzilo
   \textbackslash\{\}. Poprawka: ukosnik chowany pod znacznik zastepczy i
   rozwijany na koncu. To nie kosmetyka — niezauwazony „%” komentuje RESZTE LINII,
   wiec zdanie od modelu urywaloby sie w polowie, a PDF powstawalby normalnie,
   tylko krotszy. Test na wrogim tekscie sprawdza tez, ze \end{document} ani
   \input{} nie wyrwa sie z dokumentu.

Usluga nie zapisuje nic poza katalogiem tymczasowym, ktory sprzata po sobie;
w manifescie readOnlyRootFilesystem + emptyDir na /tmp. /health raportuje
obecnosc xelatex i rsvg-convert, zeby zepsuty obraz bylo widac od razu.

Zweryfikowane na zywo (TestClient uslugi render): zadanie bez szyfrowania
z POPRAWNYM tokenem -> 400; obcy klucz -> 400 i tajny opis nie wraca; wlasciwy
klucz -> zadanie dochodzi do aplikacji, tresci baz NIE MA na kablu, odpowiedz
zaszyfrowana. Manifesty przechodza kubectl apply --dry-run=server na zywym
klastrze.

CZEGO NIE SPRAWDZILEM: samej kompilacji PDF. W tym srodowisku nie ma ani TeX
Live, ani dzialajacego runtime'u kontenerow (docker CLI jest, daemon nie) —
probowalem zbudowac obraz i sie nie dalo. Sprawdzone jest wszystko dookola:
generowanie .tex, ucieczka znakow, szyfrowanie, kontrakt API, samowystarczalnosc
SVG. Pierwsze uruchomienie na klastrze trzeba obejrzec — dlatego PRE-24 zostaje
jako „W trakcie", nie „Zrobione".

Instrukcja wdrozenia: docs/wdrozenie-render-pdf.md (klucz, obraz, merge,
weryfikacja, znane ograniczenia).

Testy: 15 nowych (render) + 14 (lacze i wariant druku w prezentacji).
Calosc: prezentacja 131, logika 265/1 skip, render 15.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 19:21:49 +02:00
gitea 6c9029c496 feat(prezentacja): zakladka „Skompiluj" — zbiorczy raport (PRE-23)
build / build (push) Successful in 52s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m16s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m57s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 32s
Testy / Kontrola składni wszystkich warstw (push) Failing after 8s
Czwarta wskazowka partnerow. Nowa zakladka sklada w jedno trzy kawalki liczone
w roznych miejscach: policzony horoskop, interpretacje natalna z AI i wszystkie
zapamietane predykcje okresowe.

Uklad sekcji dokladnie wg prosby: imie i nazwisko -> wprowadzone dane ->
RYSUNEK kosmogramu -> interpretacja natalna -> predykcje okresowe. Test pilnuje
tej kolejnosci, bo to jedyna rzecz, ktora latwo przestawic przy refaktorze,
a partnerzy podali ja wprost.

Skad material:
- HOROSKOP liczymy TU NA NOWO z danych formularza, zamiast go zapamietywac.
  To czysta funkcja wejscia — tanio powtorzyc, a odpada trzymanie w przegladarce
  duzego wyniku, ktory moglby sie rozjechac z aktualnym formularzem.
- INTERPRETACJA NATALNA — nowy natal.js, odpowiednik predictions.js. Natalna jest
  JEDNA (dotyczy momentu urodzenia, nie okresu), wiec ponowne wygenerowanie
  podmienia slot zamiast dokladac wpis.
- PREDYKCJE — z magazynu z PRE-22.

compile.js czyta magazyny przez ICH API (window.astrololoNatal /
astrololoPredictions), a nie siegajac wprost do localStorage — format danych ma
jednego wlasciciela: modul, ktory je zapisuje. Test tego pilnuje.

Zakladka MOWI, CZEGO BRAKUJE: panel gotowosci z trzema pozycjami i podpowiedzia,
na ktorej zakladce uzupelnic. Bez tego uzytkownik zlozylby niekompletny raport
i dowiedzialby sie o tym dopiero po otwarciu PDF-a.

Tresc od modelu jest ESKEJPOWANA przed wstawieniem do DOM — to tekst z zewnatrz,
wiec bez tego mielibysmy wektor wstrzykniecia.

Weryfikacja na zywej aplikacji: dwie predykcje zapisane w Kalendarzu, natalna
w Interpretacjach, obie odczytane na Skompiluj (panel: brak horoskopu na zolto,
dwa pozostale na zielono). Po zlozeniu wszystkie trzy zielone, a raport zaczyna
sie od „Jan Kowalski" i danych wejsciowych. Kolejnosc sekcji sprawdzona na
wyrenderowanym HTML: naglowek 2931 < dane 3033 < kosmogram 3158 < natalna 26544
< predykcje 26575.

Testy: 16 nowych. Poprawione tez trzy wlasne testy, ktore lapaly nazwy plikow
w KOMENTARZACH zamiast w tagach skryptow. Calosc: prezentacja 117 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 18:09:56 +02:00
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 / Build obrazu silnika B (swisseph) (push) Successful in 38s
Testy / Kontrola składni wszystkich warstw (push) Successful in 20s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 10m42s
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 ace76183e5 feat(logic): glify astrologiczne — konwersja tekst↔symbol (LOG-22)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m55s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m43s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 37s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 21s
build / build (push) Successful in 1m22s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m12s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m39s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 33s
Testy / Kontrola składni wszystkich warstw (push) Successful in 24s
Warunek wstępny pod kosmogram (PRE-12): planety i znaki na kole rysujemy
symbolami. Nowy moduł engine/glyphs.py:

- forward: nazwa → glif (planety, punkty, Loty, znaki, aspekty, retro ℞),
- reverse: glif → nazwa (znosi obecność/brak selektora wariantu),
- glyphify(): tokeny [XX z bazy → glify; przyklad z wymagan
  „[Sa [Pis 26°08' [conj [PF" → „♄  26°08' ☌ ⊗" (stopnie nietkniete).

DAN-18 „tylko tekst, nigdy emoji" potraktowane serio, TRZEMA warstwami — bo
sam selektor NIE wystarcza (potwierdzone wizualnie w przegladarce):
1. w danych: selektor wariantu tekstowego U+FE0E na znakach zodiaku oraz ♀/♂
   (maja wariant emoji); ☉ i reszta go nie dostaja (zbedny),
2. CSS font-variant-emoji:text,
3. CSS font-family celujacy w MONOCHROMATYCZNE fonty symboli PRZED emoji.
   Bez pkt. 3 macOS/Chromium i tak renderowal znaki  jako kolorowe kafelki
   Apple Color Emoji mimo VS15 — planety wychodzily tekstem, znaki nie. Stack
   „Apple Symbols / Segoe UI Symbol / Noto Sans Symbols2" naprawia render.
   NIGDZIE nie emitujemy U+FE0F (emoji) — pilnuje tego test.

Wpiete w build_chart: kazda pozycja dostaje glyph (planeta) + sign_glyph (znak,
zalezny od zodiaku, wiec po przesunieciu), osie i Loty tak samo (Fortuna ⊗,
reszta Lotow bez standardowego symbolu → None), aspekty dostaja glif,
result[„sign_glyphs"] to pierscien 12 znakow pod kolo.

UI: kolumna „Sym." w tabeli pozycji (planeta + znak) i symbol przy aspekcie.

Testy: 14 (kompletnosc — kazdy obiekt/znak/aspekt ma glif; dwukierunkowosc;
DAN-18 brak FE0F, znaki maja VS15, ☉ nie; przyklad glyphify z wymagan).
Calosc: logika 265 passed / 1 skipped, prezentacja 25. Render znakow
potwierdzony wizualnie (czarno-biale symbole, nie emoji).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 20:46:38 +02:00
gitea e8f868e907 docs(wymagania): realne statusy + kosmogram jako feature prezentacji
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 11m56s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m36s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 31s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 22s
build / build (push) Successful in 44s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m59s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m33s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 31s
Testy / Kontrola składni wszystkich warstw (push) Successful in 18s
Kolumna Status stała na „Do przeglądu" dla wszystkiego (poza LOG-32), mimo że
kilkadziesiąt rzeczy działa w produkcji — arkusz przestał odzwierciedlać stan
projektu. Słownik statusów pochodził z fazy PRZED kodowaniem („Do przeglądu ·
Zaakceptowane · Odrzucone · W trakcie"); dodaję fazę realizacji: Zrobione ·
W trakcie · Do zrobienia.

Statusy ustawione na podstawie FAKTYCZNIE zmergeowanego kodu, nie na oko —
wątpliwe zweryfikowane w źródłach (np. LOG-13 „ascensional" okazało się tylko
„right ascension" w komentarzu; PRE-06 „Orb" to nagłówek kolumny, nie ustawienie).

Bilans: Zrobione 43 · W trakcie 8 · Do zrobienia 26.
  - Logika: 26 / 4 / 3 (brakuje m.in. LOG-09 primary directions, LOG-13
    ascensional, LOG-22 glify; LOG-11 ZR/Decennials i LOG-17 asp+/- w trakcie),
  - Prezentacja: 7 / 2 / 9,
  - Dane: 10 / 2 / 14 (dużo tabel źródłowych jeszcze niepodpiętych).

Kosmogram (PRE-12): program od początku miał rysować koło horoskopowe — umknęło.
Podnoszę z „Could/opcjonalnie" na „Should", rozpisuję zakres (SVG po stronie
serwera: znaki, domy, planety z glifami, osie, linie aspektów; docelowo znaczniki
deklinacji/antyscji z LOG-07; zależność od glifów LOG-22) i oznaczam „Do zrobienia"
jako fokus najbliższych iteracji.

Nowy PRE-18: grafika aspektów (aspectarian) i wizualizacje pochodne horoskopu —
naturalny towarzysz kosmogramu.

Przegląd: zaktualizowana legenda statusów, licznik Prezentacji 17→18, dodana
tabela postępu realizacji per warstwa.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 20:30:13 +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 4da5f5fe7e docs: braki bezpieczenstwa jako wymagania (PRE-16/17, DAN-25/26, LOG-33)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m53s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m56s
Testy / Build obrazu silnika B (swisseph) (pull_request) Failing after 44s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 34s
build / build (push) Successful in 52s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m51s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m56s
Testy / Build obrazu silnika B (swisseph) (push) Failing after 30s
Testy / Kontrola składni wszystkich warstw (push) Successful in 20s
Obecny poziom ochrony wystarcza do developmentu, ale luki musza byc zapisane,
zeby nie wyparowaly przed produkcja.

- PRE-16 (Must) HTTPS/TLS — dzis Basic Auth leci po http, czyli haslo da sie
  podsluchac. Odblokowuje przy okazji DWIE funkcje zepsute z tego samego
  powodu: geolokalizacje (Tu i teraz) i kopiowanie do schowka — oba wymagaja
  secure context.
- PRE-17 (Should) konta imienne + slad audytowy zamiast jednego wspolnego
  hasla; bez tego nie wiadomo, kto pobieral dane, ani jak odciac jedna osobe.
- DAN-25 (Must) ograniczenie udzialu NFS — kto ma do niego dostep, bierze
  komplet baz z pominieciem aplikacji. Dzis najkrotsza droga do wycieku.
- DAN-26 (Should) znakowanie baz rekordami-pulapkami — zabezpieczenie
  detekcyjne: pozwala udowodnic zrodlo wycieku.
- LOG-33 (Should) sekrety w spoczynku (etcd to tylko base64) + rotacja.

Q-12 odnotowane jako rozstrzygniete: bazy zostaly KUPIONE, wiec zgoda jest —
ale to nie zwalnia z ochrony. LOG-32 przestawione na "W trakcie" z wykazem,
co juz wdrozone, a co zostaje.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 20:47:21 +02:00
gitea 2892b71be3 docs: wymagania feature'u horoskop AI (LOG-29..32, PRE-14/15, Q-12/13)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m42s
Testy / Build obrazu silnika B (swisseph) (pull_request) Failing after 29s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 18s
build / build (push) Successful in 49s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m44s
Testy / Build obrazu silnika B (swisseph) (push) Failing after 29s
Testy / Kontrola składni wszystkich warstw (push) Successful in 26s
Nowy feature: generowanie promptow do ChatGPT/Claude z naszych wyliczen i
wolanie modelu — horoskop urodzeniowy (ekran Interpretacje) oraz horoskop
na wybrany okres (ekran Kalendarz).

Warstwa logiczna:
- LOG-29 generator promptow (profile natal + okresowy), prompt i wynik PL,
  obowiazek odnoszenia kazdej tezy do konkretnego sygnifikatora
- LOG-30 ograniczanie rozmiaru: dedup -> grupowanie -> sortowanie wg wagi
  (LOG-21) -> obciecie ogona -> skracanie; raportuje ile pominieto
- LOG-31 pluggable LLMProvider (OpenAI/Anthropic) + POST /chart/horoscope;
  klucz tylko z sekretu, limity kosztu/tokenow, prompt zwracany zawsze
- LOG-32 (Must) poufnosc: prompt niesie WLASNOSC wspolpracownika i dane
  urodzeniowe -> zgoda wlasciciela baz, API zamiast czatu konsumenckiego,
  minimalizacja, podglad przed wyslaniem, tryb bez pelnych opisow

Warstwa prezentacji:
- PRE-14 przycisk generowania + budzet promptu + podglad promptu przed
  wyslaniem + kopiowanie (prompt dziala takze bez wysylki do API)
- PRE-15 transparentnosc: dostawca/model, ile wskazan pominieto,
  zastrzezenie ze to nie porada medyczna, ostrzezenie przed wysylka

Pytania otwarte: Q-12 (zgoda wlasciciela baz — blokuje tryb pelnych opisow),
Q-13 (dostawca/model i limit kosztow).

Zaktualizowane liczniki w arkuszu Przeglad i zakresy autofiltrow.
Decyzje wg ustalen w czacie: integracja API, pelne opisy z baz, PL, suwak.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 16:46:44 +02:00
gitea 561d95c7f4 Wymagania: kolumna "Po ludzku (bez żargonu)" — nietechniczne wyjaśnienia
Dodaje per-requirement, kompletnie nietechniczne tłumaczenie do trzech
arkuszy warstw (dane 24, logika 28, prezentacja 13) jako ostatnią kolumnę.
Dla osób nietechnicznych — m.in. współpracownika dostarczającego bazy —
żeby każdy wiersz był zrozumiały bez żargonu. Autofiltr rozszerzony.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:16:33 +02:00
gitea 21442b35b9 Wymagania: dwa silniki w warstwie logicznej (własny + AGPL) do porównań
Decyzja: warstwa logiczna ma dwie wymienne implementacje silnika obliczeń —
własną/permisywną (ścieżka A) i AGPL (Swiss Ephemeris) — dla wbudowanego
frameworku porównań i walidacji. Prezentacja i dane pozostają wspólne.

- docs/architektura-dwoch-silnikow.md: schemat, izolacja licencyjna silnika
  AGPL jako osobnej usługi (engine-swisseph), mechanizm dual-run, mapowanie
  na wymagania, profile wdrożeniowe.
- astrololo_wymagania.xlsx (Warstwa logiczna): rewizja LOG-24 (EngineProvider
  z dwoma backendami) i LOG-25 (framework porównawczy); nowe LOG-26 (dual-run
  + raport różnic), LOG-27 (izolacja licencyjna silnika AGPL), LOG-28
  (kontrakt parzystości silników). Licznik w Przeglądzie: 28.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 16:50:56 +02:00
gitea 3655b39acf Rozszerz analizę warstwy logicznej: gotowce, licencje, złożoność + LOG-25
- docs/przeglad-bibliotek-i-licencji.md: przegląd istniejących bibliotek/
  programów z komentarzem licencyjnym i oceną ryzyka praw autorskich;
  rekomendacja ścieżki A (Skyfield/Moshier permisywne) + nota o prawach do
  treści baz.
- docs/warstwa-logiczna-analiza.md: rozwinięcie 24 wymagań LOG, przypisanie
  permisywnych gotowców, ocena złożoności implementacji od zera, rola B/C
  jako wyroczni walidacyjnej; kolejność budowy.
- astrololo_wymagania.xlsx: w arkuszu "Warstwa logiczna" 4 nowe kolumny
  (gotowe rozwiązanie / licencja / złożoność od zera / rola B/C) oraz nowy
  wiersz LOG-25 (harness walidacyjny). Licznik w Przeglądzie zaktualizowany.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 12:31:37 +02:00
gitea 7bda39ab46 Dodaj arkusz wymagań projektu (model trójwarstwowy)
docs/astrololo_wymagania.xlsx — spójna lista wymagań zsyntetyzowana z
dokumentów astroparser_notes2, astroparser notes3 i astro19 version2026.

Sześć arkuszy: Przegląd, Warstwa danych (24), Warstwa logiczna (24),
Warstwa prezentacji (13), Pytania otwarte (11), Słownik (25). Każde
wymaganie: ID, kategoria, opis, szczegóły, priorytet (MoSCoW), status,
źródło. Dokument roboczy do iteracyjnego przeglądu przed implementacją.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 18:18:46 +02:00