SHADBALA_BACKEND_STANDARD - TheDaniel166/moira GitHub Wiki

Shadbala Backend Standard

Status: Current contract, adversarial repairs 9 October 2026 Authority: moira/shadbala.py
Source: Selected Raman 1996 and BPHS Santhanam component rules; see source and compatibility receipt.


Part I β€” Architecture Standard

1. Governing Principle

The Shadbala subsystem is an astronomical-truth-first computation of the six sources of planetary strength (bala) used in classical Vedic astrology.

Source attribution is component-specific. Selected Saptavargaja, Kala and war rules have independently transcribed arithmetic witnesses. Retained thresholds, ingress-based Abda/Masa, osculating Chesta and sign-based Drig are identified separately; neither named Saptavargaja scale claims an entire textbook worked chart.

2. Layer Structure

The subsystem is organised into twelve constitutional phases. Each phase consumes only outputs produced by earlier phases. No phase reaches upward.

Phase  0  β€” Core computation (sthana_bala, dig_bala, kala_bala, chesta_bala,
            naisargika_bala, drig_bala, shadbala)
Phase  1  β€” Truth preservation     (SthanaBala, KalaBala, PlanetShadbala,
                                    ShadbalaResult)
Phase  2  β€” Classification          (ShadbalaTier)
Phase  3  β€” Inspectability          (PlanetShadbala.strength_ratio)
Phase  4  β€” Policy surface          (ShadbalaPolicy)
Phase  5  β€” Relational formalization (GrahaYuddha, graha_yuddha_pairs)
Phase  6  β€” Relational hardening    (GrahaYuddha.__post_init__ invariants)
Phase  7  β€” Local condition         (ShadbalaConditionProfile,
                                    shadbala_condition_profile)
Phase  8  β€” Aggregate intelligence  (ShadbalaChartProfile,
                                    shadbala_chart_profile)
Phase  9  β€” Network intelligence    (ShadbalaNetworkProfile,
                                    shadbala_network_profile)
Phase 10  β€” Full-subsystem hardening (PlanetShadbala.__post_init__,
                                    ShadbalaResult.__post_init__,
                                    validate_shadbala_output)
Phase 11  β€” Architecture freeze (this document)
Phase 12  β€” Public API curation (__all__, module docstring)

Layer boundary rules

  • A phase-N function may consume vessels from any phase below N.
  • A phase-N function may not mutate a lower-phase vessel.
  • A phase-N function may not silently switch doctrine.
  • A phase-N function may not bypass or re-derive a computation already produced by a lower phase.

3. Admitted Computation Surface

The following core computations are admitted and constitutionally frozen:

Function Sub-component Raman Ch.
sthana_bala Positional Strength (5 sub-components) Ch. 2–3
dig_bala Directional Strength Ch. 3
kala_bala Temporal Strength (6 sub-components) Ch. 4
chesta_bala Motional Strength Ch. 6 (non-luminaries), Ch. 10 Β§Β§136–137 (luminaries)
Naisargika Bala Natural/Fixed Strength (constant) Ch. 5
drig_bala Aspectual Strength Ch. 6
shadbala Grand total (all 7 planets) Ch. 1
bhava_dig_bala Bhava Digbala (house directional strength) Part II
bhava_drishti_bala Bhava Drishti Bala (aspect on bhava madhya) Part II
bhava_bala Bhava Bala grand total (all 12 houses) Part II

4. Computational Policies

Chesta Bala

