moira

Moira Validation Report - Astrology

Version: 1.4 Date: 2026-05-21 Runtime target: Python 3.14 Validation philosophy: external astrology software where stable and meaningful; canonical formulas and doctrine tables where no stable oracle exists; Moira as regression baseline once behavior is validated


1. Executive Statement

This document covers the astrological convention layer of Moira: techniques that are built on top of the astronomy engine but involve definitional choices specific to astrological tradition.

The validation standard here differs from the astronomy layer:

1.1 Current Rerun Receipt

On 2026-05-21, the full astrology validation corpus named in this document was re-run from the project .venv.

Current corpus result:

The one skip is expected:

The house validator script was also re-run successfully:

This rerun receipt supersedes older point-in-time counts recorded earlier in the paper.


2. Validation Surface

Domain Oracle / basis Enforcement Status
Sidereal systems / ayanamshas (34 systems) Astro.com swetest offline fixture pytest Validated (49 current pytest cases; 31 Swiss-mapped systems plus invariants for the remainder)
House systems (15 systems, 7416 iterations) Swiss setest/t.exp offline fixture pytest + validator script Validated (65 current pytest cases + 7416-iteration offline validator)
Aspects (major, tight-orb) Horizons-validated position substrate + angular-distance geometry pytest Validated (unit + integration; 1 expected fixture skip at J1900)
Antiscia / contra-antiscia Formula derivation + invariants (Valens, Lilly) pytest Validated
Midpoints Formula derivation + invariants (Ebertin, Witte) pytest Validated
Lots / Arabic Parts Formula derivation, day/night reversal (Paulus, Valens) pytest Validated
Dignities Essential table lookups, accidental scoring (Lilly, Ptolemy) pytest Validated
Harmonics Formula derivation + round-trip invariant (Addey) pytest Validated
Profections Annual/monthly arithmetic, 12-year cycle (Brennan, Valens) pytest Validated
Planetary hours Chaldean sequence + day-ruler derivation (Porphyry, Hephaestio) pytest Validated
Secondary progressions Offline Swiss swetest fixture at progressed dates + doctrine validation pytest Validated
Solar arc directions Offline Swiss swetest fixture for arc and directed longitudes + doctrine validation pytest Validated
Primary directions Placidus speculum doctrine, arc algebra, and symbolic time-key validation pytest Validated
Dashas Canonical Vimshottari doctrine: nakshatra entry, proportional hierarchy, ayanamsa/year-basis settings pytest Validated
Parans Horizons-derived offline paran fixture + validated event substrate + paran logic tests pytest Validated
Gauquelin sectors Canonical diurnal-arc formula + plus-zone invariants (Gauquelin) pytest Validated
Manazil / lunar mansions Equal-station arithmetic + canonical boundary assignments (al-Biruni) pytest Validated
Timelords (Firdaria / Zodiacal Releasing) Canonical tables, structural invariants, and doctrine validation pytest Validated

Status language in this table is intentional:

2.1 Python vs C++ Route Semantics

This paper validates the Python public route unless a section explicitly states otherwise.

That distinction matters because Moira’s current native backend is a dual-substrate system, not a second independent doctrine authority.

Current route law:

Time semantics differ by route:

Validation consequence:

Concrete current examples from the validation corpus:

Current native parity note:


3. Sidereal Systems

Oracle: Official Astro.com swetest CGI output, captured offline Fixture: tests/fixtures/sidereal_swetest_reference.json Thresholds:

Test file: tests/integration/test_sidereal_external_reference.py

34 ayanamsha systems are exposed. 31 have direct Swiss-mappable fixture data. 2 systems are permanently excluded from the Swiss fixture:

Validated systems include Lahiri, Fagan-Bradley, Krishnamurti, Raman, Yukteshwar, Djwhal Khul, Hipparchos, Suryasiddhanta, Aryabhata, SS Revati, SS Citra, True Chitrapaksha, True Revati, True Pushya, Aldebaran (15 Tau), Babylonian variants, Galactic Center (0 Sag), Galactic Center (Cochrane), Galactic Center (RGB), and others.

