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
@@ -10,9 +10,9 @@
<div class="opts" title="Domy dzielą to samo niebo inaczej. Zaznacz kilka, by porównać kuspy obok siebie (PRE-05). Kosmogram rysuje system wybrany wyżej.">
{% set chosen = form.house_systems or [] %}
<span class="muted small">Porównaj systemy domów:</span>
<label><input type="checkbox" name="house_systems" value="whole_sign" {{ 'checked' if 'whole_sign' in chosen else '' }}> Whole Sign</label>
<label><input type="checkbox" name="house_systems" value="equal" {{ 'checked' if 'equal' in chosen else '' }}> Equal</label>
<label><input type="checkbox" name="house_systems" value="porphyry" {{ 'checked' if 'porphyry' in chosen else '' }}> Porphyry</label>
{% for value, name in HOUSE_SYSTEMS %}
<label><input type="checkbox" name="house_systems" value="{{ value }}" {{ 'checked' if value in chosen else '' }}> {{ name }}{{ ' *' if value in HOUSE_LIMITED else '' }}</label>
{% endfor %}
</div>
<div class="opts" title="Orb = dopuszczalne odchylenie od dokładnego kąta aspektu. „Bonus świateł" powiększa orb dla aspektów ze Słońcem/Księżycem. Aspekty poboczne: półsekstyl 30°, półkwadratura 45°, kwinkunks 150° (PRE-06).">
<label>Orb aspektów (°) <input type="number" name="aspect_orb" step="0.5" min="1" max="15" value="{{ form.aspect_orb if form.aspect_orb is not none else 8 }}"></label>
@@ -6,6 +6,14 @@
deklinacja/antyscja) renderuje rodzic; tu są same tabele. Każda sekcja pokazuje
się tylko, gdy jej dane są w wyniku (opcja policzona → sekcja jest). #}
{# Fallback systemu domów: system nie istniał dla tego miejsca i policzyliśmy
inny. Musi być WIDOCZNE, bo z samego wykresu tego nie da się poznać. #}
{% if result.house_warnings %}
{% for w in result.house_warnings %}
<p class="house-warning">{{ w }}</p>
{% endfor %}
{% endif %}
{% if result.angles %}
<table class="angles">
<thead><tr><th></th><th>Znak</th><th>W znaku</th></tr></thead>
@@ -20,10 +28,9 @@
{# Porównanie systemów domów (PRE-05) — te same osie, inny podział na domy #}
{% if result.house_systems and result.house_systems | length > 1 %}
{% set HSN = {'whole_sign': 'Whole Sign', 'equal': 'Equal', 'porphyry': 'Porphyry'} %}
<div class="meta" title="Osie (Asc/MC) są wspólne — różni się podział na domy. Kosmogram rysuje pierwszy z listy.">Porównanie systemów domów ({{ result.house_systems | length }})</div>
<table class="angles">
<thead><tr><th>Dom</th>{% for hs in result.house_systems %}<th>{{ HSN.get(hs.system, hs.system) }}</th>{% endfor %}</tr></thead>
<thead><tr><th>Dom</th>{% for hs in result.house_systems %}<th>{{ house_label(hs.system) }}</th>{% endfor %}</tr></thead>
<tbody>
{% for i in range(12) %}
<tr><td>{{ i + 1 }}</td>
@@ -219,7 +226,7 @@
{% if result.cusps %}
<details class="loc">
<summary>Cusps domów ({{ result.house_system }})</summary>
<summary>Cusps domów ({{ house_label(result.house_system) }})</summary>
<table>
<thead><tr><th>Dom</th><th>Znak</th><th>Cusp</th></tr></thead>
<tbody>
@@ -34,10 +34,11 @@
<label>System domów
<select name="house_system">
{% set hs = form.house_system or 'whole_sign' %}
<option value="whole_sign" {{ 'selected' if hs == 'whole_sign' else '' }}>Whole Sign</option>
<option value="equal" {{ 'selected' if hs == 'equal' else '' }}>Equal</option>
<option value="porphyry" {{ 'selected' if hs == 'porphyry' else '' }}>Porphyry</option>
{% for value, name in HOUSE_SYSTEMS %}
<option value="{{ value }}" {{ 'selected' if hs == value else '' }}>{{ name }}{{ ' *' if value in HOUSE_LIMITED else '' }}</option>
{% endfor %}
</select>
<span class="muted small" title="Placidus i Koch dzielą łuk dobowy, który powyżej koła podbiegunowego (ok. 66,5°) nie istnieje — dla takich miejsc policzymy Porphyry i wyraźnie o tym napiszemy.">* nie działa za kołem podbiegunowym</span>
</label>
<label>Zodiak
<select name="zodiac">
@@ -65,10 +66,14 @@
{% endif %}
{% if result %}
{# Fallback systemu domów — z kosmogramu nie da się go poznać, więc mówimy wprost #}
{% for w in result.house_warnings or [] %}
<p class="house-warning">{{ w }}</p>
{% endfor %}
<div class="meta">
Silnik: <strong>{{ result.engine }}</strong> ·
obiektów: {{ result.positions | length }}
{% if result.house_system %}· domy: {{ result.house_system }}{% endif %}
{% if result.house_system %}· domy: {{ house_label(result.house_system) }}{% endif %}
{% if result.zodiac %}· zodiak: {{ result.zodiac }}{% if result.ayanamsha is defined %} (ayanamsa {{ '%.4f'|format(result.ayanamsha) }}°){% endif %}{% endif %}
{% if moment %}· moment: {{ moment }}{% endif %}
</div>
@@ -39,10 +39,11 @@ zapamiętane predykcje okresowe. Dane pobiera z pozostałych zakładek — nie t
<label>System domów
<select name="house_system">
{% set hs = form.house_system or 'whole_sign' %}
<option value="whole_sign" {{ 'selected' if hs == 'whole_sign' else '' }}>Whole Sign</option>
<option value="equal" {{ 'selected' if hs == 'equal' else '' }}>Equal</option>
<option value="porphyry" {{ 'selected' if hs == 'porphyry' else '' }}>Porphyry</option>
{% for value, name in HOUSE_SYSTEMS %}
<option value="{{ value }}" {{ 'selected' if hs == value else '' }}>{{ name }}{{ ' *' if value in HOUSE_LIMITED else '' }}</option>
{% endfor %}
</select>
<span class="muted small" title="Placidus i Koch dzielą łuk dobowy, który powyżej koła podbiegunowego (ok. 66,5°) nie istnieje — dla takich miejsc policzymy Porphyry i wyraźnie o tym napiszemy.">* nie działa za kołem podbiegunowym</span>
</label>
<label>Zodiak
<select name="zodiac">