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
8.8 KiB
8.8 KiB
年运报告 v1(#153 报告生成、#154 入口遮罩)
依据:Gitea #152 裁定(jesse 2026-11-01 确认)、#153 正文、#154 2026-10-28 评论 36265 的原型(https://claude.ai/artifact/PbnR2pkQuaWVtESzrh5ECq)和 2026-11-01 评论 37984。数据层见 annual-package-v1.md。
一条链
- 入口:「我的报告」页多一张「年运」卡片,直接进
/reports/annual(放在/reports下面,侧栏仍亮「我的报告」)。没有单独的入口页。 - 遮罩:页面先请求
GET /api/annual/overview?subject=&kind=(Next 路由 → Python/api/annual/package,detail: "slim",几 KB)。返回人物、范围、三条注意事项、出生时间是否确认、价格,以及这一年是不是已经写过。写过的(或正在写的)直接打开,不出遮罩,也不再扣点。 - 开始:
POST /api/reports {reportType: "annual_full", subject, rangeKind, situation}。服务端预留annual.full的点数,建personal_reports一行(report_type = annual_full,范围键放在requested_themes,例如annual:birthday_year:2026),把范围和现状存成personal_report_sections的annual-report-input,入报告队列。 - 算:worker 调 Python
POST /api/annual/report_facts(scripts/annual_service/report_facts.py)。这是写手唯一能用的材料:本命底子、年内各段及走势、转折点、候选窗口、各领域信号、分歧、技法执行表。 - 写:按顺序一节一节写(
src/lib/annual-report-generate.ts,写手src/mastra/annual-report.ts,没有工具、记忆和技能)。每写完一节就把快照存进annual-report-snapshot,页面每 2.5 秒读一次,写好的那一节出现,下一节显示「正在写这一节……」。 - 检查:每一节过程序检查(
gateSection):格式、确定性用语、死亡灾祸疾病诊断、正文里出现具体日期、回看写成「你已经经历了」、重复标题、段 / 窗口 / 行的 id 对不上。不过的那一节带着原因重写一次,再不过整份停下。 - 结束:写完结算
annual.full(complete_usage,事件键annual.full),状态改为ready、schema_version = annual_report.v1。中途失败按报告队列原来的规则重试;最终失败释放预留,不扣点(遮罩上「写到一半断掉不扣」)。
报告结构(#153)
| 节 | id | 内容 |
|---|---|---|
| 先看这个人 | person |
D1 上升、月亮、宫主、功能吉凶、格局(只给名称和组合,不复述生产器的效果句) |
| 这一年总览 | overview |
年盘(上升及上升主、年主、Muntha 及 Muntha 主)、各段走势、最该记住的 1–3 个窗口 |
| 工作 / 钱 / 感情与关系 / 家 / 精力与作息(学习) | 领域 id | 先底子再今年,分「回看 / 换年盘后或接下来 / 例外窗口 / 年尾」;盘上看不出信号的领域只写一段「这一年」,并说明看不出什么 |
| 转折的时间点 | windows |
每个窗口六项:时间范围(程序给)、主要主题、支持依据、分歧与限制、现实条件、建议行动;盘面依据和限制是程序行,折叠 |
| 剩下的日子怎么过 | remaining |
表格「时间 | 事情 | 怎么安排」,行是现在及以后的各段,时间和走势程序给 |
| 一句收尾 | close |
一句 |
| 计算依据 | 程序 | 计算参数、口径、技法执行情况、分歧与限制、没有纳入的 |
身体那一节只写作息和精力,不写疾病判断。
写法约束(裁定 + #154)
- 每段时间只说偏顺 / 偏紧 / 平稳 / 有顺有紧,照卡片的「走势」写,模型不能改,也不能写得更肯定;具体的事一律「可能」。
- 不写死亡、灾祸、别人的私事,不做医疗诊断;恋爱、确定关系、法律婚分开说;看不出的情况不当成事实。
- 回看写成「这段时间是否出现了……」。
- 重叠不等于独立印证:罗睺计都算一条轴,Mudda 和 Patyayini 算一层,同一套 Vimshottari 的各级算一个来源;有压力和限制的照实写,不删反证。
- 技法执行表与个人报告同一做法:
Functional Benefic/Malefic一行写功能吉星和凶星;MEVG / Global Web Evidence和Real Case Calibration都是 blocked(未做外部资料核对和真实案例校准,不作准确率声明)。
现状(遮罩里,可不填)
关系状态、工作 / 学习、最关心的(最多三项)、已有的计划(一行,80 字以内)、不想看的。只用来选择怎么写:最关心的领域排前面;不想看的那一节不写(页面写「这一节按你的选择没有写。」);在读书或关心学习时多一节「学习」;关系状态决定措辞,不用来倒推盘一定准。现状不存进人物档案,只跟这一份报告存。
计费
- 功能键
annual.full,迁移20261101120000_annual_full_report.sql(报告类型、schema、功能键白名单,做法同synastry.full)和20261101120100_annual_full_pricing.sql(三档模型都发布 20 点,已有在用价格的不覆盖)。后台「功能定价」可改,标签「年运报告(annual.full)」。 - 一份报告扣一次:创建时预留,写完结算,失败释放;同一人同一范围已经写过的直接打开,不再扣。
- 价格读不到时遮罩写「计费配置不可用」,按钮不可点;点数不够写「点数不够。」和「去补点数」。
默认口径(待占星师确认)
以下都集中在一处,改一行即可:Python scripts/annual_service/report_facts.py 的 CONFIG / HOUSE_DOMAINS,前端 src/lib/annual-report-sections.ts(分段与写法)。
- Narayana 骨架:用产品时间轴现行的旧算法(
narayana_skeleton_profile = "legacy");Sanjay Rath 版只并列参考,不算第二份支持(narayana_rath_counts_as_support = False)。 - Tithi Pravesha:保持生产器自己的地点规则(出生地、出生固定偏移),只作独立年度视角,不并入 Tajika 年,不进候选窗口(
tithi_pravesha_in_windows = False)。 - 接触:只算精确合相(经度相等)、换宫和停滞,不算容许度相位;候选窗口只由已计算的边界和这些接触组成。
- 走势:只看本命骨架那一段的 Vimshottari 小运、细运和 Narayana 小运宫主的功能吉凶(本命上升),同一颗星只算一次;有吉有凶写「有顺有紧」,都没有写「平稳」。罗计不单独定功能吉凶。Mudda、Patyayini 只写年内怎么展开,不参与投票(裁定「两边各负其责,不做简单投票」)。
- 窗口:21 天内、跨度不超过 45 天的事件聚成一组,至少两个互相独立的来源;按来源数排序取 6 个(上限 8);出生时间没确认时,含 Vimshottari / Narayana 或按上升数宫的窗口前后各放宽 14 天并标出。最该记住取还没过去的、来源最多的前三个。
- 领域对应宫:工作 10、6;钱 2、11;感情与关系 7、5;家 4;精力与作息 1、6、12;学习 4、5、9。分盘:工作 D10,钱 D2 / D11,关系 D9(加 A7、UL、DK),家 D4,学习 D24;出生时间没确认时 D10、D11、D24 不用。工作另看 A10。
- 年内分段:本命小运、细运、Narayana 小运和换年盘的边界切段,短于 21 天的并到相邻一段。回看 = 观测日前三个月内结束的段;更早的段只作「更早」。
- 出生时间「已确认」:
birth_time_status为accepted(校正后采用)或confirmed。没确认时遮罩多一行:本人带「先做生时校正」链接,别人不带。
后续(不在本期)
- 出生时区 / 夏令时:排盘按出生资料里的固定偏移读出生时钟。用 IANA 时区显示时,有夏令时的年份会看到不同的偏移(例:上海 1986–1991 年有夏令时,1990-06-15 12:00 按 +8 读,而当地当时是 +9)。出生资料里 IANA 区与固定偏移不一致的情况,需要单独定规则,引擎行为本期不动。
- 所在地年盘、行运的 BAV / SAV 与 Vedha、土星过月阶段、英文版、导出。
- 占星师审读样例报告(公开名人盘或虚构盘 2–3 份)。
测试
- Python:
tests/test_annual_report_facts.py(卡片形状、各段连续覆盖、走势只看本命骨架、窗口按默认口径、出生时间没确认时放宽与细分盘停用、领域卡片、slim 包)。 - 前端:
frontend/tests/annual-report.test.tsx(结构与现状、按顺序写并逐节保存、检查不过重写一次再停、检查规则、证据和提示、窗口程序行、遮罩与原型一致、写作中的页面、「我的报告」卡片、计费键与迁移),用真实引擎输出frontend/tests/fixtures/annual-report-facts.json,写手是测试里的替身,不调真实模型。