NINE_PARTS_BACKEND_STANDARD - TheDaniel166/moira GitHub Wiki
Nine Parts Backend Standard
Subsystem: moira/nine_parts.py
Computational Domain: Abu Ma'shar's Nine Hermetic Lots
Constitutional Phase: 11 — Architecture Freeze and Validation Codex
Status: Constitutional
Part I — Architecture Standard
§1. Computational Definition
§1.1 What the Nine Parts Are
The Nine Parts are Abu Ma'shar's expansion of the classical Hermetic Lots into a system of nine: seven lots associated with the seven classical planets, plus two nodal lots (the Part of the Sword and the Part of the Node). Each lot is computed as a directed arc from one chart body to another, projected from the Ascendant.
Doctrine basis: Abu Ma'shar, Kitāb taḥāwil sinī al-mawālīd. Confirmed formulas and reversal rule: Benjamin N. Dykes, Introductions to Traditional Astrology (Cazimi Press, 2010) and Persian Nativities Vol. II (Cazimi Press, 2010).
This subsystem is not the Hellenistic nonomoiria (9-fold sign subdivision)
and is not the Vedic Navamsha (D9 chart). The Vedic Navamsha is handled by
moira/varga.py. The Hellenistic nonomoiria is not currently implemented.
§1.2 Formula Table
All nine parts use the formula: Longitude = (Asc + Add − Sub) mod 360°
| # | Part | Planet | Day Add | Day Sub |
|---|---|---|---|---|
| 1 | Fortune | Moon | Moon | Sun |
| 2 | Spirit | Sun | Sun | Moon |
| 3 | Love | Venus | Spirit | Fortune |
| 4 | Necessity | Mercury | Fortune | Spirit |
| 5 | Courage | Mars | Fortune | Mars |
| 6 | Victory | Jupiter | Jupiter | Spirit |
| 7 | Nemesis | Saturn | Fortune | Saturn |
| 8 | Sword | — | Mars | Saturn |
| 9 | Node | — | North Node | Moon |
Parts 3 (Love), 4 (Necessity), and 6 (Victory) are derived: their formula ingredients include other computed lots (Fortune and/or Spirit), not only raw planet longitudes. The engine computes Fortune and Spirit first; derived parts are computed after.
§1.3 Night Reversal Rule
Abu Ma'shar applies full reversal for all nine parts for night charts. For night charts, the Add and Sub operands are swapped:
Night formula: Longitude = (Asc + Day_Sub − Day_Add) mod 360°
Night definition: the chart is nocturnal when the Sun is in houses 1–6
(below the horizon). The caller supplies is_night_chart: bool; the engine
does not determine sect independently.
No per-lot exceptions. The full reversal applies to all nine parts uniformly. This is the Abu Ma'shar standard confirmed by Dykes. Some medieval editors stopped reversing the Part of Fortune following a misreading of Ptolemy; this engine does not follow that error.
§1.4 Dependency Order
Step 1: Fortune (raw: Moon, Sun)
Spirit (raw: Sun, Moon)
Step 2: Love (derived: Spirit, Fortune)
Necessity (derived: Fortune, Spirit)
Courage (raw: Fortune [computed], Mars)
Victory (derived: Spirit [computed], Jupiter)
Nemesis (raw: Fortune [computed], Saturn)
Sword (raw: Mars, Saturn)
Node (raw: North Node, Moon)
The engine enforces this order internally. Callers do not control computation order.
§2. Public API
§2.1 Primary Entry Point
def nine_parts_abu_mashar(
asc: float,
planets: dict[str, float],
is_night_chart: bool,
policy: NinePartsPolicy = DEFAULT_NINE_PARTS_POLICY,
) -> NinePartsAggregate
Parameters:
| Parameter | Type | Description |
|---|---|---|
asc |
float |
Ascendant longitude in degrees [0, 360) |
planets |
dict[str, float] |
Planet name → longitude mapping |
is_night_chart |
bool |
True when Sun is in houses 1–6 |
policy |
NinePartsPolicy |
Doctrinal configuration |
Required planet keys: Sun, Moon, Mars, Jupiter, Saturn,
North Node.
Returns: NinePartsAggregate — complete result with all parts, dependency
relations, per-part condition profiles, and aggregate intelligence.
Raises: KeyError if a required planet key is missing; ValueError if
any longitude is non-finite.
§2.2 Validation Entry Point
def validate_nine_parts_output(aggregate: NinePartsAggregate) -> list[str]
Returns a list of failure strings. An empty list confirms full consistency. See §4 (Validation Codex) for the complete check list.
§3. Type Surface
§3.1 Classification Namespaces
| Type | Values | Purpose |
|---|---|---|
NinePartName |
FORTUNE … NODE |
Canonical Abu Ma'shar part names |
NinePartFormulaVariant |
DAY, NIGHT |
Which formula column was applied |
NinePartDependencyKind |
DIRECT, DERIVED |
Whether the formula uses other lots |
NinePartsReversalRule |
FULL_REVERSAL |
Only admitted reversal doctrine |
§3.2 Policy Surface
@dataclass(frozen=True)
class NinePartsPolicy:
reversal_rule: NinePartsReversalRule = NinePartsReversalRule.FULL_REVERSAL
DEFAULT_NINE_PARTS_POLICY is the module-level default instance.
The only admitted reversal rule is FULL_REVERSAL. No other option is
historically supported for the Abu Ma'shar Nine Parts system.
§3.3 Truth-Preservation Vessel — NinePartComputationTruth
Preserved per part. Records every operand and decision made during formula evaluation.
| Field | Type | Description |
|---|---|---|
asc_longitude |
float |
Ascendant used for projection |
add_key |
str |
Add operand key (after reversal) |
sub_key |
str |
Sub operand key (after reversal) |
add_longitude |
float |
Resolved longitude of add operand |
sub_longitude |
float |
Resolved longitude of sub operand |
is_night_chart |
bool |
Whether chart was nocturnal |
formula_reversed |
bool |
Whether night reversal was applied |
formula_variant |
NinePartFormulaVariant |
DAY or NIGHT |
formula |
str |
Human-readable formula string |
Invariant: formula_reversed implies is_night_chart. formula_variant
is NIGHT iff formula_reversed is True. formula must equal
f"Asc + {add_key} − {sub_key}".
§3.4 Primary Result Vessel — NinePart
| Field | Type | Description |
|---|---|---|
name |
NinePartName |
Canonical name |
planet_association |
str | None |
Associated planet; None for Sword and Node |
meaning |
str |
Brief interpretive domain |
longitude |
float |
Computed longitude [0, 360) |
sign |
str |
Sign name |
sign_degree |
float |
Degree within sign [0, 30) |
sign_symbol |
str |
Glyph character |
dependency_kind |
NinePartDependencyKind |
DIRECT or DERIVED |
computation |
NinePartComputationTruth |
Full computation audit trail |
Invariants: longitude in [0, 360); sign_degree in [0, 30);
sign matches sign_of(longitude).
Phase 3 properties:
| Property | Returns | Description |
|---|---|---|
is_derived |
bool |
True when dependency_kind is DERIVED |
is_nocturnal_formula |
bool |
True when night formula was used |
has_planet_association |
bool |
False only for Sword and Node |
degrees_in_sign |
int |
Whole degrees in sign |
minutes_in_sign |
int |
Arc minutes within whole degree |
§3.5 Relational Vessel — NinePartsDependencyRelation
| Field | Type | Description |
|---|---|---|
part |
NinePartName |
The part whose dependency is described |
lot_dependencies |
tuple[NinePartName, ...] |
Lots this formula depends on |
Invariant: lot_dependencies must match the canonical dependency list for
the named part. Empty for direct parts.
Properties: is_direct (no lot dependencies), dependency_count.
§3.6 Relational Group Vessel — NinePartsSet
| Field | Type | Description |
|---|---|---|
parts |
list[NinePart] |
Nine parts in canonical order |
is_night_chart |
bool |
Sect of the chart |
policy |
NinePartsPolicy |
Policy used |
dependency_relations |
list[NinePartsDependencyRelation] |
One per part |
Invariants: exactly 9 parts; exactly 9 dependency relations; all parts
share the same is_night_chart.
Methods: get(name), get_dependency_relation(name).
Phase 6 properties: direct_parts, derived_parts,
nocturnal_formula_count, planetary_parts, nodal_parts.
§3.7 Condition Vessel — NinePartConditionProfile
| Field | Type | Description |
|---|---|---|
part |
NinePart |
The part |
dependency_relation |
NinePartsDependencyRelation |
Dependency relation |
lord |
str |
Traditional domicile ruler of the part's sign |
lord_is_part_planet |
bool |
True when lord == part's planet association |
Invariant: lord must match _SIGN_RULER[part.sign].
Properties: is_in_own_sign, is_derived.
§3.8 Aggregate Vessel — NinePartsAggregate
| Field | Type | Description |
|---|---|---|
parts_set |
NinePartsSet |
Complete parts set |
condition_profiles |
list[NinePartConditionProfile] |
9 profiles |
policy |
NinePartsPolicy |
Policy used |
Invariant: exactly 9 condition profiles.
Properties: parts_in_own_sign, unique_lords, dominant_lord.
Methods: get_profile(name).
§4. Validation Codex
validate_nine_parts_output(aggregate) checks:
| # | Check | Failure example |
|---|---|---|
| 1 | Exactly 9 parts | "Expected 9 parts, found 8" |
| 2 | Parts in canonical order | "Part 2: expected LOVE, got COURAGE" |
| 3 | Night consistency across parts | "Fortune: is_night_chart mismatch" |
| 4 | formula_reversed matches night flag | "Fortune: formula_reversed=False but is_night_chart=True" |
| 5 | Derived parts follow their dependencies | "Love appears before its dependency Spirit" |
| 6 | DERIVED classification on derived parts | "Love: dependency_kind should be DERIVED" |
| 7 | DIRECT classification on direct parts | "Fortune: dependency_kind should be DIRECT" |
| 8 | Longitudes finite and in [0, 360) | "Fortune: longitude 361.0 not in [0, 360)" |
| 9 | sign_degree in [0, 30) | "Fortune: sign_degree 30.0 not in [0, 30)" |
| 10 | Sign names match longitudes | "Fortune: sign 'Aries' does not match sign_of(…)" |
| 11 | Lord assignments match sign rulers | "Fortune: lord 'Sun' does not match sign ruler for 'Cancer'" |
| 12 | Exactly 9 condition profiles | "Expected 9 condition profiles, found 8" |
| 13 | Exactly 9 dependency relations | "Expected 9 dependency relations, found 7" |
§5. Doctrine Boundaries
§5.1 What This Module Owns
- The Nine Parts formula catalogue for the Abu Ma'shar tradition
- Night reversal logic (FULL_REVERSAL)
- Dependency ordering enforcement (Fortune/Spirit before derived lots)
- Result vessels through all constitutional process layers
- Lord-of-the-part assignment (traditional domicile rulers only)
§5.2 What This Module Does Not Own
- Night determination (caller supplies
is_night_chart) - House calculation or Ascendant computation
- Solar return chart construction
- Al-Sijzi Transfer of Management mechanics (Phase 2, not yet implemented)
- Vedic Navamsha (handled by
moira/varga.py) - Hellenistic nonomoiria (not yet implemented)
- The Part of Fortune used elsewhere in Moira (e.g. in
lots.pyorlongevity.py) is not governed by this module; each subsystem owns its own Fortune computation
§5.3 Admitted Doctrine
- Abu Ma'shar, full-reversal variant only
- Traditional (pre-modern) domicile rulers (no outer planets)
- Egyptian bounds and Dorothaean triplicity rulers are not used in this module; the lord-of-the-part assignment uses domicile only
§5.4 Deferred Doctrine (Not Yet Implemented)
- Al-Sijzi Transfer of Management: itissāl chain of the lot lord, tasyīr profection of the part through bounds (Phase 2)
- The intersection with
longevity.pyfor the Part-based Hyleg refinement (Phase 2 interface design required before implementation)
Part II — Implementation Notes
§6. Module Location
moira/nine_parts.py — standalone module, not part of lots.py.
Rationale: the Nine Parts are a specific named doctrinal system (Abu Ma'shar),
not a generic lot catalogue entry. Keeping them separate prevents confusion
with the ~430-entry PARTS_DEFINITIONS catalogue and makes the doctrinal
scope explicit.
§7. Relation to lots.py
The nine_parts_abu_mashar() engine does not call lots.py internally. It
reimplements the arc formula (Asc + A − B mod 360°) directly for the nine
parts, ensuring that the reversal rule, dependency order, and result vessels
are governed entirely by this module.
The formulas for Fortune and Spirit in nine_parts.py are mathematically
identical to the "Fortune" and "Spirit" entries in lots.py. They are not
the same objects; callers should not mix results from the two modules.
§8. Relation to varga.py
The Vedic Navamsha (D9) is fully implemented in moira/varga.py via
calculate_varga(longitude, 9) and the navamsa() convenience function.
The segment_idx % 12 formula in varga.py naturally encodes the Vedic
elemental starting-point rule and produces correct navamsha sign assignments.
No additional navamsha work is needed in nine_parts.py.
Part III — Change Policy
§9. Stability Guarantees
The following are frozen and require a doctrine review before changing:
_NINE_PARTS_CATALOGUE— the nine formula definitionsNinePartNameenum values and their orderNinePartsReversalRule.FULL_REVERSALsemantics- The dependency order (Fortune/Spirit before derived lots)
The following are internal and may change without API notice:
_SIGN_RULER,_DERIVED_PARTS,_LOT_DEPENDENCIES_ALL_DEPENDENCY_RELATIONS,_DEPENDENCY_RELATION_BY_NAME_validate_inputs,_resolve_key
§10. Extension Points
To add Al-Sijzi Transfer of Management (Phase 2):
- Define
LotManagementvessel in this module - Add
lot_management(part, chart, date) -> LotManagement - Design the
longevity.pyintersection interface in a separate doctrinal note before touching either module - Do not modify any existing Phase 1–8 vessels or the primary engine