From aae3fea01100e7721091a95667bbd737ab3ba737 Mon Sep 17 00:00:00 2001 From: jesse-ux Date: Wed, 14 Oct 2026 00:49:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=A4=A7=E8=BF=90=E5=B9=B4?= =?UTF-8?q?=E9=95=BF=E6=94=B9=E6=88=90=20365.25=20=E5=A4=A9=EF=BC=8C?= =?UTF-8?q?=E5=92=8C=E6=8E=A8=E8=BF=90=E8=84=9A=E6=9C=AC=E5=90=8C=E4=B8=80?= =?UTF-8?q?=E5=A4=A9=EF=BC=88BUG-1321=EF=BC=8C=E4=B8=8A=E6=B8=B8=204d54320?= =?UTF-8?q?9=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 只改兜底时间线的结束日和进入本运年数这两处。同一大运起止相差 0 天。pytest tests/test_dasha_year_length_alignment.py 2 通过。增长合同仍过。 Co-Authored-By: Grok (agent loop) --- docs/BUG_HISTORY.md | 15 ++++++ scripts/jyotish_api_server.py | 4 +- tests/test_dasha_year_length_alignment.py | 62 +++++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 tests/test_dasha_year_length_alignment.py diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md index bd8daf5f..920fabed 100644 --- a/docs/BUG_HISTORY.md +++ b/docs/BUG_HISTORY.md @@ -17765,3 +17765,18 @@ - 复发自:无。 - 修复版本:分支 `codex/upstream-sync7-20261014`,尚未合入 staging。 +## BUG-1321 | 接口里的大运年长和推运脚本差了一点,起止会对不齐 + +- 状态:fixed-pending-verify +- 首次发现 / 最近更新:2026-10-14 / 2026-10-14 +- 来源:issue #56。上游 `4d543209`。任务书 T4。 +- 现象:接口的兜底大运和「进入本运几年」用 365.25636 天为一年。同一条时间线的推运脚本用 365.25 天。年限一长,日期会差一天。 +- 触发条件:走兜底大运时间线,或计算进入当前大运的年数。 +- 根因:两处常量没有跟着推运脚本改。同步第六轮漏了上游 10-03 的这一处。 +- 修复:这两处改成 365.25,与推运脚本相同。其它大运系统的年长不动。 +- 验证:`tests/test_dasha_year_length_alignment.py` 2 通过。同一大运起止相差 0 天。158 年的旧常量会落到下一天,新常量不会。 +- 防复发:兜底时间线必须和推运脚本的起止是同一天;进入本运的年数按 365.25 除。 +- 相关记录:BUG-1320。 +- 复发自:无。 +- 修复版本:分支 `codex/upstream-sync7-20261014`,尚未合入 staging。 + diff --git a/scripts/jyotish_api_server.py b/scripts/jyotish_api_server.py index c915df6e..39d3826f 100644 --- a/scripts/jyotish_api_server.py +++ b/scripts/jyotish_api_server.py @@ -6378,7 +6378,7 @@ class JyotishAPIHandler(BaseHTTPRequestHandler, VedastroEvidenceMixin, SynastryM periods = [] current = birth_dt for lord in DASHA_ORDER: - end_date = current + timedelta(days=period_years * 365.25636) + end_date = current + timedelta(days=period_years * 365.25) periods.append({ 'lord': lord, 'years': period_years, @@ -7398,7 +7398,7 @@ class JyotishAPIHandler(BaseHTTPRequestHandler, VedastroEvidenceMixin, SynastryM current_idx, current_md = analyzer.find_current(timeline, today) antardashas = analyzer.build_antardasha(current_md) current_ad = analyzer.find_current_sub(antardashas, today) - years_into_md = max(0.0, (today - current_md['start']).days / 365.25636) + years_into_md = max(0.0, (today - current_md['start']).days / 365.25) five_levels = enhanced.calculate_five_level_dasha(current_md['lord'], years_into_md) formatted_timeline = [self._format_datetime_period(period) for period in timeline] formatted_antardashas = [self._format_datetime_period(period) for period in antardashas] diff --git a/tests/test_dasha_year_length_alignment.py b/tests/test_dasha_year_length_alignment.py new file mode 100644 index 00000000..525dd043 --- /dev/null +++ b/tests/test_dasha_year_length_alignment.py @@ -0,0 +1,62 @@ +"""BUG-1321: the API fallback dasha year matches dasha_analyzer's 365.25 days. + +Upstream 4d543209. The two 365.25636 constants in the API server made the +fallback timeline and the years-into-mahadasha figure drift from the analyzer. +""" + +from __future__ import annotations + +import importlib.util +import os +import sys +from datetime import datetime, timedelta + +SCRIPTS = os.path.join(os.path.dirname(__file__), "..", "scripts") +if SCRIPTS not in sys.path: + sys.path.insert(0, SCRIPTS) + +from dasha_analyzer import build_dasha_timeline, lon_to_nakshatra # noqa: E402 + + +def _api_handler(): + """Reuse the existing unbound handler helper. Do not add another forgery site.""" + path = os.path.join(os.path.dirname(__file__), "test_api_server_security.py") + spec = importlib.util.spec_from_file_location("_api_security_helpers_dasha", path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module._handler() + + +def test_fallback_timeline_matches_analyzer_to_the_day() -> None: + birth = datetime(2000, 1, 1) + nak_info, progress, _pada = lon_to_nakshatra(0.0) + timeline, _elapsed, _remaining, _lord = build_dasha_timeline("2000-01-01", nak_info, progress) + handler = _api_handler() + years = timeline[0]["years"] + periods = handler._fallback_dasha_periods(birth, "generic", {"years": years * 9}) + assert periods[0]["lord"] == timeline[0]["lord"] + assert periods[0]["start"] == timeline[0]["start"].strftime("%Y-%m-%d") + assert periods[0]["end"] == timeline[0]["end"].strftime("%Y-%m-%d") + fallback_days = ( + datetime.strptime(periods[0]["end"], "%Y-%m-%d") + - datetime.strptime(periods[0]["start"], "%Y-%m-%d") + ).days + analyzer_days = (timeline[0]["end"].date() - timeline[0]["start"].date()).days + assert fallback_days - analyzer_days == 0 + + long_periods = handler._fallback_dasha_periods(birth, "generic", {"years": 1422}) + expected = (birth + timedelta(days=158 * 365.25)).strftime("%Y-%m-%d") + stale = (birth + timedelta(days=158 * 365.25636)).strftime("%Y-%m-%d") + assert expected != stale + assert long_periods[0]["end"] == expected + + +def test_years_into_mahadasha_uses_the_analyzer_year() -> None: + birth = datetime(2000, 1, 1) + today = datetime(2003, 1, 1) + handler = _api_handler() + layer = handler._compute_vimshottari_analysis_layer(birth, 0.0, current_date="2003-01-01") + days = (today - birth).days + years_into = layer["five_levels"]["mahadasha"]["years_into_period"] + assert years_into == days / 365.25 + assert years_into != days / 365.25636