Retained motion convention (not selected by the Saptavargaja scale):

  • Sun: Chapter X (Β§136, pp. 101–103). Sayana (tropical) longitude + 90Β°, reduced to ≀ 180Β° and divided by 3 Shashtiamsas. Maximum 60 Sha at Cancer ingress (northern solstice), 0 Sha at Capricorn ingress (southern solstice), 30 Sha at equinoxes.
  • Moon: Chapter X (Β§137, pp. 101–103). Elongation |lon_Moon βˆ’ lon_Sun|, reduced to ≀ 180Β° and divided by 3 Shashtiamsas. Maximum 60 Sha at Full Moon (opposition), 0 Sha at New Moon (conjunction), 30 Sha at quarters.
  • Five non-luminaries (Mars, Mercury, Jupiter, Venus, Saturn): Chapter VI (Chesta Bala or Motional Strength, pp. 64–79). Derived from Chesta Kendra = (Seeghrochcha βˆ’ (mean_lon + true_lon) / 2) mod 360Β°, reduced to ≀ 180Β° and divided by 3 Shashtiamsas. For superior planets (Mars, Jupiter, Saturn), Seeghrochcha is the Sun's longitude and mean longitude is the planet's mean orbital longitude evaluated from the strict orbital core. For inferior planets (Mercury, Venus), Seeghrochcha is the planet's heliocentric longitude and the mean planet is the Sun.
  • Speed-ratio fallback: preserved for callers without positions or ephemeris access (retrograde gives 60 Sha; standstill gives 0 Sha).

Explicit geometry and source components

Full calculation requires immutable ShadbalaContext: UT epoch, named ayanamsa, seven apparent geocentric sidereal longitudes, seven true-equatorial tropical declinations, Chesta inputs, local apparent solar fraction, sunrise/set/next sunrise, named year/month/day/hour lords and provenance. derive_shadbala_context and Moira.shadbala_context bind the serving reader for all dependencies. Supplied contexts perform no hidden ephemeris lookup. Missing polar solar events remain inspectable and raise ShadbalaContextError for full strength.

Saptavargaja defaults to raman_1996; bphs_santhanam_27 changes only the seven awards. Both use the explicit Raman D1-only Moolatrikona convention, actual D1 degrees, and D1 compound relationships. Temporary friendship is houses 2,3,4,10,11,12. Source D7 counts from own/seventh for odd/even signs, D12 from own sign, and D30 uses unequal planetary spans. Public generic harmonic selectors are separate. SaptavargajaEntry preserves each sign/lord/state/award. Mercury receives both odd-sign Ojayugma contributions like Sun/Mars/Jupiter/Saturn.

Nathonnatha is linear in apparent solar hour angle; Mercury always receives60. Paksha uses continuous Sun–Moon phase, with Moon doubling. The named Moira nature convention treats Moon as benefic on [84,264) degrees and Mercury as malefic when sharing a D1 sign with Sun/Mars/Saturn or a malefic Moon. A supplied context may explicitly select Mercury benefic/malefic. These endpoint and association choices are declared interpretations, not an undisputed universal. Tribhaga divides actual day/night arcs in thirds: Mercury/Sun/Saturn by day, Moon/Venus/Mars by night; Jupiter always 60. Half-open boundaries assign the new third. Ayana applies (24 + signed_declination)*60/48; Sun is doubled, Mercury uses absolute declination, Moon/Saturn reverse sign. Declinations beyond 24 degrees retain the formula's signed result rather than an undocumented cap.

Kala Bala β€” Yuddha Bala (Graha Yuddha)

Only Mars/Mercury/Jupiter/Venus/Saturn participate, at separation strictly below one degree. Raman 1996 articles 76–77 select lesser normalized longitude and abs(raw_aggregate_difference)/abs(source_disc_diameter_difference). Raw aggregate is Sthana+Dig+Kala through Hora, excluding Ayana. Fixed source disc values are9.4,6.6,190.4,16.6,158.0 arcseconds respectively; they are not modern observed angular diameters. Winner gains and loser loses the same Kala amount; Chesta is unchanged.

moira_simultaneous_raman_raw_pairs_v1 evaluates every pair once against immutable pre-war components, accumulates all credits/debits, and retains signed net values. Exact equal longitude pairs have a stable lexical label and zero adjustment. These tie/multi-way choices are Moira composition rules; the inspected source passages prescribe two-body behavior only. WarResolution is canonical for final totals, chart/network/Bhava/full and Lagna consumers.