The current external-reference sidereal file contains 49 pytest cases, all passing on the 2026-05-21 rerun.

Route note:

3.1 Star-Anchored True Ayanamsa Model-Basis Difference

Five systems (True Chitrapaksha, True Revati, Aldebaran (15 Tau), True Pushya, True Mula) compute the ayanamsa from the live tropical longitude of a reference star rather than a polynomial formula. Because Moira uses IAU 2006 Fukushima-Williams precession while Swiss Ephemeris uses an older precession model, and because Moira’s star pipeline does not include annual aberration (~20.5” maximum effect), a systematic residual exists between Moira and Swiss for these systems:

System Anchor star Residual envelope Dominant cause
True Chitrapaksha Spica 5-19” Annual aberration (~20.5”)
True Pushya delta Cancri 12-18” Aberration + proper motion
True Revati zeta Piscium 5-20” Aberration + proper motion
Aldebaran (15 Tau) Aldebaran 91-109” High proper motion (-189 mas/yr dec) + precession model

These residuals are model-basis differences where Moira’s IAU 2006 pipeline is the stronger model. The 126” threshold envelope accommodates the worst case (Aldebaran at historical epochs). Mean-mode results for the same systems pass at the standard 3.6” threshold because mean mode uses polynomial formulas calibrated to Swiss.

Fixes applied 2026-04-05:


4. House Systems

Primary proof: Moira-owned geometric and structural covenant suites
Secondary oracle: Official Swiss Ephemeris setest/t.exp
Fixture: tests/fixtures/swe_t.exp
Threshold: 0.001 degrees (3.6 arcseconds)
Test files:

15 house systems are validated: Placidus, Koch, Campanus, Regiomontanus, Porphyry, Equal, Whole Sign, Alcabitius, Morinus, Topocentric, Vehlow, Meridian, Azimuthal, Krusinski-Pisa, APC.

Current rerun standing for the house layer:

Validation order is doctrinally explicit:

4.1 Corpus composition

The Swiss setest/t.exp fixture contains 12,757 raw ITERATION blocks across six test sections. After analysis, the 7,416 validated iterations are drawn from two distinct calling conventions:

Source Blocks API exercised Notes
Standard tropical (no flag / iflag=0) 3,888 swe_houses() + swe_houses_ex(iflag=0) Degree output, tropical; iflag=0 is equivalent to no flag
ARMC-direct 3,528 swe_houses_armc() ARMC supplied directly from fixture; obliquity computed independently by Moira
Total 7,416   All pass at 3.6” threshold

The remaining 5,341 blocks are excluded for documented reasons:

Category Count Reason
iflag=8192 (radians output) 720 Swiss returns cusps in radians under this flag; same computation, different units - excluded by design
Sidereal (iflag=65536 + isid) 1,080 Requires ayanamsa-adjusted house computation; see section 4.3
swe_house_pos() blocks 1,536 Single-point house membership query, no cusp array
Unsupported system (G) 312 Not mapped in Moira’s HouseSystem constants
Missing coordinates 18 Incomplete fixture records
Total excluded 5,341  

Stress cases covered across all 7,416 validated iterations:

Two systems (Azimuthal, APC) were found genuinely wrong during earlier validation and corrected. All 7,416 iterations now pass.

4.2 ARMC-direct validation

The 3,528 ARMC-direct blocks exercise houses_from_armc() - Moira’s equivalent of Swiss swe_houses_armc(). In these blocks the fixture supplies the ARMC value directly (degrees) rather than deriving it from a Julian date and geographic longitude. Moira computes obliquity independently from the block’s JD_UT via its own TT conversion and IAU 2006 pipeline.

This makes ARMC-direct validation a clean regression-oracle test: given the exact ARMC that Swiss used, do Moira’s house cusp algorithms still produce the same 12 cusp longitudes? Any residual here is attributable solely to the cusp computation itself, not to ARMC derivation. All 3,528 pass at 3.6”.

