86a0f16f9e
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m29s
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) Failing after 14s
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 10m29s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m28s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m29s
Testy / Build obrazu silnika B (swisseph) (push) Failing after 13s
Testy / Kontrola składni wszystkich warstw (push) Successful in 8s
Etap 0 planu egzotycznych systemów domów: zanim zaczniemy implementować Placidusa i spółkę, potrzebujemy narzędzia, które powie, czy wynik jest poprawny. Błąd w domach jest CICHY — wykres wygląda dobrze, tylko planety siedzą w złych domach. FRAMEWORK (tests/oracle): liczenie cuspów jako funkcja (RAMC, ε, φ), Swiss Ephemeris jako wyrocznia. Trzy decyzje projektowe, które okazały się kluczowe: - IZOLACJA: obu implementacjom podajemy TE SAME wejścia przez swe_houses_armc. Porównywanie „naszego horoskopu" z „horoskopem swissepha" mieszałoby różnice czasu gwiazdowego i ε z błędami domów — utonęlibyśmy w fałszywych alarmach. Czas gwiazdowy i ε mają własny test. - KRYTERIUM to liczba przypadków powyżej tolerancji (1″), max odchylenie I MIEJSCE, a nie procent zgodności. Procent ukrywa kształt błędu: „97%" nie odróżnia szumu zmiennoprzecinkowego od rogu dziedziny, w którym mylimy się o 30°. - GRANICE PER DATA: koło podbiegunowe nie jest stałą 66,56° — zależy od ε, które zmienia się z datą (23,75° w 370 p.n.e.), więc przesuwa się o ~0,3°. Uruchomiony na kodzie uchodzącym za poprawny, w PIERWSZYM przebiegu znalazł dwa realne błędy: 1. ASCENDENT O 180° ZA KOŁEM PODBIEGUNOWYM. `atan2` wybierał niewłaściwy punkt przecięcia ekliptyki z horyzontem — zwracaliśmy Descendent. Planety lądowały w PRZECIWNYCH domach dla całej północnej Skandynawii (Tromsø, Rovaniemi, Murmańsk), na ~11% przypadków przy tych szerokościach. Rozstrzyga położenie względem MC: punkt wschodzący leży w półkolu (0°,180°) na wschód od MC. 2. NIEDETERMINIZM WHOLE SIGN NA GRANICY ZNAKU. Ascendent o włos od granicy (359,999999999976 vs 1e-10 — ta sama wartość, różne strony) przerzucał dom I o 30°. Ten sam horoskop na innej maszynie dawał inny wynik. Przyciąganie do granicy przy 1e-9° (3,6 mikrosekundy łuku — poniżej realnej dokładności danych). Oba mają testy regresji w zwykłej suicie, więc są łapane też bez swissepha. Po poprawkach: build 0 przekroczeń, sweep 20 000 przypadków = 760 000 porównań, max odchylenie 0.000000000°. Istniejące suity bez regresji (logika 277+3, prez. 249). CI: krok BLOKUJĄCY w jobie swisseph-image, odpalany wewnątrz obrazu silnika B z zamontowaną warstwą logiczną. pyswisseph zostaje wyłącznie wyrocznią testową — nie wchodzi do zależności produktu, izolacja z LOG-27 nienaruszona. Dodane `cusps_for(ramc, eps, lat, system)` — kanoniczne wejście, w które Etap 1 będzie tylko dopisywał kolejne systemy. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
78 lines
3.1 KiB
Python
78 lines
3.1 KiB
Python
"""Testy osi i domów — czysta matematyka (LOG-05, bez efemeryd)."""
|
||
import pytest
|
||
|
||
from app.engine import houses as H
|
||
|
||
# RAMC i ε policzone Skyfieldem dla horoskopu referencyjnego (30.04.1984, Warszawa)
|
||
RAMC, EPS, LAT = 353.1968, 23.44133, 52.2333
|
||
|
||
|
||
def _near(a, b, tol=0.05):
|
||
return abs(((a - b + 180) % 360) - 180) < tol
|
||
|
||
|
||
def test_asc_mc_match_reference():
|
||
asc = H.compute_asc(RAMC, EPS, LAT)
|
||
mc = H.compute_mc(RAMC, EPS)
|
||
assert _near(asc, 112.18) # Cancer 22°10' (astro.com)
|
||
assert _near(mc, 352.59) # Pisces 22°35'
|
||
|
||
|
||
def test_whole_sign_starts_on_sign_boundary():
|
||
cusps = H.cusps(112.18, 352.59, H.WHOLE_SIGN)
|
||
assert cusps[0] == 90.0 # dom 1 = 0° Raka
|
||
assert cusps[1] == 120.0
|
||
|
||
|
||
def test_equal_cusps_are_30_apart_from_asc():
|
||
cusps = H.cusps(112.18, 352.59, H.EQUAL)
|
||
assert abs(cusps[0] - 112.18) < 1e-9
|
||
assert abs(cusps[1] - 142.18) < 1e-9
|
||
|
||
|
||
def test_porphyry_angles_on_cusps():
|
||
cusps = H.cusps(112.18, 352.59, H.PORPHYRY)
|
||
assert abs(cusps[0] - 112.18) < 1e-9 # Asc = dom 1
|
||
assert abs(cusps[9] - 352.59) < 1e-9 # MC = dom 10
|
||
assert abs(cusps[6] - (112.18 + 180) % 360) < 1e-9 # Dsc = dom 7
|
||
|
||
|
||
def test_assign_house_whole_sign():
|
||
cusps = H.cusps(112.18, 352.59, H.WHOLE_SIGN) # dom 1 = Rak (90–120°)
|
||
assert H.assign_house(100.0, cusps) == 1 # w Raku
|
||
assert H.assign_house(40.0, cusps) == 11 # Byk -> 11. dom
|
||
|
||
|
||
# ── regresje wykryte przez porównanie z wyrocznią (tests/oracle) ──────────
|
||
|
||
def test_ascendant_branch_beyond_polar_circle():
|
||
"""REGRESJA: powyżej koła podbiegunowego `atan2` wybierał NIEWŁAŚCIWY punkt
|
||
przecięcia ekliptyki z horyzontem — zwracaliśmy Descendent zamiast Ascendenta,
|
||
czyli błąd o 180°. Planety lądowały w PRZECIWNYCH domach dla całej północnej
|
||
Skandynawii. Rozstrzyga położenie względem MC: punkt wschodzący leży zawsze
|
||
w półkolu (0°,180°) na wschód od MC."""
|
||
eps = 23.4393
|
||
for lat in (67.0, 70.0, 85.0, -70.0):
|
||
for ramc in (60.0, 100.0, 200.0, 270.0, 300.0):
|
||
asc = H.compute_asc(ramc, eps, lat)
|
||
mc = H.compute_mc(ramc, eps)
|
||
offset = (asc - mc) % 360.0
|
||
assert 0.0 <= offset <= 180.0, (
|
||
f"Asc poza półkolem wschodzącym: lat={lat} ramc={ramc} offset={offset:.4f}")
|
||
|
||
|
||
def test_whole_sign_is_deterministic_at_sign_boundary():
|
||
"""REGRESJA: Ascendent o włos od granicy znaku (359,999999999976 vs 1e-10 —
|
||
ta sama wartość, różne strony) przerzucał cały dom I o 30°. Ten sam horoskop
|
||
na innej maszynie dawał inny wynik."""
|
||
below = H.cusps(359.999999999976, 270.0, H.WHOLE_SIGN)
|
||
above = H.cusps(1e-10, 270.0, H.WHOLE_SIGN)
|
||
assert below[0] == above[0] == 0.0, (below[0], above[0])
|
||
|
||
|
||
def test_polar_circle_moves_with_obliquity():
|
||
"""Granica dziedziny Placidusa/Kocha NIE jest stałą 66,56° — zależy od ε,
|
||
a ε zmienia się z datą. Testy brzegowe muszą ją liczyć per data."""
|
||
assert H.polar_circle(23.4393) == pytest.approx(66.5607, abs=1e-4) # dziś
|
||
assert H.polar_circle(23.747) == pytest.approx(66.253, abs=1e-4) # 370 p.n.e.
|