Drig Bala

Sign-based Vedic aspect doctrine (not degree-based):

  • 4th/8th aspects of Mars score Β½ weight; 7th aspect scores full weight.
  • Saturn's 3rd/10th aspects score Β½ weight; 7th scores full weight.
  • Jupiter's 5th/9th aspects score Β½ weight; 7th scores full weight.
  • All other planet–planet aspects (7th house opposition) score full weight.

Kala Bala β€” Abda and Masa

Located by bisection on the Sun's actual apparent sidereal longitude from the kernel (moira.planets.planet_at), pinning the Sankranti JD to 1-second precision. Not from mean-motion approximation.

Bhava Bala (Raman Part II)

Three components per house, summed to total_shashtiamsas:

  • Bhavadhipati Bala β€” the total Shadbala piṇḍa of the house lord. The lord is the classical lord of the rasi holding the bhava madhya (no nodal lordships). The chart's jd and ayanamsa are taken from the supplied ShadbalaResult so the two computations cannot disagree.
  • Bhava Digbala β€” the madhya rasi's locomotion class fixes the strong house (nara β†’ H1, jalachara β†’ H4, keeta β†’ H7, chatushpada β†’ H10); 60 Sha there, βˆ’10 Sha per house of shortest circular distance, 0 opposite. Half-sign splits: Sagittarius 1st half nara / 2nd half chatushpada; Capricorn 1st half chatushpada / 2nd half jalachara.
  • Bhava Drishti Bala β€” the bhava madhya is the aspected point, all seven classical planets aspecting, using the same sign-based aspect doctrine as Drig Bala (shared core: _sign_aspect_drig_sha).

Bhava madhya policy (explicit): the chart's house cusps are taken as the madhya reference points, mirroring the module-wide house doctrine used by dig_bala; equal houses from the Ascendant are the fallback when cusps are unavailable. Houses are ranked 1–12 by total strength (ties broken by lower house number).

No required/threshold marker exists for houses: the tradition defines required Rupas for planets only, so Bhava Bala is reported as raw strength plus rank β€” no pass/fail is invented.

Ishta / Kashta Phala (BPHS Ch. 27)

Exposed as P3 inspectability properties on PlanetShadbala, derived β€” never stored β€” from the vessel's own displayed components:

  • ishta_phala = √(Uchcha Bala Γ— Chesta Bala)
  • kashta_phala = √((60 βˆ’ Uchcha) Γ— (60 βˆ’ Chesta))

Both on the 0–60 Shashtiamsa scale. Policy: the displayed Chesta Bala is used; war adjustments leave the displayed Chesta unchanged.

Graha Yuddha transfer disclosure

GrahaYuddha.adjustment_shashtiamsas carries the actual resolved Kala amount. Detection-only pairs carry None. Deprecated chesta_transferred remains a legacy construction field and is never populated by current calculation. REST retains shashtiamsas_transferred, with adjustment_component=kala_yuddha. The full ledger exposes raw totals, bases, Chesta, credits/debits and net values.


Part II β€” Vessel Inventory

Core vessels (Phase 1)

Vessel Frozen Slots Notes
SthanaBala βœ… βœ… Five sub-components + total
KalaBala βœ… βœ… Six sub-components + total
PlanetShadbala βœ… βœ… All 6 bala + totals + is_sufficient
ShadbalaResult βœ… βœ… Full chart: jd, ayanamsa_system, planets
BhavaBala βœ… βœ… One house: 3 components + totals + rank
BhavaBalaResult βœ… βœ… All 12 houses + strongest/weakest

Constitutional-layer vessels

