feat(skill): extend special lagna coverage

This commit is contained in:
732642856
2026-06-26 21:07:08 +08:00
parent 20e7c7dc4c
commit 235c44bcd1
4 changed files with 70 additions and 8 deletions
+4 -4
View File
@@ -4,8 +4,8 @@
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue)](https://www.python.org/)
[![Techniques](https://img.shields.io/badge/techniques-74-blueviolet)](references/technique_registry.json)
[![Covered](https://img.shields.io/badge/covered-65-green)](references/technique_registry.json)
[![Techniques](https://img.shields.io/badge/techniques-75-blueviolet)](references/technique_registry.json)
[![Covered](https://img.shields.io/badge/covered-66-green)](references/technique_registry.json)
[![Complete](https://img.shields.io/badge/complete-9-brightgreen)](references/technique_registry.json)
[![Partial](https://img.shields.io/badge/partial-0-lightgrey)](references/technique_registry.json)
@@ -31,7 +31,7 @@
This is a **Vedic (Jyotish) astrology analysis system** designed for deep, auditable full-chart readings. It is NOT a simple ephemeris calculator — it is a multi-stage interpretive pipeline that:
1. **Computes** divisional charts (D1/D9/D10/...) via Swiss Ephemeris
2. **Runs** 74 registered techniques (Dashas, Yogas, Shadbala, Ashtakavarga, Transits...)
2. **Runs** 75 registered techniques (Dashas, Yogas, Shadbala, Ashtakavarga, Transits...)
3. **Routes** the analysis through strict workflow paths depending on question type (career / relationship / wealth / timing)
4. **Audits** every technique used — declaring what was called, what is complete/covered, and which limitations affect confidence
5. **Degrades gracefully** — limitations are labeled, not silently over-promising
@@ -45,7 +45,7 @@ This is a **Vedic (Jyotish) astrology analysis system** designed for deep, audit
| Technique Audit Table (confidence labeling) | ✅ | ❌ | ❌ | ❌ |
| Capability degradation (limits are explicit) | ✅ | ❌ | ❌ | ❌ |
| MEVG external verification gates | ✅ | ❌ | ❌ | ❌ |
| 74 techniques registered | ✅ | ✅ (50+) | ✅ (200+) | ✅ |
| 75 techniques registered | ✅ | ✅ (50+) | ✅ (200+) | ✅ |
| Traditional algorithm benchmarked | ✅ mixed depth | ✅ | ✅ | ✅ |
| Docker / MCP Server | ✅ | ❌ | ✅ | ❌ |
| English docs / PyPI package | ✅ in progress | ✅ | ✅ | ✅ |
+26
View File
@@ -878,6 +878,32 @@
"audit_label": "Upapada Lagna",
"missing_impact": "Marriage quality analysis incomplete without UL."
},
"special_lagnas_extended": {
"name": "Special Lagnas / HL GL VL PP ViL",
"domains": [
"lagna",
"timing",
"wealth",
"status"
],
"status": "covered",
"knowledge_refs": [
"references/open_source_sources/jaimini-tropical/jaimini/core/lagnas.py"
],
"commands": [
"chart",
"full-reading"
],
"output_paths": [
"special_lagnas.HL",
"special_lagnas.GL",
"special_lagnas.VL",
"special_lagnas.PP",
"special_lagnas.ViL"
],
"audit_label": "Special Lagnas",
"missing_impact": "Special Lagna timing, status and prosperity sub-angles are thinner without HL/GL/VL/PP/ViL."
},
"tithi_lord": {
"name": "Tithi Lord / 月日守护星",
"domains": [
+23 -3
View File
@@ -779,6 +779,9 @@ def calc_special_lagnas_precise(
hl_idx = ghati_floor % 12 if ghati_floor % 2 else (7 - ghati_floor) % 12
gl_idx = ghati_floor % 12
vl_idx = (asc_sign_idx * 3) % 12
vl_from_hl_idx = (hl_idx * 3) % 12
pp_idx = (hl_idx + gl_idx) % 12
vil_idx = int((ghatis * 2)) % 12
sunrise_local_hours = (sunrise_utc + tz_offset) % 24
sunrise_local_minutes = int(round(sunrise_local_hours * 60)) % (24 * 60)
@@ -794,6 +797,8 @@ def calc_special_lagnas_precise(
'ghatis_elapsed_from_sunrise': round(ghatis, 4),
'HL': _special_lagna_payload('HL', 'Hora Lagna', hl_idx, fraction * 30.0, ghatis, before_sunrise),
'GL': _special_lagna_payload('GL', 'Ghati Lagna', gl_idx, fraction * 30.0, ghatis, before_sunrise),
'PP': _special_lagna_payload('PP', 'Pranapada Lagna', pp_idx, fraction * 30.0, ghatis, before_sunrise),
'ViL': _special_lagna_payload('ViL', 'Vighati Lagna', vil_idx, fraction * 30.0, ghatis, before_sunrise),
'VL': {
'name': 'VL',
'full_name': 'Varnada Lagna',
@@ -801,8 +806,13 @@ def calc_special_lagnas_precise(
'sign_idx': vl_idx,
'lord': SIGN_LORDS[_sign_name(vl_idx)],
'method': 'Ascendant sign × 3',
'vl_from_hl': {
'sign': _sign_name(vl_from_hl_idx),
'sign_idx': vl_from_hl_idx,
'lord': SIGN_LORDS[_sign_name(vl_from_hl_idx)],
},
},
'note': 'HL/GL以出生地日出为起点计算;GL对24分钟边界敏感,出生时间不准时应结合生时校正。'
'note': 'HL/GL/PP/ViL以出生地日出为起点计算;GL与ViL对细分钟边界敏感,出生时间不准时应结合生时校正。'
}
@@ -819,12 +829,22 @@ def calc_special_lagnas(asc_sign_idx: int, hour: int, minute: int = 0) -> Dict:
hl_idx = ghati_floor % 12 if ghati_floor % 2 else (7 - ghati_floor) % 12
gl_idx = ghati_floor % 12
vl_idx = (asc_sign_idx * 3) % 12
vl_from_hl_idx = (hl_idx * 3) % 12
pp_idx = (hl_idx + gl_idx) % 12
vil_idx = int(ghatis * 2) % 12
return {
'method': 'Special Lagnas HL/GL/VL simplified (jaimini-tropical MIT adapted; sunrise-sensitive)',
'capability_status': 'auxiliary_partial',
'ghatis_elapsed_from_midnight': round(ghatis, 4),
'HL': {'sign': _sign_name(hl_idx), 'sign_idx': hl_idx, 'lord': SIGN_LORDS[_sign_name(hl_idx)]},
'GL': {'sign': _sign_name(gl_idx), 'sign_idx': gl_idx, 'lord': SIGN_LORDS[_sign_name(gl_idx)]},
'VL': {'sign': _sign_name(vl_idx), 'sign_idx': vl_idx, 'lord': SIGN_LORDS[_sign_name(vl_idx)]},
'note': 'HL/GL/VL对日出非常敏感;本函数用于结构化补齐,精确版本需接入当地日出。'
'PP': {'sign': _sign_name(pp_idx), 'sign_idx': pp_idx, 'lord': SIGN_LORDS[_sign_name(pp_idx)]},
'ViL': {'sign': _sign_name(vil_idx), 'sign_idx': vil_idx, 'lord': SIGN_LORDS[_sign_name(vil_idx)]},
'VL': {
'sign': _sign_name(vl_idx),
'sign_idx': vl_idx,
'lord': SIGN_LORDS[_sign_name(vl_idx)],
'vl_from_hl': {'sign': _sign_name(vl_from_hl_idx), 'sign_idx': vl_from_hl_idx, 'lord': SIGN_LORDS[_sign_name(vl_from_hl_idx)]},
},
'note': 'HL/GL/VL/PP/ViL对日出非常敏感;本函数用于结构化补齐,精确版本需接入当地日出。'
}
+17 -1
View File
@@ -150,6 +150,8 @@ class TestSpecialLagnas:
assert 'HL' in result
assert 'GL' in result
assert 'VL' in result
assert 'PP' in result
assert 'ViL' in result
def test_ghatis_calculated(self):
result = calc_special_lagnas(0, 10, 30)
@@ -177,10 +179,24 @@ class TestSpecialLagnas:
assert result['precision'] == 'sunrise_correct'
assert 'sunrise_local_time' in result
assert result['ghatis_elapsed_from_sunrise'] > 0
for key in ['HL', 'GL', 'VL']:
for key in ['HL', 'GL', 'VL', 'PP', 'ViL']:
assert result[key]['sign'] in SIGNS
assert result[key]['lord'] in SIGN_LORDS.values()
def test_precise_special_lagnas_include_varnada_crosscheck(self):
result = calc_special_lagnas_precise(
4, REDACTED_YEAR, 4, 17, 14, 45, lat=36.466667, lon=114.2, tz_offset=8
)
assert result['VL']['sign_idx'] == (4 * 3) % 12
assert 'vl_from_hl' in result['VL']
def test_precise_special_lagnas_expose_named_extended_payloads(self):
result = calc_special_lagnas_precise(
0, 1990, 6, 15, 10, 30, lat=28.6, lon=77.2, tz_offset=5.5
)
assert result['PP']['full_name'] == 'Pranapada Lagna'
assert result['ViL']['full_name'] == 'Vighati Lagna'
def test_precise_special_lagnas_are_time_sensitive(self):
morning = calc_special_lagnas_precise(
0, 1990, 6, 15, 10, 0, lat=28.6, lon=77.2, tz_offset=5.5