Firdaria (LOG-11) — perska technika time-lord

- engine/firdaria.py: sekta (dzień = Słońce nad horyzontem, ta sama półkula
  osi Asc-Dsc co MC); kolejność diurnalna/nokturnalna; klasyczne długości
  okresów (Su10 Ve8 Me13 Mo9 Sa11 Ju12 Ma7 + NN3 + SN2 = 75 lat); okresy główne
  planet dzielone na 7 podokresów (sub-lord od władcy okresu), węzły bez sub.
- endpoint /chart/firdaria.
- oś czasu: firdaria_events — starty (pod)okresów w oknie; wpięte w build_timeline
  (domyślnie) + tokeny [major][sub] do dopięcia interpretacji (1B->2B).

Walidacja:
- sekta = day dla horoskopu referencyjnego (zgodnie z notes3 "Day birth");
  night gdy Słońce po stronie IC; sumy i przyleganie okresów; podokresy 7x
  sumujące się do okresu; wiek 42 w okresie Saturna.
- E2E: okresy Sun 1984-1994 ... Saturn 2024-2035; w osi czasu
  "Firdaria: Saturn / Mars" 2027 -> 223 interpretacje ([Sa+[Ma -> "injury").
- 78 testów przechodzi (nowy test_firdaria).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 22:48:53 +02:00
parent cff0ac194c
commit 9d5b65ddbd
6 changed files with 172 additions and 2 deletions
+57
View File
@@ -0,0 +1,57 @@
"""Firdaria (LOG-11) — perska technika time-lord.
Sekwencja okresów głównych zależy od sekty (dzień/noc). Sekta: urodzenie dzienne,
gdy Słońce jest nad horyzontem, czyli po tej samej stronie osi AscDsc co MC.
Klasyczne długości okresów (lata): Su 10, Ve 8, Me 13, Mo 9, Sa 11, Ju 12, Ma 7
(razem 70) + Węzeł Północny 3 + Węzeł Południowy 2 = 75 lat. Każdy okres główny
planety dzieli się na 7 podokresów (sub-lord w tej samej kolejności, cyklicznie).
Węzły — bez podokresów (najczęstsza konwencja).
"""
from __future__ import annotations
from datetime import datetime, timedelta
DAY_ORDER = ["Sun", "Venus", "Mercury", "Moon", "Saturn", "Jupiter", "Mars"]
NIGHT_ORDER = ["Moon", "Saturn", "Jupiter", "Mars", "Sun", "Venus", "Mercury"]
YEARS = {"Sun": 10, "Venus": 8, "Mercury": 13, "Moon": 9,
"Saturn": 11, "Jupiter": 12, "Mars": 7}
NODES = [("North Node", 3), ("South Node", 2)]
DAYS_PER_YEAR = 365.2422
def is_day_birth(sun_lon: float, asc: float, mc: float) -> bool:
"""Słońce nad horyzontem = ta sama półkula osi AscDsc co MC."""
return (((sun_lon - asc) % 360.0) < 180.0) == (((mc - asc) % 360.0) < 180.0)
def _date(birth: datetime, years: float) -> str:
return (birth + timedelta(days=years * DAYS_PER_YEAR)).date().isoformat()
def firdaria(birth: datetime, sun_lon: float, asc: float, mc: float) -> dict:
"""Pełny rozkład Firdarii: sekta, kolejność, okresy główne i podokresy."""
day = is_day_birth(sun_lon, asc, mc)
order = DAY_ORDER if day else NIGHT_ORDER
majors = [(lord, YEARS[lord]) for lord in order] + NODES
periods: list[dict] = []
age = 0.0
for lord, yrs in majors:
period = {"lord": lord, "years": yrs,
"start": _date(birth, age), "end": _date(birth, age + yrs)}
if lord in YEARS: # planeta -> 7 podokresów
sub_len = yrs / 7.0
i = order.index(lord)
sub_age = age
subs: list[dict] = []
for k in range(7):
sub_lord = order[(i + k) % 7]
subs.append({"lord": sub_lord,
"start": _date(birth, sub_age),
"end": _date(birth, sub_age + sub_len)})
sub_age += sub_len
period["sub"] = subs
periods.append(period)
age += yrs
return {"sect": "day" if day else "night", "order": order, "periods": periods}