Vessel Phase Notes
ShadbalaTier P2 SUFFICIENT / INSUFFICIENT class constants
GrahaYuddha P5/P6 War-pair record: victor, loser, separation_deg
ShadbalaPolicy P4 ayanamsa_system governance
ShadbalaConditionProfile P7 Per-planet condition summary
ShadbalaChartProfile P8 Aggregate chart strength summary
ShadbalaNetworkProfile P9 Strength ranking + war network

Part III β€” Public API

The following names are exported via __all__ and constitute the stable public surface of this module.

Constants

  • NAISARGIKA_BALA β€” natural fixed strength values (Shashtiamsas)
  • REQUIRED_RUPAS β€” minimum Rupa thresholds per planet (Parashara)
  • MEAN_DAILY_MOTION β€” classical mean daily motions (Β°/day)

Vessels

  • ShadbalaTier, SthanaBala, KalaBala, PlanetShadbala, ShadbalaResult
  • ShadbalaPolicy, GrahaYuddha
  • ShadbalaConditionProfile, ShadbalaChartProfile, ShadbalaNetworkProfile

Functions

  • sthana_bala, dig_bala, kala_bala, chesta_bala, drig_bala
  • shadbala β€” full chart computation (all 7 planets)
  • hora_lord_at β€” planetary hora lord at a birth moment
  • graha_yuddha_pairs β€” public war-pair detection
  • shadbala_condition_profile, shadbala_chart_profile, shadbala_network_profile
  • validate_shadbala_output

Part IV β€” Invariant Register

GrahaYuddha

  1. victor ∈ {Mars, Mercury, Jupiter, Venus, Saturn}
  2. loser ∈ {Mars, Mercury, Jupiter, Venus, Saturn}
  3. victor β‰  loser
  4. Detected separation is 0 <= separation_deg < 1.0; the legacy vessel still permits1.0, but canonical ledger validation rejects such a fabricated detection.

PlanetShadbala

  1. total_shashtiamsas = sthana_bala.total + dig_bala + kala_bala.total + chesta_bala + naisargika_bala + drig_bala
  2. total_rupas = total_shashtiamsas / 60.0
  3. is_sufficient ↔ total_rupas β‰₯ required_rupas

ShadbalaResult

  1. ayanamsa_system must be non-empty.
  2. jd must be a finite float.

validate_shadbala_output checks

  1. Each planets[key].planet == key.
  2. total_rupas β‰ˆ total_shashtiamsas / 60 (tolerance 1e-6).
  3. is_sufficient consistent with total_rupas vs required_rupas.

Part V β€” Delegation Boundaries

Responsibility Delegated to
Vedic dignity rank moira.vedic_dignities
Varga sign indices moira.varga
Panchanga elements (Vara, Paksha) moira.panchanga
Sunrise / sunset moira.rise_set
Orbital elements (mandoccha) moira.orbits
Sidereal conversion (tropical β†’ sidereal) moira.sidereal
Kernel state vectors moira.spk_reader

The core shadbala() function does not perform sidereal conversion. The caller is responsible for supplying sidereal longitudes.


Part VI β€” Failure Doctrine

Condition Behavior
tithi_number not in [1, 30] ValueError via shadbala()
Required planet absent from sidereal_longitudes or planet_speeds KeyError propagated
ShadbalaResult.ayanamsa_system empty ValueError in __post_init__
ShadbalaResult.jd non-finite ValueError in __post_init__
GrahaYuddha invariant breach ValueError in __post_init__
validate_shadbala_output inconsistency ValueError
shadbala_network_profile with empty planets ValueError

Part VII β€” Validation Notes