4.3 Sidereal house blocks - residual audit

The 1,080 sidereal blocks (iflag=65536, isid in {0, 18, 27}) were audited but not included in the passing test surface. The residuals are entirely in ayanamsa computation, not in house cusp geometry. When Swiss’s ARMC is supplied directly and Moira’s ayanamsa is applied, all discrepancy traces to the ayanamsa value alone.

isid System Moira constant Ayanamsa diff at 2013 House cusp residual Category
0 Fagan-Bradley Ayanamsa.FAGAN_BRADLEY +1.24” 1.24” max Precession rate
27 True Chitrapaksha Ayanamsa.TRUE_CHITRAPAKSHA -9.71” 10.0” max Precession rate + absent aberration
18 J2000 None - - No Moira constant

Fagan-Bradley (+1.24”): This is not a calibration offset. Decomposition shows:

The Moira J2000 anchor was calibrated against Swiss at J2000 (difference is 0.018”). The growing component is the precession rate difference between Moira’s IAU 2006 Fukushima-Williams model and Swiss Ephemeris’s older model. At J2000 the total residual is about 0.02”; at 13 years it is 1.24”; projected to 100 years it reaches about 9.3” in magnitude. This is not fixable by adjusting the J2000 anchor - the source is the precession rate, not the epoch value.

True Chitrapaksha (-9.71”): Same IAU 2006 vs Swiss precession rate difference applies (~0.09”/year), but the dominant source is Moira’s fixed-star pipeline not including annual aberration (~20.5” maximum effect). The anchor star Spica’s apparent position differs between Moira and Swiss by the aberration amount. This matches the documented residual envelope already recorded in section 3.1 for star-anchored ayanamsas.

Conclusion: Both residuals arise from the same root cause - Moira’s stronger IAU 2006 precession substrate produces ayanamsa values that diverge from Swiss as epochs depart from J2000, with star-anchored systems carrying an additional aberration contribution. Neither is a calibration error. Neither is fixable without downgrading the precession model. The house cusp computation itself is correct; the residual lives entirely in the ayanamsa layer.

isid=18 (J2000 ayanamsa): Swiss SE_SIDM_J2000 anchors the tropical and sidereal zodiacs to coincide at J2000.0, accumulating purely from precession thereafter. Moira does not yet have a corresponding constant. If added, it would carry the same precession rate residual as Fagan-Bradley (~0.09”/year), since the J2000 anchor would be exact by construction. since the J2000 anchor would be exact by construction.


5. Aspects

Validation layers:

Fixture: tests/fixtures/aspects_reference.json
Generated by: scripts/build_aspects_fixture.py
Threshold: 1e-6 degrees
Test file: tests/integration/test_aspects_external_reference.py
Aspect tier: major aspects only
Tight-orb window: 1.0 degree
Epochs: J1900, J1950, J2000, J2024
Bodies: 10 major bodies (Sun through Pluto)

Minor aspects remain covered by the larger unit suite in tests/unit/test_aspects.py.

Current rerun standing:


6. Rule-Engine Validation

Primary test file: tests/unit/test_rule_engine_validation.py

The following modules are pure arithmetic / rule-table engines with no ephemeris dependency. Their validation is therefore formula-derivation and invariant-based rather than external-oracle comparison.

6.1 Antiscia and Contra-antiscia

Canon: Vettius Valens, Anthology II.37; William Lilly, Christian Astrology (1647) p. 90
Formula: antiscion = (180 - lon) mod 360; contra = (360 - lon) mod 360
Validation: hand-derived reference table, round-trip invariants, contact detection, and seam-edge cases

6.2 Midpoints

Canon: Reinhold Ebertin, The Combination of Stellar Influences (1940); Alfred Witte, Rules for Planetary Pictures
Formula: shorter-arc midpoint; 90-degree dial projection
Validation: hand-derived midpoint table, commutativity, self-midpoint, pair-count, sort-order, and seam-crossing invariants

