feat(domy): Placidus i Koch + jawny fallback poza kołem podbiegunowym
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m30s
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 17s
Testy / Kontrola składni wszystkich warstw (push) Successful in 8s
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m28s
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 8s

Etap 2: dwa systemy łuku dobowego — jedyne, które mają miejsca, gdzie po prostu
NIE ISTNIEJĄ. Koch zgadza się z wyrocznią co do zera; Placidus do 1,7e-6°, przy
czym to próg zbieżności WYROCZNI, nie nasz: nasze cuspy spełniają definicję
Placidusa z dokładnością 1e-12° (osobny test, działa bez swissepha).

Placidus jako jedyny nie ma wzoru zamkniętego — cusp jest zdefiniowany warunkiem
na samego siebie („punkt, który przebył 1/3 swojego półłuku"), więc iterujemy po
punkcie stałym do 1e-11°. Brak zbieżności traktujemy jako wyjście poza dziedzinę,
nie jako wynik.

Koch okazał się natomiast ZAMKNIĘTY: jego kryterium to czas od wschodu stopnia
stojącego na MC, a półłuk tego stopnia znamy wprost z jego deklinacji. Definicja
za Astrodienst (astro.com/astrowiki/en/Koch_House_System) — nie zgadywana.

Powyżej koła podbiegunowego oba odmawiają liczenia i wyrocznia odmawia dokładnie
tych samych przypadków (5245/20 000 losowych, zero rozjazdów dziedziny). Odmowa
jest wyjątkiem, nie liczbą: cicha podmiana systemu jest niewykrywalna z wykresu.

Ustępstwo wobec rzeczywistości siedzi osobno, w cusps_detailed(): podstawia
Porphyry'ego i ZAWSZE zostawia ślad. Ten ślad idzie wszystkimi trzema wyjściami —
na ekran (ramka, nie „muted"), w prompt do modelu (inaczej napisze „Twój Placidus"
o Porphyrym) i do PDF-a, w ramce PRZED rysunkami. Astrolog z Tromsø dostaje
wynik i wie, że go dostał inaczej.

Przy okazji: nazwy systemów były zaszyte w czterech szablonach naraz. Przy trzech
systemach uchodziło to na sucho, przy dziesięciu nie — jest katalog w jednym
miejscu, a testy szablonów RENDERUJĄ je zamiast szukać tekstu w źródle, więc
łapią też literówki w Jinja.

Większe jądro efemeryd (de441): świadomie zdegradowane do „nice to have" —
rozszerza wyłącznie zakres dat, nie poprawia niczego w obecnym. Odnotowane
w domain.py przy JD_MIN/JD_MAX, żeby nie wróciło po cichu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-05 22:04:33 +02:00
parent 548d9301f3
commit 7266f671a4
18 changed files with 457 additions and 32 deletions
+16
View File
@@ -210,6 +210,22 @@ def build(report: dict, wheel_pdf: str | None = None,
parts.append(r"\end{tabular}")
parts.append(r"\vspace{1em}")
# ── 2a. ostrzeżenia o systemie domów ────────────────────────────────
# Muszą stać PRZED rysunkami: kosmogram narysowany po fallbacku wygląda
# bezbłędnie, więc jedyną informacją, że podział domów jest z innego systemu,
# jest ten akapit. W ramce, żeby nie dało się go wziąć za podpis.
warnings = [w for w in (report.get("warnings") or []) if str(w).strip()]
if warnings:
parts.append(r"\begin{center}")
parts.append(r"\fbox{\begin{minipage}{0.92\textwidth}\small")
for i, w in enumerate(warnings):
if i:
parts.append(r"\par\medskip")
parts.append(esc(str(w)))
parts.append(r"\end{minipage}}")
parts.append(r"\end{center}")
parts.append(r"\vspace{1em}")
# ── 3. rysunki kosmogramu ───────────────────────────────────────────
# Jedna reguła na wszystkie: keepaspectratio z limitem SZEROKOŚCI i WYSOKOŚCI.
# Koło i aspektarian są kwadratowe (ogranicza je wysokość), deklinacja i
+21
View File
@@ -307,3 +307,24 @@ def test_full_ai_markdown_leaves_no_visible_markers():
"###Podsekcja bez spacji\n\n- punkt **ważny**\n- i ***kluczowy***\n\n"
"#### Zamknięty ####")
assert _no_visible_markers(md(src))
def test_house_fallback_warning_lands_in_the_pdf():
"""Zasada projektu: co pokazujemy na stronie, trafia do raportu i PDF-a.
Po fallbacku systemu domów kosmogram wygląda bezbłędnie, więc ten akapit
jest JEDYNĄ informacją, że podział domów pochodzi z innego systemu, niż
zamówiono. Musi też stać PRZED rysunkami, nie po nich."""
tex = build({"person": "Jan Kowalski",
"data": {"date": "1984-04-30", "house_system": "porphyry"},
"warnings": ["UWAGA: system domów „placidus” nie ma definicji"]},
figures=[{"pdf": "wheel.pdf", "caption": "Kosmogram"}])
assert "fbox" in tex
assert "nie ma definicji" in tex
assert tex.index("nie ma definicji") < tex.index("wheel.pdf"), \
"ostrzeżenie musi stać przed rysunkami"
def test_no_warning_box_when_nothing_was_substituted():
tex = build({"person": "Jan Kowalski", "data": {}, "warnings": []})
assert "fbox" not in tex