The following are verified by the test suite (tests/unit/test_shadbala.py, 92 tests as of P11 freeze):

  • All NAISARGIKA_BALA, REQUIRED_RUPAS, MEAN_DAILY_MOTION canonical values.
  • chesta_bala: Raman Ch. X luminary solstices/elongations, Raman Ch. VI non-luminary Chesta Kendra, and backward-compatible speed-ratio cases.
  • drig_bala: Jupiter/Saturn 7th-sign opposition, Mars special aspects, no-aspect β†’ 0.
  • kala_bala: local solar time, continuous phase/nature, actual thirds, declination rules and explicit AMVH inputs.
  • sthana_bala: sub-component sum equals total.
  • dig_bala: float in [0, 60]; at strong cusp β†’ maximum.
  • shadbala integration: 7 planets present; total_rupas = total_shashtiamsas / 60; is_sufficient correct; invalid tithi raises.
  • Vessel invariants: all vessels frozen, slots=True.
  • __all__ surface: all exported names importable.
  • validate_shadbala_output: valid result does not raise; planet-key mismatch raises.

The repair acceptance adds independent pair arithmetic, permutations, corrupted-ledger rejection and real May2000/December2020 chart/full/Lagna HTTP witnesses. See the linked current validation receipt.


Document produced at constitutional freeze (P11), April 2026.

REST admission and reader ownership β€” 8 October 2026

All six chart/result/profile/network/condition/Bhava/full routes use the owning engine's reader-bound Shadbala call. They expose requested/applied ayanamsa and requested/resolved/effective house systems in policy_receipt, including actual polar fallback. Unknown house systems reject; registered names and codes are admitted. That admission checkpoint did not change numerical Bala rules; the subsequent October9 repair above does. See the VED-005 admission standard and its verification receipt.

Direct-call and REST migration β€” 9 October 2026

shadbala(..., context=ctx) and kala_bala(..., context=ctx) now reject missing, partial or contradictory context. sthana_bala requires all seven D1 positions through sidereal_longitudes. Dated facade callers supply observer coordinates or a context; REST derives one per request. REST strength planets are now apparent geocentric positions; observer location controls houses and solar geometry. Older topocentric REST positions were incompatible with that contract.

Output validation checks typed components, sums, Rupas, thresholds, context, Saptavargaja evidence and every war ledger entry. Negative Ayana requires its declination context; nonzero Yuddha requires its canonical ledger. Existing legacy manually constructed zero-war results remain structurally admissible. An internally inconsistent service result is a server error, not client 422. Polar full-strength unavailability is typed 422 shadbala_context_unavailable; Lagna keeps its independent evidence and explicit unavailable strength basis.

The public surface also includes ShadbalaContext, ShadbalaContextError, derive_shadbala_context, SaptavargajaEntry, saptavargaja_breakdown and WarResolution. Exact exports are tested. Required Rupas retain their existing values, including Sun 6.5, as a separate Moira threshold convention.

Second adversarial pass: composition and receipt validation

Derived contexts declare vara_basis="civil_utc_midnight" and vara_jd_utc. This preserves dated Panchanga's UTC weekday convention while all geometry continues to use UT1. Dated adapters pass the original UTC JD; direct UT1 context derivation uses the time owner's inverse. The context checks that the UTC evidence converts to its exact UT1 epoch and selects its Vara lord. Legacy synthetic contexts retain vara_basis="supplied" with no UTC claim. This does not attribute a UTC-midnight convention to a classical source; ingress-based Abda/Masa conventions remain separately declared.

Context-backed validation recomputes Uchcha, Ojayugma, Drekkana and Drig from the accepted positions, as well as the existing Kala, Chesta, Saptavargaja and war checks. Positional ranges and discrete awards are enforced. Balanced component changes cannot pass merely by preserving sums. House-independent positional calculation and validation share one formula owner. Kendradi membership and Dig's range are checked, but their exact values cannot be reconstructed without house evidence, which is not carried in this context. Legacy context-free results receive structural validation; neither kind of supplied receipt proves the observational authenticity of caller data.

After compatibility checking, Lagna and Bhava consumers use the accepted context positions before discrete sign, Navamsa, house or aspect decisions. The 1e-9-degree comparison tolerance is unchanged. Lagna retains missing bodies and caller-supplied nodes; context evidence does not fill input gaps.