6.3 Profections

Canon: Chris Brennan, Hellenistic Astrology (2017), Ch. 9; Vettius Valens, Anthology, Book IV
Formula: profected ASC = (natal_asc + age * 30) mod 360; house = (age mod 12) + 1
Validation: hand-derived table across ages 0-30, house-range guard, monthly-lord length and first-lord invariants, and 12-year cycle identity

6.4 Planetary Hours

Canon: Porphyry, Introduction to Tetrabiblos; Hephaestio of Thebes, Apotelesmatika I
Validation: Chaldean sequence, weekday day-ruler mapping, first night-hour derivation, 24-hour completeness, and the next-day +3 shift invariant

6.5 Harmonics

Canon: John Addey, Harmonics in Astrology (1976)
Formula: harmonic longitude = (natal_lon * H) mod 360
Validation: hand-derived table, H1 identity, output-range invariant, sorting, and harmonic-number clamping

6.6 Lots / Arabic Parts

Canon: Paulus Alexandrinus, Introductory Matters; Vettius Valens, Anthology Books II-IV
Formula: ASC + Add - Sub modulo 360, with night reversal where doctrine requires it
Validation: Fortune and Spirit day/night formulas, range guards, and the Fortune/Spirit complement invariant

6.7 Dignities

Canon: William Lilly, Christian Astrology Book I; Ptolemy, Tetrabiblos I.17-22
Validation: essential dignity cases, accidental scoring bands, retrograde penalties, cazimi / combust boundaries, mutual reception, total-score invariant, traditional sort order, sect-light logic, and hayz conditions


7. Predictive and Extended Technique Validation

The techniques below are not correctly described as “untested.” They already have real validation surfaces. The distinction is whether that surface is a finished external-oracle comparison or a strong internal / doctrinal pass.

7.1 Secondary Progressions and Solar Arc Directions

Current validation surface: tests/unit/test_moira_progressions.py, tests/unit/test_progressions_public_api.py, tests/integration/test_progressions_external_reference.py
Backend standard: moira/docs/PROGRESSIONS_BACKEND_STANDARD.md

What is already validated:

What is not yet externally validated:

Fixture: tests/fixtures/progressions_swetest_reference.json
Builder: scripts/build_progressions_swetest_fixture.py
Threshold: 1.0 arcsecond

Status: externally validated for planetary positions and solar-arc values against offline Swiss references; angle-specific extensions remain desirable.

7.2 Dashas

Current validation surface: tests/unit/test_dasha.py
Backend standard: moira/docs/DASHA_BACKEND_STANDARD.md

What is already validated:

Research conclusion:

Oracle harness now present:

Reference doctrine adopted for Moira validation:

Status: validated against doctrine and invariants. External Vedic software comparison is optional supplemental cross-checking, not a prerequisite for claiming a truthful validation story.

7.3 Primary Directions

Current validation surface: tests/unit/test_primary_directions.py

What is now validated:

Status:

7.4 Parans

Current validation surface: tests/unit/test_parans.py, tests/integration/test_parans_external_reference.py
Backend standard: moira/docs/PARANS_BACKEND_STANDARD.md

What is already validated:

Fixture: tests/fixtures/parans_horizons_reference.json
Builder: scripts/build_parans_horizons_fixture.py

Status: validated against an external event oracle for curated paran cases, plus the existing internal coverage for matching, policy, and field behavior.

7.5 Gauquelin Sectors

Current validation surface: tests/unit/test_experimental_validation.py, tests/unit/test_session_fixes.py, tests/integration/test_gauquelin_external_reference.py

Validated against the canonical diurnal-arc sector model:

This technique is already validated and should not be described as merely “mentioned.”

7.6 Manazil / Lunar Mansions

Current validation surface: tests/unit/test_experimental_validation.py

Validated as canonical equal-station arithmetic:

This is a real validation pass for the current doctrine. A future comparison to published mansion tables would be supplemental, not the first validation.

7.7 Timelords (Firdaria and Zodiacal Releasing)

Current validation surface: tests/unit/test_timelords.py and moira/docs/VALIDATION_EXPERIMENTAL.md

What is already validated:

Status: validated against doctrine and invariants. External software comparison may still be useful as supplemental cross-checking.


8. Supplemental Validation Expansion Roadmap

8.1 Aspects

Recommended oracle: Astro.com chart output or Solar Fire
Threshold: 0.001 degrees

Useful next checks:

8.2 Primary Directions

The current Placidus mundane implementation is now doctrine-validated.

Useful supplemental expansion:

8.3 Secondary Progressions

External oracle coverage is already in place via the offline Swiss swetest fixture in tests/fixtures/progressions_swetest_reference.json.

Useful supplemental expansion:

8.4 Solar Arc Directions

External oracle coverage is already in place for solar-arc values and directed planetary longitudes via the offline Swiss swetest fixture.

Useful supplemental expansion:

8.5 Dashas

External-software comparison for Vimshottari is now treated as supplemental, not foundational.

If performed, it must declare at minimum:

Useful supplemental checks:

Implementation note:

8.6 Parans

The subsystem is now externally anchored through Horizons-derived event timing for curated paran cases.

Useful supplemental expansion:

8.7 Manazil / Lunar Mansions

Recommended oracle: published lunar-mansion tables (Ibn Arabi, Picatrix, al-Biruni variants as implemented)

What to validate:


9. Astrology Validation Status

Domain Current state Recommended oracle Priority
House corpus expansion Closed, re-verified 2026-05-21. Standard tropical blocks remain 3,888, ARMC-direct blocks remain 3,528, and the validated Swiss-derived house corpus remains 7,416 iterations total. The current pytest surface for houses is 65 passing cases across geometry, branch doctrine, public fallback behavior, and external-reference slices. Sidereal house residuals remain classified as ayanamsa-layer model-basis differences, not cusp-computation defects. Swiss setest/t.exp Closed
Sidereal true-ayanamsa target fixes Closed, re-verified 2026-05-21. TRUE_REVATI remains corrected from 0 deg to 359 deg 50 min and TRUE_PUSHYA remains corrected from 106.667 deg to 106 deg. Residuals remain in the documented 5-20 arcsecond envelope and are still classified as model-basis differences between Moira’s IAU 2006 path and Swiss. Astro.com swetest Closed
Sidereal fixture coverage gap Closed, re-verified 2026-05-21. The current offline sidereal corpus still covers 31 Swiss-mapped systems, with Aryabhata 522 and GALEQU_IAU1958 remaining intentionally excluded for stated methodological reasons. The live integration file now collects 49 cases, all passing on rerun. Astro.com swetest Closed
Aspects integration fixture Closed, re-verified 2026-05-21. aspects_reference.json remains anchored to Horizons-validated positions across four epochs. The current integration file collects 10 cases: 9 pass and the J1900 no-tight-orb case remains the one expected skip. Horizons-validated substrate Closed
Vimshottari integration fixture Closed, re-verified 2026-05-21. The manual-oracle corpus still contains the three declared Lahiri plus Julian-year reference cases, and the current integration file still collects 4 passing cases. Doctrine validation remains the primary proof surface because no single Swiss-like external authority exists for Vimshottari without first fixing settings. Doctrinal self-consistency Closed
Python versus native route semantics Partially closed, re-verified 2026-05-21. Astrology validation claims in this paper remain anchored to the Python public/reference route, and native C++ is still not treated as a second astrology-doctrine authority. However, the specific native calendar_from_jd() parity defect on historical/proleptic Gregorian cases has been corrected, and tests/test_native_parity.py now passes on the previously failing boundary samples. Broader route-authority separation remains intentional doctrine, not an unresolved bug. Python public route plus native parity audit Intentional