Files
Jyotisha/docs/engine/annual-package-v1.md
T
ClaudeandClaude Opus 5.5 32fa756bd4 refactor(annual): move the annual package and report facts into annual_service
Staging's backend gate (run 6338) failed three budgets: handler method
count 218 > 217, JyotishAPIHandler.__new__ sites 6 > 5, and the scripts/
root .py count. The package and facts code now live in
scripts/annual_service/ (package.py, report_facts.py, api.py with
compute_annual_package / compute_annual_report_facts and
AnnualServiceInputError). jyotish_api_server.py registers /api/annual
mode=package, /api/annual/package and /api/annual/report_facts thinly
through a module-level _annual_service helper, like /api/chart_points,
with no handler methods: back to 217. Tests call the module functions
and keep a thin-registration test; no cap or baseline changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-01 20:33:17 +08:00

9.2 KiB
Raw Blame History

年度数据包 v1(annual_package_version = 1)

依据:Gitea #152 裁定(jesse 2026-11-01 确认)「落地前要先做的四件事」。这是 #153(年运报告)和 #154(入口遮罩页)的数据接口。只做计算和数据搬运,不含解读文字,不建候选窗口。

入口

  • POST /api/annual,请求体加 "mode": "package";或 POST /api/annual/package(同一个处理函数)。
  • "detail": "slim"(#154 遮罩用):只回报告范围、每张年盘的有效期、生日分界和块状态,几 KB;不回运限行、行运和生产器数据。默认 "full"。
  • 年运报告的事实与结论卡:POST /api/annual/report_facts(同样的请求体,加必填的 birth_time_confirmed),见 annual-report-v1.md。
  • 不带 mode 的 /api/annual 仍返回原来的基础太阳返照报告(report),形状不变;只多传了 node_mode(默认 mean,结果不变)。
  • 代码:scripts/annual_service/package.py(normalize_request、build_annual_package);请求解析与入口在 scripts/annual_service/api.py(compute_annual_package、compute_annual_report_facts,输入错误 AnnualServiceInputError 映射为 400),scripts/jyotish_api_server.py 只做薄注册(_annual_service,与 /api/chart_points 同一做法)。前端合同:frontend/src/lib/annual-package-contract.ts(zod + 映射,无界面)。

请求字段

字段 说明
year month day hour minute second 出生时间,秒会传到所有生产器
lat lon tz 出生地;tz 缺省时按经纬度推算
timezone_id / timezone 可选 IANA 时区;有则返照本地时间、报告范围按该时区(含夏令时)
ayanamsa 岁差,默认同其他接口
node_mode mean / true
report_range {kind, year?, start_date?},kind 为 birthday_year(生日年度)/ calendar_year(公历年)/ next_12_months(未来十二个月)
observation_date 报告观测日期,默认今天;next_12_months 不给 start_date 时从这天起
return_location {mode: "birth_place"}。v1 只开放出生地,其它值返回 400;字段保留,以后加所在地对照不改形状

响应结构

{success, endpoint: "annual", mode: "package", annual_package_version: 1, package},package 的键序:

  1. schema = jyotish.annual_package.v1、annual_package_version
  2. parameters:出生时刻(UTC、出生固定偏移下的本地时间)、岁差、交点、宫制、回归地点、观测日期、本命盘经度(natal_chart)
  3. report_range:报告范围
  4. year_charts[]:覆盖报告范围的每张年盘
  5. natal_periods:vimshottari、narayana(legacy + rath)
  6. slow_transits:木星、土星、罗睺、计都
  7. independent_annual_views.tithi_pravesha:独立年度视角
  8. computation_boundaries:时间语义与计算边界的说明
  9. not_included:没放进来的项和原因
  10. block_index:所有块的路径、状态、生产器、原因;blocked_count

块状态

每个块都有 status:computed / blocked / not_applicable,以及 producer;非 computed 一定有 reason。生产器原有的状态(如 partial_verified、parameter_sensitive)放在 producer_status,不提升。生产器报错、返回 blocked、两个年运生产器结果冲突(producer_conflict:...,两个值都在 conflict_values)都写成 blocked。某个块 blocked 不影响整个响应。

时间语义(四种时间分开表示)

所有边界都是一个“时刻”:{utc, local, utc_offset, timezone_id, jd_ut}。local 用回归地点的时区(v1 即出生地;给了 IANA 就按当时的规则取偏移,否则用出生固定偏移)。出生时刻本身用出生固定偏移显示,因为排盘按这个偏移读出生时钟(例:上海 1986–1991 年有夏令时)。

  1. 报告范围 report_range:start 含、end 不含。
    • 生日年度:本次太阳返照到下次太阳返照;
    • 公历年:当地 1 月 1 日 0 点到次年 1 月 1 日 0 点;
    • 未来十二个月:start_date 当地 0 点到十二个日历月后(月底按月末截)。
    • year_chart_years 列出与范围重叠的年盘,跨生日时是相邻两张;crosses_birthday、birthday_boundaries 给出换年盘的时刻。
    • observation:观测日期、在范围内 / 前 / 后,回看起点(默认三个月)。
  2. 年盘有效期 year_charts[].validity:本次返照(含)到下次返照(不含),end_source = next_solar_return;in_report_range 是与报告范围的交集。
  3. 各运限自己的年制:Mudda 365.25 天、Patyayini 固定 365.25 天,都从返照时刻起;Vimshottari 365.25 天,从出生时刻起;Narayana 在年龄轴上,日期 = 出生时刻 + 年龄 × 365.25 天(与引擎算当前年龄的口径一致)。各行保留原始起止,in_report_range 是裁到报告范围的部分,不拉伸到返照年(返照年约 365.256 天,Mudda / Patyayini 的年末比下次返照早几分钟)。
  4. 计算边界:生产器在本地时钟上加天数的(Mudda、Patyayini、Vimshottari),按“从锚点时刻起经过的时间”换成 UTC,跨夏令时也对。月盘第 12 张止于下次返照。

候选窗口不在本期,由 #153 用上面这些时刻去建。

各块由谁计算

块 生产器
年盘、上升及上升主、宫位 cmd_solar_return → solar_return.solar_return_full_report(结果交给 annual_tajika_pack.build_annual_tajika_pack)
Muntha、Muntha 主落宫 solar_return._muntha_from_natal_ascendant(经年运包);落宫按年盘整宫数
年主 tajika_year_lord.select_annual_year_lord(Panchadhikari,经年运包冲突门)
年度力量 tajika.calc_tajika_strength_layers:Panchavargiya、Harsha Bala;不是本命 Shadbala
Sahams tajika.calc_all_sahams(原样保留公式来源与昼夜依据)
Tajika Yoga tajika_named_yoga_authority(只有结构,不翻译成事件)
Tripataki annual_native.tripataki_chakra
Mudda tajika_mudda.annual_mudda_dasha(出生月宿起运,与年主无关)
Patyayini annual_native.patyayini.build_native_patyayini(tajika-annual skill 指定的年度原生入口;不用 extended_dashas.py 的等长旧函数),输入八点的经度一并给出
Tajika 月盘 annual_native.monthly_charts.build_monthly_charts:太阳每前进 30° 一张,不是公历月,也不是月亮回归盘
Tithi Pravesha annual_native.tithi_pravesh.build_tithi_pravesh,独立单列:起点规则不同于太阳回归,地点用出生地和出生固定偏移(生产器自己的规则);找到几个候选就列几个,不替用户选
Vimshottari MD/AD/PD jyotish_engine.cmd_dasha(出生时刻起运)
Narayana narayana_dasha.narayana_dasha_full_report(产品现用的旧算法,used_by_product_timeline: true)和 narayana_rath(Sanjay Rath 版,占星师口径,并列展示,false);只列与范围重叠的 MD / AD
慢星行运 位置取 jyotish_engine._calc_sidereal_planets_for_jd(与本命盘同一参考系,跟随交点和岁差);每天 12:00 UT 取样,再二分到 1 秒以内。给出:范围起点的位置(从上升和月亮各算宫)、换宫、停滞、与本命十点(上升 + 九曜)的精确合相经过及次数、木星 / 土星的逆行回路(停滞时刻与经度、回扫弧段、前后影区进出时刻、落在弧段内的本命点及每次经过)

本期修的参数缺口(BUG-1501)

solar_return.calc_solar_return_chart 排出生盘和年盘时交点口径写死为 mean,node_mode=true 传不到年盘,年盘罗睺 / 计都和 Tripataki 总是平均交点。现在 calc_solar_return_chart / solar_return_full_report 接受 node_mode(默认 mean),cmd_solar_return 和 cmd_tajika 都会传。

没放进来的(not_included)

  • Varsha Narayana:本仓没有原生生产器(上游 yinduzhanxing 有,未同步)。
  • Yoga / Nakshatra Pravesha:上游只有研究版,裁定不进报告。
  • 外部引擎回放(PyJHora):只在完整数据版的子进程里跑,这里不执行。
  • 所在地返照:v1 只开放出生地。
  • 行运的 BAV / SAV、Vedha、Sade Sati 阶段:报告阶段做;BAV / SAV 来自 /api/ashtakavarga。
  • 候选窗口:#153。
  • Real Case Calibration:按裁定仍是 blocked,不作准确率声明。

已知限制

  • Narayana 旧算法的 AD 年龄由生产器保留 4 位小数,换成日期约有 53 分钟误差;MD 年龄是整年相加,没有这个问题。旧算法只排一轮,范围超出这一轮时写 blocked。
  • 慢星事件按天取样,一天内相继发生的两件事可能合并(慢星实际不会出现)。真交点每天取样。
  • 回路的影区边界落在扫描窗口(范围前后各 220 天)之外时写 null,并在 shadow_note 里说明。
  • 返照、Mudda、Patyayini 的时刻都按返照求解器的精确时刻(JD)对齐;生产器内部用的是截到秒的时间,差不到 1 秒。
  • 一个公历年的完整包大约 350 KB(大头是 Mudda / Patyayini 的子运行,每行有三个时刻)。