merge: upstream sync 10 into the data audit branch
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y # Conflicts: # docs/BUG_HISTORY.md
This commit is contained in:
@@ -1,5 +1,15 @@
|
||||
# 印度占星 Skill 更新日志
|
||||
|
||||
## 2026-11-04 — 上游同步第十轮:研究快照移到上游最新版,三处计算按上游修正
|
||||
|
||||
- 上游研究版 Skill 的只读快照更新到上游 main 最新提交 `5fb8379c`;新快照不再带私人样例的说法。
|
||||
- 解读流程、PDF 读盘说明和两个命令的用法里残留的私人出生样例,换成上游用的公开名人样例。
|
||||
- 五份参考说明按上游的原文更正:Argala 次级看 5 宫、由 9 宫阻挡;Saham 用表 74 全部 36 项;十六分盘权重 D27 为 0.5、D30 为 1;Yogi 点说明标明当前公式;解读流程加上「开场也要有条件、没查到不等于不成立」的全文证据边界。
|
||||
- 分盘联动里 D12 一列现在有宫位(以前一直是空的);星座名异常时报错,不再当成白羊(BUG-1541)。
|
||||
- 指定日期的完整解读里,Narayana 当前段、星宿大运年龄、年运备用年龄都按那一天算;年运备用年龄到公历生日才加一岁(BUG-1542)。
|
||||
- KP 子主星和宫头用原始度数和含秒的时刻,不再用显示用的四舍五入值;只影响贴着分界的行星(BUG-1543)。
|
||||
- 网页对话的提示词没有变化。Skill 版本不变;没有数据库变更。
|
||||
|
||||
## 2026-11-03 — 输入框:单行起步,字多了变两层(产品定的方案 2)
|
||||
|
||||
- 空着或只有一行字时,输入框是一条圆胶囊:电脑上 64px 高,手机上 56px 高,左边「常用问题」,中间输入,右边一颗 40px 的圆形发送键(可点区域 44px)。占位字仍是「想聊什么都可以」。
|
||||
|
||||
@@ -261,7 +261,7 @@ adapter available 解释为已完成 VedAstro、PyJHora/JHora 或 jyotishganit r
|
||||
**凡是用户询问事业、婚恋、财务、事件应期、历史回测或技法可靠性,必须先读取 `references/strict-workflow-router.md`。**
|
||||
|
||||
核心要求:
|
||||
1. 先判断问题类型,再自动选择 `career-timing-strict` / `relationship-timing-strict` / `wealth-timing-strict` / `event-timing-strict` / `event-verification-strict`。
|
||||
1. 先判断问题类型,再自动选择 `career-timing-strict` / `relationship-timing-strict` / `finance-timing-strict`(兼容 `wealth-timing-strict`)/ `event-timing-strict` / `event-verification-strict`。
|
||||
2. 用户不需要知道 Chara Dasha、A10、Argala、Shadbala、Ashtakavarga 等技法名称;AI 必须按问题类型自动调用。
|
||||
3. 必须产出 Technique Audit Table,说明每项高级技法是否调用、结果是什么、缺失会如何降低置信度。网页由界面折叠展示,口语正文不要再贴该表。
|
||||
4. 不得把未实现或未调用的技法静默省略;A10/Karma Pada、Pushkara、Vargottama、Dasha Sandhi 已进入 full-reading 输出;Bhava Chalit 与 Sudarshana Chakra 已进入 complete,可正常纳入 Technique Audit Table。
|
||||
|
||||
@@ -21209,6 +21209,54 @@
|
||||
- 复发自:BUG-1165 / BUG-1182(示例句被照抄)。BUG-1182 的防复发只禁了示例括号里「宫位 → 人物行为」的读法,没有禁写死的请求句和范围句,也没有给规则总量设上限,所以未拦住。
|
||||
- 修复版本:分支 `codex/consult-pattern-voice-20261104`。
|
||||
|
||||
## BUG-1541 | 完整解读的分盘联动里 D12 一列永远没有宫位;坏星座名被当成白羊
|
||||
|
||||
- 状态:resolved(代码 + 回归测试;待部署)
|
||||
- 首次发现 / 最近更新:2026-11-04(上游同步第十轮核对上游 `cf6c316d`、`f60568a0`)/ 2026-11-04
|
||||
- 影响面:`scripts/jyotish_engine.py` `calc_inter_chart_linkage`、`calc_all_inter_chart_linkages` 与 `_cmd_full_reading` 的调用;完整解读 `modules.inter_chart_linkage`;咨询数据卡在分盘本身没有宫位时回落读这里(`scripts/consult_card_domain_facts.py`)。
|
||||
- 现象:D12 一列每颗星的 `house` 都是 `None`;D1 / D9 / D10 某颗星的星座名不在十二星座表里时,按白羊算宫位,不报错。
|
||||
- 触发条件:任何有 D12 的完整解读;星座名异常时。
|
||||
- 根因:D12 加进联动表时上升位置写死成 `None`,完整解读已经算好的 `d12_asc_idx` 没有传进去;星座查表失败时默认取下标 0。上游同一缺陷,10-16 修复,我方第九轮只搬了甲批,没有核对这两个提交。
|
||||
- 修复:两个函数加 `d12_asc_idx` 参数,完整解读把已算好的 D12 上升传进去;星座名不认识、上升下标不是 0–11 的整数时抛 `ValueError`,由完整解读的 `try` 记进 `errors`(咨询原生层由 `_guard` 记成 `blocked`),不再静默当白羊。
|
||||
- 验证:新测试 `tests/test_upstream_sync10_d12_linkage.py`(移植上游 `tests/test_inter_chart_d12_house.py` 并补坏上升下标):十二个 D12 上升各算一次宫位;缺 D12 上升仍为 `None`;坏星座、坏上升报错;完整解读调用的最后一个参数是 `d12_asc_idx`。改前 18 条失败、改后 19 条通过;`test_consultation_native_layers.py`、`test_flying_star_audit.py`、`test_full_reading_module_parity.py` 20 条通过。
|
||||
- 影响输出:完整解读联动表的 D12 宫位从空变成有值;咨询卡 D12 宫位只在分盘本身没有宫位、且出生时间精度够时才会读到(精度不够仍是 withheld)。计算口径没有改,不涉及冻结身份文件。
|
||||
- 防复发:上述测试。
|
||||
- 关联记录:BUG-1483~BUG-1490(第九轮甲批)、issue #141。
|
||||
- 复发自:无
|
||||
- 修复版本:分支 `codex/upstream-skill-sync-20261104`,待合并。
|
||||
|
||||
## BUG-1542 | 指定日期的完整解读里,Narayana 当前段、星宿大运年龄和年运备用年龄仍按今天算
|
||||
|
||||
- 状态:resolved(代码 + 回归测试;待部署)
|
||||
- 首次发现 / 最近更新:2026-11-04(上游同步第十轮核对上游 `933f254e`)/ 2026-11-04
|
||||
- 影响面:`scripts/jyotish_engine.py` `cmd_full_reading` 的 Step 4.13 Narayana(`today_dt`)、星宿大运年龄(`nak_age`)、Step 9 Tajika 备用年龄(`age`)。
|
||||
- 现象:传了 `transit_date`(回放、年运、指定日期的报告)时,Vimshottari 与行运按该日期算,Narayana 当前段和星宿大运按运行当天算,同一份报告里混着两个日期。没给年龄时,年运备用年龄用 `天数 // 365`,每四年早一天进下一岁,生日前几天就按新一岁起年盘。
|
||||
- 触发条件:完整解读带 `transit_date`,或只带 `today`;年运没给年龄。
|
||||
- 根因:这三处各自写了「今天」:Narayana 只读 `args.today`,星宿大运和年运备用年龄直接用 `datetime.now()`;而 `today_str` 与 `transit_reference_date` 已经按 `transit_date → today → now` 取。上游同一缺陷,10-16 修复,第九轮没核对这个提交。
|
||||
- 修复:三处都按 `transit_date → today → now` 取观察日期;年运备用年龄按公历生日算(到了生日才加一岁)。提示文字不变。没有照搬上游的 `target_year` 分支和 `total_seconds` 年龄(我方这里没有 `target_year`,Narayana 年龄沿用 `days / 365.25`)。
|
||||
- 验证:新测试 `tests/test_upstream_sync10_observation_date.py`(移植上游 `test_full_reading_observation_date.py`、`test_tajika_report_age.py`):四个日期变量对四种入参取同一日期;年运备用年龄在生日前后、`transit_date` 优先、给了年龄不覆盖;2000-01-01 到 2039-12-25 是 39 岁不是 40;星宿大运年龄按观察日期。改前 10 条失败、改后 11 条通过。
|
||||
- 影响输出:只在请求日期不是今天时变化(回放、年运、指定日期);网页咨询按当天算的结果不变。年运备用年龄在生日前约 N/4 天内(N 为年龄)会少一岁,对应的年盘年份随之更正。不涉及冻结身份文件。
|
||||
- 防复发:上述测试;同一份报告里新增日期变量要沿用同一取法。
|
||||
- 关联记录:BUG-1541、BUG-1220(年盘保留秒)。
|
||||
- 复发自:无
|
||||
- 修复版本:分支 `codex/upstream-skill-sync-20261104`,待合并。
|
||||
|
||||
## BUG-1543 | KP 子主星与宫头用的是显示用的四舍五入值
|
||||
|
||||
- 状态:resolved(代码 + 回归测试;待部署)
|
||||
- 首次发现 / 最近更新:2026-11-04(上游同步第十轮核对上游 `26d5a52d`)/ 2026-11-04
|
||||
- 影响面:`scripts/jyotish_engine.py` `cmd_kp`(命令 `kp`、`/api/kp` 一类入口)。KP 在商业覆盖层仍是 `reference_only`。
|
||||
- 现象:行星落在星主 / 子主 / 子子主分界附近、或宫头附近时,KP 表可能差一格。
|
||||
- 触发条件:行星度数或宫头离 KP 分界小于约 0.0001 度;出生时间带秒。
|
||||
- 根因:`cmd_kp` 把 `calculate_bhava_boundaries()` 返回的宫头(保留 4 位小数)、行星的 `degree_in_sign`(保留 4 位小数)和星盘结果里的 `julian_day`(保留 6 位小数,约 0.09 秒)交给 KP 分析,KP 分界是按原始经度切的。上游同一缺陷,10-16 修复,第九轮没核对。
|
||||
- 修复:按出生时刻重算儒略日(与 `compute_chart_data` 同一公式,含秒);宫头改用 `calculate_cusps()` 原值;行星度数用 `degree_raw % 30`,没有原值时才退回显示值。
|
||||
- 验证:新测试 `tests/test_upstream_sync10_kp_unrounded_inputs.py`(移植上游 `tests/test_kp_unrounded_inputs.py`):儒略日、宫头、行星度数都是原值;改前失败、改后通过。`test_kp_system.py`、`test_kp_cusp_house_assignment.py`、`test_kp_monthly_report_packet.py` 5 条通过、2 条跳过;公开名人盘实跑 `cmd_kp` 正常返回。
|
||||
- 影响输出:只有贴着分界的行星或宫头会换一格,其余逐字节相同。不涉及冻结身份文件。
|
||||
- 未搬:同一上游提交里的 Vivaha Saham 昼夜公式与 Yoga 燃烧状态透传,见本轮进度记录。
|
||||
- 防复发:上述测试;显示用的取整值不进计算。
|
||||
- 关联记录:BUG-1383(KP 边界,第八轮)、BUG-1541、BUG-1542。
|
||||
- 复发自:无
|
||||
- 修复版本:分支 `codex/upstream-skill-sync-20261104`,待合并。
|
||||
## BUG-1545 | Narayana 大运(旧算法)过了第一轮就把第一轮重放,六七十岁以上的人拿到错的当前运
|
||||
|
||||
- 状态:resolved(引擎 + 回归测试;未部署)
|
||||
|
||||
@@ -25,3 +25,8 @@
|
||||
- **事件映射(甲8)**:在 77 例上,±10 / ±30 / ±60 分钟三档的回放头名分别下降 13~17、10~16、8~21 个百分点,主要来自事业一行扩到 10、6、9、11 宫。
|
||||
- **月亮行运(甲9)**:按 0.25 权重加入月亮起点,结果不变;按 1.0 权重,±60 分钟档降 1.3 个百分点。
|
||||
- 详细记录:`affliction_weight_trial_2026_10_03.md`、`rectification_mapping_trial_2026_10_03.md`。
|
||||
|
||||
## 2026-11-04 复核(上游 main `5fb8379c`)
|
||||
|
||||
1. Narayana:上游 `narayana_dasha_full_report` 已把 seed / sequence / duration / dual-lord profile 传给 `calc_narayana_mahadasha`,另加 `cycle_count` 与 AD `strength_profile`。用虚构行星位置在三个上升上实跑,`kn_rao` 与 `legacy_local` 的大运序列不同,第 1 条已修。命令行默认仍叫 `kn_rao`,这个名字指什么仍未说明。我方默认 legacy,标为旧算法,另给 Rath 视图(BUG-1215、BUG-1218)。我方没有第二周期,也没有 AD 强度口径(`6859b263`,第九轮决定不做)。
|
||||
2. 8 星制 Karaka:上游 `jaimini.KARAKA_8` 已改为 BPHS 次序,罗睺按 30 减星座内度数排;我方同样已修,两边一致。
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# PROGRESS · 上游同步第十轮(2026-11-04)
|
||||
|
||||
- 分支:`codex/upstream-skill-sync-20261104`;基线 `origin/staging` `db2fc3fc`
|
||||
- 上游:`732642856/yinduzhanxing` main `5fb8379c4f3e649cb4804065c9a3059e4bf633fe`(2026-10-21,到 11-04 仍是 HEAD)
|
||||
- 上次镜像:`b9a0ef8f`(已被上游改写,提交时间对应 `dc3b8fef`);第九轮甲 / 乙批已按语义移植到 `5fb8379c`,但没有动镜像
|
||||
- 范围:本轮查 skill 文档层(SKILL.md、references/)和第九轮没有核对过的引擎修正;不推送,不碰 staging / main
|
||||
- 预检:`scripts/pre_work_check.py --remote-timeout 8 --command-timeout 45` 全部通过(外部引擎适配、远端可见性、碎片扫描、聚焦测试)
|
||||
|
||||
## 做了什么
|
||||
|
||||
| 提交 | 内容 | 风险 |
|
||||
| --- | --- | --- |
|
||||
| `3bae79fb` | 用导入器 `--apply` 从干净克隆镜像上游 `SKILL.md` 到 `references/upstream/yinduzhanxing/`;`source-manifest.json`、`import-plan.json`、导入记录 `commit-5fb8379c….json` 改钉 `5fb8379c`;b9a0ef8f 的导入记录和测试留作历史 | 仅文档 |
|
||||
| `297e27e0` | 把残留的私人样例(4 月 17 日 14:45、约北纬 36.5 东经 114.2)换成上游用的公开样例(1935-06-21 Cajarc):`ai-reading-workflow-prompt.md`、`pdf-chart-reading-guide.md`、`cmd_narayana_dasha.py` / `cmd_solar_return.py` 的用法说明 | 仅文档 |
|
||||
| `2539d57f` | 五份参考文档按上游的原文更正:Argala 次级为 5 / 9 宫、Saham 表 74 全 36 项、十六分盘 D27 0.5 / D30 1、Yogi 公式说明(路径改成我方 `scripts/annual_native/yogi_sphuta.py`)、解读流程加 10-02 全文证据边界;`finance-timing-strict` 别名对齐 | 仅文档 |
|
||||
| `4b6aa087` | BUG-1541:D12 分盘联动按 D12 上升算宫位;坏星座名报错,不再当白羊(上游 `cf6c316d`、`f60568a0`) | 改对外输出 |
|
||||
| `8137c692` | BUG-1542:完整解读 Narayana 当前段、星宿大运年龄、年运备用年龄统一按 `transit_date → today → now` 取日期;备用年龄按公历生日(上游 `933f254e`) | 改计算 |
|
||||
| `9d69cd56` | BUG-1543:KP 用原始宫头、原始行星度数和含秒的儒略日(上游 `26d5a52d` 的 KP 部分) | 改计算(仅分界附近) |
|
||||
|
||||
三处引擎文件都不在校正冻结清单(`sealed_holdout_rerun.PRODUCTION_FILES`、dataset `frozen_scoring.files`)里,不需要按 ERR-110 重冻。
|
||||
|
||||
## 没有搬的
|
||||
|
||||
| 上游 | 原因 |
|
||||
| --- | --- |
|
||||
| `SKILL.md` 正文(真源索引 09-15、分类 skill 联用、技法查漏编译链、PL9 / VedAstro 长段、P0/P1 回填长段、Shadbala / Dasha 升格门槛措辞) | 我方 `SKILL.md` 是商业入口,导入策略把它列为保护路径;这些段落指向我方没有的文件(`skills/<family>/`、`technique_ontology.json`、`current_capability_truth_index_2026_09_15.md` 等),或已有更短的商业版。研究原文已在快照里 |
|
||||
| `references/strict-workflow-router.md`:MEVG 改成「可选」、外部 oracle 缺口不再 `blocked`、新增 `interpretation_status_contract.md` | 与本仓 AGENTS.md §3、§4(MEVG 必做、缺口必须 blocked 或降级)冲突;路由章节会进对话提示词 |
|
||||
| `bphs-ch48-narayana-dasha.md` 新版 | 描述的第二周期(`cycle_count`)与 AD 强度口径我方没有;我方默认是标为旧算法的 legacy 加 Rath 视图(BUG-1215、BUG-1218) |
|
||||
| `quick-reference-guide.md`、`technique-capability-matrix.md`、`functional-role-profile.md` 的差异 | 我方较新(`marriage-match` 七项、#163 盘面说明) |
|
||||
| 上游独有的 113 个顶层 references(rangacharya / raman 研究包、web intake、skill family router、MEVG 审计等)和 1 600 多个 oracle / 书籍 / 案例文件 | 研究资产或依赖上游分类 skill;不进商业包 |
|
||||
| `26d5a52d` 的 Vivaha Saham 昼夜公式 | 需要在完整解读 Step 16 之前算昼夜,还要改 `consultation_native_layers.build_vivah_saham`(没有出生地时刻);夜生盘的婚姻点会变,需要产品与数据核对 |
|
||||
| `26d5a52d` 的 Yoga 燃烧状态透传 | 我方 `cmd_yoga` 已分叉(第 5 字段 `R` 逆行),要另核 |
|
||||
| `0acf7833`、`01f53764`(报告表格与英文报告) | 上游 PL9 渲染器,我方报告链不同 |
|
||||
| `b4dada9a`、`7e5498f6`(年运计算缓存范围) | 依赖上游 `annual_calculation_cache.py` 等研究回放 |
|
||||
| `6859b263`(Narayana 小运强度口径)、`2f52cfca`(karaka_calculator)、33 个未接入大运模块 | 第九轮已决定不做或另评估,原因不变 |
|
||||
|
||||
## 跑过的检查
|
||||
|
||||
见本文件末尾「验证」一节。
|
||||
|
||||
## 两处 10-03 上游问题的现状
|
||||
|
||||
1. Narayana 的 K.N. Rao profile:上游 `narayana_dasha_full_report` 现在会把 seed / sequence / duration / dual-lord 传给 `calc_narayana_mahadasha`(另加 `cycle_count`、`strength_profile`)。拿虚构行星位置在三个上升上实跑,`kn_rao` 与 `legacy_local` 的大运序列不同,机制上已修。上游命令行默认仍是 `variant_profile='kn_rao'`,「K.N. Rao 版 Narayana」这个名字指什么仍未说明。我方:默认 legacy 并标为旧算法,另给 Rath 视图,已删 `--variant-profile`;非 legacy profile 同样会传进去。我方没有第二周期和 AD 强度口径。
|
||||
2. 8 星制 Chara Karaka:上游 `jaimini.KARAKA_8` 已改为 BPHS 次序(第 5 位 PiK、第 8 位 DK),并有罗睺倒数度数(`974403a6`);我方同样已修。两边一致。
|
||||
|
||||
## 验证
|
||||
|
||||
| 检查 | 命令 | 结果 |
|
||||
| --- | --- | --- |
|
||||
| 预检 | `scripts/pre_work_check.py --remote-timeout 8 --command-timeout 45` | 全部通过 |
|
||||
| Python 快速门 | `python scripts/run_quality_gate.py --profile quick --skip-frontend-runtime`(在第 6 个提交 `9d69cd56` 上) | 通过(py_compile 448 个文件,pytest 395 秒) |
|
||||
| 新测试 | `tests/test_upstream_sync10_*.py` 三个文件 | 31 条通过;改前 D12 18 条失败、日期 10 条失败、KP 1 条失败 |
|
||||
| 快照与导入 | `test_upstream_import_plan.py`、`test_upstream_git_import_{b9a0ef8f,5fb8379c}.py`、`test_report_orchestrator_reader_contract.py`、`test_repo_privacy_markers.py`、`test_cross_project_contract.py`、`test_import_yinduzhanxing.py` | 通过 |
|
||||
| 联动相关 | `test_consultation_native_layers.py`、`test_flying_star_audit.py`、`test_full_reading_module_parity.py` | 20 条通过(台账里提到的不稳定用例这次没有失败) |
|
||||
| 前端 skill | `npx tsx --test tests/skill-*.test.ts tests/consultation-methodology.test.ts` | 48 条:47 通过、1 跳过(本机没有 docker) |
|
||||
@@ -552,3 +552,4 @@
|
||||
| — | — | **#163 星盘页术语与盘上标注(占星师答复 4–8)**:六力达标线、大运 / 小运 / 细运、运主落宫边框与「从运主起算」、Chara 运主、敌友默认上升主星与三种关系、瑜伽不连线、八分法 / Arudha 映射(Claude 直接执行) | 待验收 | `codex/163-terms-overlays` |
|
||||
| `TASK-birth-time-source-intake-20261102.md` | `PROGRESS-birth-time-source-intake-20261102.md` | **#144 第一单(jesse 选 A)**:建档六个出生时间来源选项;不再把来源换成固定误差,改填最早 / 最晚或「不清楚误差」;加列 `id_document`、记录方式、误差是否已知、时辰(只加不删);第二单(分项算稳定性)另开排队 | 待验收(Claude 11-02 完成 T1–T7;T5 原句仓内 0 处;迁移在本机 PostgreSQL 16 跑通,门禁 PG17 待复核;顺带 BUG-1513、1514) | `codex/birth-time-intake-144` |
|
||||
| —(issue #165,Claude 直接执行) | `PROGRESS-birth-time-stability-20261103.md` | **#144 第二单**:星盘页按用户给的出生时间范围逐分钟算九项(上升星座 / 度数 / 宫头、D9、D10 上升、月亮星座 / 星宿 / pada / 宫位),各说一致 / 有变化;先核实原始资料的提示(日期有疑问、时区未确认、上升或月亮星宿变化);大运周期边界原文;上升预检与两个扫描脚本显式传岁差与交点(BUG-1515);只记得时辰第三问,不改数据库 | 本地提交,待验收 | `codex/birth-time-stability-165` |
|
||||
| —(Claude 直接执行) | `PROGRESS-upstream-sync10-20261104.md` | **上游同步第十轮**:研究快照镜像移到上游 main `5fb8379c`;私人样例换成公开样例;五份参考文档按上游原文更正;引擎三处修正(BUG-1541 D12 联动宫位、BUG-1542 同一观察日期、BUG-1543 KP 原始输入)。Vivaha Saham 昼夜公式与 Yoga 燃烧透传未搬,待产品决定 | 待验收 | `codex/upstream-skill-sync-20261104` |
|
||||
|
||||
@@ -15,6 +15,16 @@
|
||||
|
||||
## ⚠️ 核心原则
|
||||
|
||||
### 全文证据边界(2026-10-02)
|
||||
|
||||
标题、开场第一句、摘要、卡片、正文、结尾建议均受相同证据约束。
|
||||
先回答问题不等于先作确定断言;条件性迹象在开场也必须保持条件性。
|
||||
计算完成、规则条件满足、传统解释、外部复核和现实事件是不同状态。
|
||||
未检测、检测失败或尚未验证不能写成“不成立”;可保留带规则与限制的候选格局。
|
||||
事业分别说明行业候选、工作方式、公众可见度与发展节奏,逐项绑定10宫星、10宫主、
|
||||
D10、A10、功能角色和强度等实际证据。禁止无依据的“幕后、专业交付、晚成”模板。
|
||||
不得用名人姓名或已知职业补全盲读;职业象征须保留相近候选与现实核验问题。
|
||||
|
||||
1. **不跳步**:每个阶段必须完成后才能进入下一阶段
|
||||
2. **不猜测**:数据缺失时标注"缺失",不编造数据
|
||||
3. **不锚定**:先输出星盘推导,再等用户反馈,不先知道用户生活再"找依据"
|
||||
@@ -307,7 +317,7 @@ Step 0.5: Karaka 系统识别与声明
|
||||
**示例输入**:
|
||||
- "1990年1月1日 12:00(示例) 示例城市"
|
||||
- "我出生于 1990-08-15 早上6:30 北京"
|
||||
- "April 17, REDACTED_YEAR, 2:45 PM, San Francisco, China (36.6N, 114.5E)"
|
||||
- "June 21, 1935, 11:00 AM, Cajarc, France (44.486N, 1.842E)"
|
||||
|
||||
**执行指令**(一条命令搞定所有计算):
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Argala 行星干预体系完整指南
|
||||
|
||||
> 2026-10-14 原文裁决:当前计算以 PVR《Integrated Approach》§§10.5–10.7(正文来源页117–118)为依据。第5宫是次级干预,第9宫是对应阻挡;计都所在参照星座逆向计数;双方数量相等不能直接判受阻,须比较强弱。本指南其余历史扩展(第8宫、性别条件、占位数量直接换算Rajayoga等级)没有在上述原文中得到支持,不得用作当前计算依据。下方旧矩阵只作为历史记录,不代表已核验规则。
|
||||
|
||||
> **适用场景**:分析行星对宫位的"锁门/开门"效应——哪些行星在帮助/阻碍某个宫位的结果实现
|
||||
> **版本**:v1.0.0 | **创建日期**:2026-04-24
|
||||
> **优先级**:⭐⭐⭐⭐⭐(K.N. Rao PAC-DARES方法论核心组件)
|
||||
@@ -57,12 +59,12 @@
|
||||
|
||||
### 2.2 次Argala(Secondary Argala)
|
||||
|
||||
**规则**:从目标宫位起算,第5宫和第8宫有次级Argala效应:
|
||||
**当前规则**:从目标宫位起算,第5宫有次级Argala,第9宫阻挡它:
|
||||
|
||||
| 干预宫位 | 名称 | 含义 | 条件 |
|
||||
|----------|------|------|------|
|
||||
| **第5宫** | 次级创造Argala | 智慧/创造力的干预 | 仅当该宫内有**男性行星**(Sun/Mars/Jupiter)时生效 |
|
||||
| **第8宫** | 次级隐藏Argala | 隐藏资源/危机转化的干预 | 仅当该宫内有**女性行星**(Moon/Venus)或**暗行星**(Rahu/Ketu/Saturn)时生效 |
|
||||
| **第5宫** | 次级Argala | 干预 | 与第9宫配对比较,不附加行星性别条件 |
|
||||
| **第9宫** | Virodhargala | 阻挡第5宫干预 | 数量相等时须比较强弱 |
|
||||
|
||||
### 2.3 Virodha Argala(反干预/解锁)
|
||||
|
||||
@@ -74,7 +76,6 @@
|
||||
| 第4宫 | **第10宫** | 外部职责抵消基础支持 |
|
||||
| 第11宫 | **第3宫** | 个人行动抵消网络收益 |
|
||||
| 第5宫(次级) | **第9宫** | 信仰/远见抵消创造力干预 |
|
||||
| 第8宫(次级) | **第2宫** | 资源消耗抵消隐藏力量 |
|
||||
|
||||
**判断规则**:
|
||||
- 如果主Argala宫有行星 → 有Argala
|
||||
@@ -272,4 +273,4 @@ E (Exchange) → S (Strength)
|
||||
- K.N. Rao PAC-DARES体系
|
||||
- B.V. Raman《Three Hundred Important Combinations》
|
||||
- Sanjay Rath《Jaimini Sutras》Argala章节
|
||||
- Parasara《Brihat Parasara Hora Sastra》Argala Adhyaya
|
||||
- Parasara《Brihat Parasara Hora Sastra》Argala Adhyaya
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"generated_at": "2026-10-21T15:49:21Z",
|
||||
"mirror_files": [
|
||||
{
|
||||
"license": "MIT",
|
||||
"source": "SKILL.md",
|
||||
"source_sha256": "5c1c0738fbe6f586fad36cfa13f602934dcea8f8d54c536655f6cb2091773d8d",
|
||||
"status": "applied",
|
||||
"target": "references/upstream/yinduzhanxing/SKILL.md",
|
||||
"target_sha256_after": "5c1c0738fbe6f586fad36cfa13f602934dcea8f8d54c536655f6cb2091773d8d",
|
||||
"target_sha256_before": "6bed459b8b971b189895e62aabfb90e41dbdf8f5b9e80a4b5330d40922fe21eb"
|
||||
}
|
||||
],
|
||||
"operator_review_required": true,
|
||||
"policy_version": 2,
|
||||
"privacy_scan": {
|
||||
"rejections": [],
|
||||
"scanned_files": 1,
|
||||
"status": "pass"
|
||||
},
|
||||
"protected_rejections": [],
|
||||
"schema_version": 1,
|
||||
"semantic_merge_files": [
|
||||
{
|
||||
"diff_summary": "manual semantic merge required: +93/-94 lines",
|
||||
"path": "SKILL.md",
|
||||
"source_sha256": "5c1c0738fbe6f586fad36cfa13f602934dcea8f8d54c536655f6cb2091773d8d",
|
||||
"status": "review_required",
|
||||
"target_sha256": "552080ec6901198de896012fa38badb4f055857183f7f263038f7dbf232eef4a"
|
||||
},
|
||||
{
|
||||
"diff_summary": "manual semantic merge required: +234/-177 lines",
|
||||
"path": "AGENTS.md",
|
||||
"source_sha256": "34165d7d95ba0b85f18e75ba526fd630ba9fed9abbf522cc2008f99a7d6e90f7",
|
||||
"status": "review_required",
|
||||
"target_sha256": "521292fa13037bc06f08c7cc002f506c3f0651eb4c9f2da55290969a8c615594"
|
||||
},
|
||||
{
|
||||
"diff_summary": "manual semantic merge required: +17/-6 lines",
|
||||
"path": "references/strict-workflow-router.md",
|
||||
"source_sha256": "a0bb91ba04bfb1218fa494ec07011c271e073fa9cac4e6f16fe05157554e9a96",
|
||||
"status": "review_required",
|
||||
"target_sha256": "b2dc3b8a86cf74d875841ee4714fd1be64bb594503088311e6622556175b90bc"
|
||||
},
|
||||
{
|
||||
"diff_summary": "manual semantic merge required: +700/-385 lines",
|
||||
"path": "scripts/unified_consultation_orchestrator.py",
|
||||
"source_sha256": "2c836861bc0132dee035050ecb4ae14ab9215140d2559086f0d3728c80e546fe",
|
||||
"status": "review_required",
|
||||
"target_sha256": "d249528a9f281917c6b895d198053cc81fb0c7d06666302658b11ef79495e7c3"
|
||||
},
|
||||
{
|
||||
"diff_summary": "manual semantic merge required: +83/-141 lines",
|
||||
"path": "scripts/report_orchestrator.py",
|
||||
"source_sha256": "27956a632793735ec660da312b66be967a35c0345edab90b8efe4a65663e4262",
|
||||
"status": "review_required",
|
||||
"target_sha256": "0fb80002561a6718088eceed0b20df2a8faa0adbc222756fadf8cd158a6957a6"
|
||||
},
|
||||
{
|
||||
"diff_summary": "manual semantic merge required: +10060/-4011 lines",
|
||||
"path": "scripts/jyotish_api_server.py",
|
||||
"source_sha256": "689468af6d4cfefb4e378ae0de2a6550d5b7b2f04f357a4b16adbb9b245139e5",
|
||||
"status": "review_required",
|
||||
"target_sha256": "b3aead367ef53003c72fc2cbdea3d827463d629fc90a173a8095eb81812b0d74"
|
||||
}
|
||||
],
|
||||
"source_commit": "5fb8379c4f3e649cb4804065c9a3059e4bf633fe",
|
||||
"source_mode": "git",
|
||||
"source_repository": "732642856/yinduzhanxing",
|
||||
"source_repository_url": "https://github.com/732642856/yinduzhanxing",
|
||||
"source_skill_sha256": "5c1c0738fbe6f586fad36cfa13f602934dcea8f8d54c536655f6cb2091773d8d",
|
||||
"source_tree_hash": "ee8bd9865cf11a6eb7f90705a262db8b2d145ae0cee6ee6eda32b311548f5aa2",
|
||||
"target_base_commit": "db2fc3fcfe155c5f5ed64000c46e2a669de54a1f",
|
||||
"target_repository": "root/Jyotisha",
|
||||
"tests_run": [
|
||||
"tests/test_cross_project_contract.py",
|
||||
"tests/test_import_yinduzhanxing.py"
|
||||
]
|
||||
}
|
||||
@@ -208,6 +208,36 @@
|
||||
],
|
||||
"hash_contract_result": "pass: pinned mirror remains b9a0ef8f; batch A is a semantic port of upstream main 5fb8379c; b9a0ef8f was rewritten and its timestamp matches dc3b8fef; SKILL.md was not re-mirrored; importer --apply was not run",
|
||||
"rollback": "git revert 8aed605a43ad8e235cd341ebcaeb7675503325e6 bd09485243000ea7012b865dbee04fc00c535005 c1bd59e97a76e914b884b650cae1adfb13b1e858 7bede9c99a056446648aa1e8fa36b3a4734a36eb 96312893b7ad7660e72081c81bf4bf031f0b38a0 b35c424945e578abe95fca69de5eff1a8e14c0e1 16bae006158aad8b493362ce1a51391626a95dca 9d3f59a87206d4b7f6c10f94c56565bbd98089a6 d226b0e5388cc3606272956bc5b9c2072685210d on branch codex/upstream-sync9-20261028"
|
||||
},
|
||||
{
|
||||
"source_repository": "732642856/yinduzhanxing",
|
||||
"source_commit": "5fb8379c4f3e649cb4804065c9a3059e4bf633fe",
|
||||
"target_repository": "jesse-ux/Jyotisha",
|
||||
"target_commit": "9d69cd5625456c452949da2e47c7ad68332b2b46",
|
||||
"change_class": "calculation_contract",
|
||||
"copied_files": [
|
||||
"references/upstream/yinduzhanxing/SKILL.md",
|
||||
"references/upstream/yinduzhanxing/source-manifest.json",
|
||||
"references/upstream/yinduzhanxing/import-plan.json",
|
||||
"references/cross_project_contract/imports/commit-5fb8379c4f3e649cb4804065c9a3059e4bf633fe.json",
|
||||
"references/ai-reading-workflow-prompt.md",
|
||||
"references/pdf-chart-reading-guide.md",
|
||||
"references/argala-complete-guide.md",
|
||||
"references/sahams-execution-guide.md",
|
||||
"references/shodasavarga-complete-guide.md",
|
||||
"references/yogi-avayogi-system.md",
|
||||
"references/event_judgment_wealth.md",
|
||||
"scripts/cmd_narayana_dasha.py",
|
||||
"scripts/cmd_solar_return.py",
|
||||
"scripts/jyotish_engine.py"
|
||||
],
|
||||
"dependency_delta": "none",
|
||||
"privacy_review": "pass: mirrored SKILL.md drops the private sample wording; the leftover private sample date, time and place in two references and two usage strings are replaced with upstream's public example; no production configuration, secret, or user data",
|
||||
"focused_tests": [
|
||||
"python -m pytest tests/test_upstream_import_plan.py tests/test_upstream_git_import_b9a0ef8f.py tests/test_upstream_git_import_5fb8379c.py tests/test_report_orchestrator_reader_contract.py tests/test_repo_privacy_markers.py tests/test_upstream_sync10_d12_linkage.py tests/test_upstream_sync10_observation_date.py tests/test_upstream_sync10_kp_unrounded_inputs.py"
|
||||
],
|
||||
"hash_contract_result": "pass: git-mode mirror moved to 5fb8379c with scripts/import_yinduzhanxing.py --apply from a clean clone; semantic-merge paths stay review_required; three engine fixes are semantic ports of cf6c316d/f60568a0, 933f254e and the KP part of 26d5a52d",
|
||||
"rollback": "git revert 9d69cd5625456c452949da2e47c7ad68332b2b46 8137c692b1bbe862bef83b13910437cb2549eb05 4b6aa08726cb5ec4c179c7ad89ec3e25ecfbe7d6 2539d57fee9da72f97045577279aaa3bdb3796fc 297e27e0bda9232d7de1c5747e1a14be3845db62 3bae79fbcae80a8db644f7f0252fadb1c9a5c4bc on branch codex/upstream-skill-sync-20261104"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
|
||||
- `lakshmi_dhana_activation_chain`
|
||||
- `yogi_asc_tight_orb_wealth`
|
||||
- `strict-workflow-router.md` 的 `wealth-timing-strict`
|
||||
- `strict-workflow-router.md` 的 `finance-timing-strict`(兼容 `wealth-timing-strict`)
|
||||
- `divisional-chart-deep-reading.md` 中的财富链 `D2 -> D4 -> D10 -> D11`
|
||||
|
||||
若调用不到,必须在 Audit Table 里标注其对置信度的削弱。
|
||||
|
||||
@@ -53,9 +53,9 @@
|
||||
| 出生日期 | 1990-01-01 | 年月日 |
|
||||
| 出生时间 | 12:00:19 | 时分秒,越精确越好 |
|
||||
| 出生地点 | 示例城市 | 城市名 |
|
||||
| 经度 | 115.5°E | 东经/西经 |
|
||||
| 纬度 | 36.6°N | 北纬/南纬 |
|
||||
| 时区 | UTC+8 | 相对于UTC |
|
||||
| 经度 | 122.4°W | 东经/西经 |
|
||||
| 纬度 | 37.8°N | 北纬/南纬 |
|
||||
| 时区 | UTC-8 | 相对于UTC |
|
||||
| 性别 | Male/Female | 用于关系分析征象星选择 |
|
||||
| Ayanamsa | Lahiri 23°51'11" | 恒星黄道校正值 |
|
||||
|
||||
@@ -244,9 +244,9 @@
|
||||
"date": "1990-01-01",
|
||||
"time": "12:00:19",
|
||||
"location": "San Francisco",
|
||||
"latitude": 36.6,
|
||||
"longitude": 115.5,
|
||||
"timezone": "UTC+8",
|
||||
"latitude": 37.7749,
|
||||
"longitude": -122.4194,
|
||||
"timezone": "UTC-8",
|
||||
"gender": "Male",
|
||||
"ayanamsa": "Lahiri 23°51'11\""
|
||||
},
|
||||
|
||||
@@ -47,7 +47,10 @@
|
||||
|
||||
## 四、当前真实边界
|
||||
|
||||
当前 skill 已能输出常见 36 个 Saham 与婚姻点等专项点。
|
||||
2026-10-14计算链更新:通用计算器已接入PVR表74全部36项及其昼夜例外。
|
||||
来源为《Integrated Approach》印刷页394–396;并保留独立婚姻点入口。
|
||||
额外旧候选项仍单独标为 `legacy_candidate_unverified`,不属于这36项的认证范围。
|
||||
这项源码更新不等于客户冻结版本已经更新或报告已经重新发布。
|
||||
|
||||
但必须保留的边界:
|
||||
|
||||
|
||||
@@ -56,8 +56,8 @@ BPHS提供的行星功能性吉凶量化系统(与Shadbala天文强度互补
|
||||
| D16 | — | — | 1 | 2 |
|
||||
| D20 | — | — | — | 0.5 |
|
||||
| D24 | — | — | — | 0.5 |
|
||||
| D27 | — | — | — | 1 |
|
||||
| D30 | 1 | 1 | 1.5 | 1.5 |
|
||||
| D27 | — | — | — | 0.5 |
|
||||
| D30 | 1 | 1 | 1.5 | 1 |
|
||||
| D40 | — | — | — | 0.5 |
|
||||
| D45 | — | — | — | 0.5 |
|
||||
| D60 | — | — | **5** | **4** |
|
||||
|
||||
@@ -7,11 +7,14 @@ description: 印度占星(Jyotish)专业解盘与推运系统。核心能力
|
||||
# 印度占星专业解盘与推运系统
|
||||
|
||||
> **版本**:v6.9.15 | **详细变更**:`CHANGELOG.md`
|
||||
> **对标状态**:中文用户端与技法覆盖领先;D1/D9/AV/Chara 等有守门,Dasha/Shadbala 外部 oracle 扩充仍在进行。
|
||||
> **对标状态**:中文用户端与技法覆盖领先;D1/D9/AV/Chara 等有守门,Dasha/Shadbala/Tajika 已进入分层证据治理阶段:部分 target-set / packet / source-bounded 链路已闭合,但 formal case admission、same-chart parity、production tuning 与 global oracle closure 仍不得过度宣称。
|
||||
>
|
||||
> **真相边界**:当前问题已不是“完全缺技法名称”,而是少数高价值传统深度仍未闭环;请优先修复精度与裁决链,而不是继续表面堆功能名。读取能力状态时必须优先使用 `references/oracle/effective_skill_capability_view_2026_07_19.json` 与 `references/oracle/skill_truth_overlay_2026_07_19.json`,不得直接把 `references/technique_registry.json` 的旧 `covered` 当作完整闭环。
|
||||
> **Ashtottari(2026-09-01)**:规则族冲突锁已部分解开 → `selected_rule_family_parameter_sensitive`;主源验证文档 `docs/research/ashtottari_primary_text_verification_2026_09_01.md`,适用族 `rahu_from_lagna_lord_kendra_trikona_plus_paksha_daynight`({4,5,7,9,10});未闭环项:第二引擎 oracle(`attach_external_same_profile_comparison`)。yn-1993 本盘不适用。
|
||||
> **当前真源索引(2026-09-15)**:读取能力状态时,优先使用 `docs/research/current_capability_truth_index_2026_09_15.md`、`python3 scripts/current_report_authority_snapshot.py --format json`、`python3 scripts/workspace_governance_audit.py`、`docs/research/pl9_full_parity_dashboard_2026_09_11.md` 与当前质量门输出。`references/oracle/effective_skill_capability_view_2026_07_19.json`、`references/oracle/skill_truth_overlay_2026_07_19.json`、`skill_gap_truth_audit_latest.md` 等旧快照只能作历史边界,不得覆盖 9 月以来的 closure / authority / report-export 事实。
|
||||
> **真相边界**:当前问题已不是“完全缺技法名称”,而是高价值传统深度的升格门槛:packet complete、source-bounded wired、external verified、formal admitted、production tuning allowed、global closure 必须分开写。请优先修复精度、证据仲裁、报告交付和状态真源,而不是继续表面堆功能名。不得直接把 `references/technique_registry.json` 的旧 `covered` 当作完整闭环。
|
||||
> **Ashtottari(2026-09-01)**:规则族冲突锁已部分解开 → `selected_rule_family_parameter_sensitive`;主源验证文档 `docs/research/ashtottari_primary_text_verification_2026_09_01.md`,适用族 `rahu_from_lagna_lord_kendra_trikona_plus_paksha_daynight`({4,5,7,9,10});未闭环项:第二引擎 oracle(`attach_external_same_profile_comparison`)。适用性必须按当前输入独立计算。
|
||||
> **执行总控**:`references/quick-reference-guide.md`
|
||||
> **分类 skill 联用**:按 `references/skill_family_router.json` 与本轮 `selected_skill_families` 逐个读取 `skills/<family>/SKILL.md`,遵循 `references/skill_family_handoff.md` 交接。综合模式各传统并列解释;路由记录不代表真实执行。
|
||||
> **技法查漏编译链**:`references/technique_ontology.json` 统一身份与别名。先运行 `python3 scripts/technique_source_adapters.py --write` 刷新 JH/PyJHora 命名技法和本地书籍主题候选,再运行 `python3 scripts/technique_gap_scanner.py --write --check-web` 对照注册表、书籍规则链和源码,生成各 skill 的缺口队列与用法包。文本命中或身份归并不等于可执行。
|
||||
> **严格路由**:`references/strict-workflow-router.md`(涉及事业/婚恋/财务/应期/技法验证时必须优先读取)
|
||||
> **机器注册表**:`references/oracle/effective_skill_capability_view_2026_07_19.json` + `references/oracle/skill_truth_overlay_2026_07_19.json` + `references/technique_registry.json` + `scripts/audit_capabilities.py`
|
||||
> **文章级细节模板**:`references/interpretation_template_registry.json` + `scripts/validate_interpretation_templates.py`
|
||||
@@ -25,7 +28,7 @@ description: 印度占星(Jyotish)专业解盘与推运系统。核心能力
|
||||
| 分盘 | D1-D144 + D2/D3变体 + 复合D-m×n + 自定义D-N(2-300) |
|
||||
| Bhava Chalit | Sripati/Porphyry/Equal/Whole Sign/Placidus/Koch 不等宫位调整 |
|
||||
| Sudarshana | Asc/Moon/Sun 三参考点盘 + 宫位收敛分析 |
|
||||
| Shadbala | absolute Rupa 分量求和;内部不变量通过,外部绝对值 oracle 扩充中 |
|
||||
| Shadbala | absolute Rupa 分量求和;入口 profile parity 与 packet fields 已推进,same-chart absolute parity / residual attribution / second oracle 仍需守门 |
|
||||
| Ashtakavarga | BAV+SAV+PAV(展开式)+Sodhita(净化式) |
|
||||
| KP系统 | reference-only / partial;不得按完整主链能力宣称,须以 `skill_truth_overlay` 为准 |
|
||||
| 合盘 | 16因子36分制(Ashtakoot+Kuta) |
|
||||
@@ -122,7 +125,7 @@ adapter available 解释为已完成 VedAstro、PyJHora/JHora 或 jyotishganit r
|
||||
VedAstro 官方 MCP 端点(`https://mcp.vedastro.org/api/mcp/public`)initialize/tools-list 正常,
|
||||
但 tools/call 层已知 resolver 故障(`Invalid or Outdated Call`)。**默认计算通路改为 REST 桥直连**:
|
||||
|
||||
- 脚本:`scripts/vedastro_rest_bridge.py`(horoscope / dasa 子命令,默认 yn-1993 参数)
|
||||
- 脚本:`scripts/vedastro_rest_bridge.py`(horoscope / dasa 子命令,默认公开回放基准参数)
|
||||
- 端点:`https://api.vedastro.org/api/Calculate`(已实测 `Status: Pass`,绕过 MCP resolver 故障)
|
||||
- 决策记录:`docs/research/vedastro_rest_bridge_default_decision_2026_09_01.md`
|
||||
- REST 桥返回 `Status: Pass` 视为官方 raw evidence 可用(对应 `official_verified`);失败时降级 `local_fallback`
|
||||
@@ -421,15 +424,16 @@ python3 scripts/validate_interpretation_templates.py --format markdown
|
||||
- Bhrigu Pada / RTN / Tithi Lord / Pancha Pakshi 必须作为辅助确认层;若没有主承诺和推运激活,输出置信度不得超过 C。
|
||||
- 所有文章/课程/网上说法默认归入 B/C 级线索,必须经过注册表中的 `required_cross_checks` 与 `forbidden_claims` 过滤。
|
||||
|
||||
## 当前最硬的未闭环点
|
||||
## 当前最硬的升格门槛
|
||||
|
||||
> 这部分比“再加几个技法名”更重要,决定 skill 距离传统软件级深度还有多远。
|
||||
> 这部分不是说基础能力不存在,而是说明哪些层级尚未从 `packet/source-bounded/verified slice` 升格到 `formal admitted/global closure/production tuning allowed`。
|
||||
|
||||
1. **Dasha 外部绝对边界闭环**
|
||||
- 当前 `ready_for_calibration: 4`
|
||||
- Dasha-only 目标集已由 PyJHora 黑盒证据推进到 3/3,但全局 Dasha/Shadbala 队列仍有非 Dasha 靶点缺字段,`production_tuning_allowed: false`
|
||||
2. **Shadbala 外部绝对值闭环**
|
||||
- 当前 absolute Rupa 结构自洽,但还不是外部绝对值完全校准
|
||||
1. **Dasha promotion gates**
|
||||
- 多数 Dasha 链路已 source-bounded wired;下一步是 p92 selector、p93-p103 Rashi selector/duration、p109-p120 row-date / child-row profile、p132/p133/p135 minute-boundary gates。
|
||||
- 不得把同案 producer 输出直接升格为 PL9 universal selector 或 formal case admission。
|
||||
2. **Shadbala same-chart absolute parity**
|
||||
- 入口 profile parity 与 packet fields 已推进;当前重点是固定同盘/ayanamsa/node mode 后,拿到安全第二来源原始表并解释 Mercury Chesta / Sthana residual。
|
||||
- `production_tuning_allowed: false` 前,禁止调生产常数贴合单一截图或 PDF。
|
||||
3. **Chara Dasha 共主仲裁尾差**
|
||||
- KN Rao benchmark 已过,但 Aquarius/Scorpio 的 Rahu/Ketu 共主强弱仲裁仍有尾差
|
||||
4. **KP ruling planets / 事件裁决细节**
|
||||
@@ -437,7 +441,7 @@ python3 scripts/validate_interpretation_templates.py --format markdown
|
||||
5. **Prashna 分支工作流**
|
||||
- 问事类型分支、裁决链、时机判断仍需更稳定的传统链路
|
||||
6. **Varshaphala / Tajika / Sahams 年运裁决深度**
|
||||
- 年盘骨架已在,第一条 Steve Jobs 1984 外部年运样本已闭环;但整体仍只有 `1/5`,事件裁决、权重层、Einstein 1905 等后续样本仍需继续成熟
|
||||
- 第一目标包已推进到 target-set verified;下一步是第二波公开样本、多年/边界样本、judgment templates 与 Mudda Dasha 事件链,不是继续证明年盘骨架存在。
|
||||
7. **Kalachakra / Narayana 等替代 Dasha 的成熟度边界**
|
||||
- 已有覆盖,但部分子层、边界口径、外部黑盒对照仍需继续收紧
|
||||
8. **高阶解释层整合**
|
||||
@@ -558,7 +562,7 @@ $PYTHON $SCRIPT <子命令> [参数]
|
||||
| `aspects` | 度数精确相位系统 |
|
||||
| `jaimini` | Jaimini Karaka/Karakamsha、A1-A12/UL、Graha Pada、Special Lagnas;Chara Dasha timing 为 KN Rao Method(covered;仍需保留共主仲裁与外部对标边界) |
|
||||
| `nakshatra-adv` | 高级Nakshatra(Tara Bala+Chandra Bala+Sub-Lord) |
|
||||
| `nakshatra-dasha` | 星宿大运推演(Ashtottari + Nakshatra-level Vimshottari);**Ashtottari 状态 2026-09-01 解冻**:`blocked_rule_source_conflict` → `selected_rule_family_parameter_sensitive`(可执行但 unverified;适用判定需走 `rahu_from_lagna_lord_kendra_trikona_plus_paksha_daynight` 族,详见 `docs/research/ashtottari_primary_text_verification_2026_09_01.md`,yn-1993 本盘因 Rahu 距太阳 8 宫不适用) |
|
||||
| `nakshatra-dasha` | 星宿大运推演(Ashtottari + Nakshatra-level Vimshottari);**Ashtottari 状态 2026-09-01 解冻**:`blocked_rule_source_conflict` → `selected_rule_family_parameter_sensitive`(可执行但 unverified;适用判定需走 `rahu_from_lagna_lord_kendra_trikona_plus_paksha_daynight` 族,详见 `docs/research/ashtottari_primary_text_verification_2026_09_01.md`,结果随当前盘独立判定) |
|
||||
| `nakshatra-full` | 星宿综合报告(本命 + 大运 + 过境星宿) |
|
||||
| `argala` | Argala门闩系统:主 Argala + Virodhargala + Rajayoga 分类 |
|
||||
| `tajika` | Tajika年运盘(Muntha+YearLord+Mudda Dasha) |
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
"schema_version": 1,
|
||||
"source_repository": "732642856/yinduzhanxing",
|
||||
"source_repository_url": "https://github.com/732642856/yinduzhanxing",
|
||||
"source_commit": "b9a0ef8f0f0de8714982a5aa7100f5aea16c9d09",
|
||||
"source_tree_sha256": "9ae737b02a48b38dca7d78094413b961a75e5abad17f2fe206f7dc3b1401d51a",
|
||||
"boundary": "Task 1 git-mode snapshot b9a0ef8f from origin/codex/add-birth-time-rectification-skill (not on main). The importer still mirrors only the pinned upstream root SKILL.md under references/upstream; none of these research scripts is copied into the commercial runtime. Semantic-merge destinations remain review-only except for files this commercial round copies by hand.",
|
||||
"source_commit": "5fb8379c4f3e649cb4804065c9a3059e4bf633fe",
|
||||
"source_tree_sha256": "ee8bd9865cf11a6eb7f90705a262db8b2d145ae0cee6ee6eda32b311548f5aa2",
|
||||
"boundary": "Tenth sync: git-mode snapshot 5fb8379c, upstream main HEAD on 2026-11-04. The nine plan sources below still exist at that commit. The importer still mirrors only the pinned upstream root SKILL.md under references/upstream; none of these research scripts is copied into the commercial runtime. Semantic-merge destinations remain review-only except for files this commercial round copies by hand.",
|
||||
"entries": [
|
||||
{
|
||||
"source": "scripts/evidence_maturity.py",
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"boundary": "Git source b9a0ef8f0f0de8714982a5aa7100f5aea16c9d09 was origin/codex/add-birth-time-rectification-skill (branch=codex/add-birth-time-rectification-skill, not on main). Only root SKILL.md is mirrored into this directory; commercial and rectification Skills remain protected. skill_sha256 is retained as a legacy alias of source_skill_sha256. Semantic-merge paths were reviewed by the importer and not overwritten. Ninth sync on 2026-10-28 (issue #141) follows upstream main 5fb8379c4f3e649cb4804065c9a3059e4bf633fe for batch A only: Yogini d268d519, Tithi 33537b31, Saham cb8a1ca7, Ashtottari 0712f98f, Kalachakra f353a096, Arudha 8b55630a, Darakaraka 45b3b66b, dasha boundary test 07fc5be3, aspects e628118d. b9a0ef8f was rewritten and is absent; its commit time matches dc3b8fef7f769758dd0e63bdab037cde8be194bc. source_commit, source_git_tree, and the skill hashes stay on the mirrored SKILL.md and were not re-imported.",
|
||||
"boundary": "Git source 5fb8379c4f3e649cb4804065c9a3059e4bf633fe is upstream main HEAD on 2026-11-04 (no upstream commits after it). Tenth sync on 2026-11-04 re-mirrors only root SKILL.md into this directory with scripts/import_yinduzhanxing.py --apply from a clean clone; commercial and rectification Skills remain protected. skill_sha256 is retained as a legacy alias of source_skill_sha256. Semantic-merge paths were reviewed by the importer and not overwritten. The previous mirror b9a0ef8f (rewritten upstream; commit time matches dc3b8fef) keeps its import record under references/cross_project_contract/imports as history. Engine content between dc3b8fef and 5fb8379c was ported semantically in syncs 8, 9 and 9b and is not implied by this mirror.",
|
||||
"import_policy_version": 2,
|
||||
"imported_at": "2026-09-09T07:40:00Z",
|
||||
"imported_at": "2026-11-04T04:00:00Z",
|
||||
"license": "MIT",
|
||||
"schema_version": 1,
|
||||
"skill_sha256": "6bed459b8b971b189895e62aabfb90e41dbdf8f5b9e80a4b5330d40922fe21eb",
|
||||
"source_commit": "b9a0ef8f0f0de8714982a5aa7100f5aea16c9d09",
|
||||
"source_committed_at": "2026-09-08T17:36:09Z",
|
||||
"source_git_tree": "864cab471cadb31b71a7256c995c12b7552d7cb5",
|
||||
"skill_sha256": "5c1c0738fbe6f586fad36cfa13f602934dcea8f8d54c536655f6cb2091773d8d",
|
||||
"source_commit": "5fb8379c4f3e649cb4804065c9a3059e4bf633fe",
|
||||
"source_committed_at": "2026-10-21T15:49:21Z",
|
||||
"source_git_tree": "6cd6160804ea7419d609ccd639cc537a8a81c3c9",
|
||||
"source_mode": "git",
|
||||
"source_repository": "732642856/yinduzhanxing",
|
||||
"source_repository_url": "https://github.com/732642856/yinduzhanxing",
|
||||
"source_skill_sha256": "6bed459b8b971b189895e62aabfb90e41dbdf8f5b9e80a4b5330d40922fe21eb",
|
||||
"source_tree_sha256": "9ae737b02a48b38dca7d78094413b961a75e5abad17f2fe206f7dc3b1401d51a"
|
||||
"source_skill_sha256": "5c1c0738fbe6f586fad36cfa13f602934dcea8f8d54c536655f6cb2091773d8d",
|
||||
"source_tree_sha256": "ee8bd9865cf11a6eb7f90705a262db8b2d145ae0cee6ee6eda32b311548f5aa2"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# Yogi / Ava Yogi / Duplicate Yogi 行星系统
|
||||
|
||||
> 2026-09-26 校正(上游 5fb8379c 同步,2026-11-04 移入):下文是保留的历史混合笔记,不是当前可执行公式。
|
||||
> 其中“Lagna+93°20′”、93°20′=6宿、结果为双子6°40′等说法相互矛盾,不能用于计算。
|
||||
> 当前原生 profile 为 Sun+Moon+93°20′,Avayogi 再加186°40′;93°20′是巨蟹3°20′,
|
||||
> 精确宿界归入 Pushya(Saturn)。计算以 `scripts/annual_native/yogi_sphuta.py`
|
||||
> (`YOGI_OFFSET`、`AVA_OFFSET`)为准。
|
||||
> 未找到明确来源的 Lagna 变体保持待考,不与当前日月公式合并。
|
||||
|
||||
> 来源:公众号文章(1-4印度占星),整合 Tithi Lord、财富业力、灵性距离、Dasha/Transit 激活等跨文章知识点。
|
||||
> 版本:v1.0 | 2026-04-25
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ def cmd_narayana_dasha(args, chart_data):
|
||||
narayana-dasha 子命令:计算并报告 Narayana Dasha(Rishi Dasha)。
|
||||
|
||||
用法:
|
||||
python jyotish_engine.py narayana-dasha --year REDACTED_YEAR --month 4 --day 17 \\
|
||||
--hour 14 --minute 45 --lat 36.47 --lon 114.2 --tz 8 --age 33
|
||||
python jyotish_engine.py narayana-dasha --year 1935 --month 6 --day 21 \\
|
||||
--hour 11 --minute 0 --lat 44.486 --lon 1.842 --tz 1 --age 33
|
||||
"""
|
||||
if chart_data is None:
|
||||
return "\n".join([
|
||||
|
||||
@@ -5,8 +5,8 @@ cmd_solar_return: Solar Return (Varshaphala) CLI 子命令
|
||||
Jyotish Vedic Astrology Skill — v6.0.18
|
||||
|
||||
用法:
|
||||
python3 jyotish_engine.py solar-return --year REDACTED_YEAR --month 4 --day 17 \
|
||||
--hour 14 --minute 45 --lat 36.4667 --lon 114.2 --tz 8 --target-year 2026
|
||||
python3 jyotish_engine.py solar-return --year 1935 --month 6 --day 21 \
|
||||
--hour 11 --minute 0 --lat 44.486 --lon 1.842 --tz 1 --target-year 2026
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
+39
-13
@@ -587,7 +587,7 @@ def calc_dispositor_chain(planet_name, planets_data, max_depth=12):
|
||||
return chain
|
||||
|
||||
|
||||
def calc_inter_chart_linkage(planet_name, d1_data, d9_data, d10_data, d12_data=None, d1_asc_idx=None, d9_asc_idx=None, d10_asc_idx=None):
|
||||
def calc_inter_chart_linkage(planet_name, d1_data, d9_data, d10_data, d12_data=None, d1_asc_idx=None, d9_asc_idx=None, d10_asc_idx=None, d12_asc_idx=None):
|
||||
"""
|
||||
计算行星在 D1/D9/D10 分盘之间的飞星落宫。
|
||||
返回 {chart_type: {sign, house_in_chart, lord_of_sign_in_chart}}
|
||||
@@ -599,7 +599,8 @@ def calc_inter_chart_linkage(planet_name, d1_data, d9_data, d10_data, d12_data=N
|
||||
('D10', d10_data, d10_asc_idx),
|
||||
]
|
||||
if d12_data:
|
||||
charts.append(('D12', d12_data, None))
|
||||
# D12 houses count from the D12 ascendant (upstream cf6c316d / f60568a0).
|
||||
charts.append(('D12', d12_data, d12_asc_idx))
|
||||
|
||||
for chart_name, chart_data, asc_idx in charts:
|
||||
if not isinstance(chart_data, dict):
|
||||
@@ -608,9 +609,14 @@ def calc_inter_chart_linkage(planet_name, d1_data, d9_data, d10_data, d12_data=N
|
||||
if not isinstance(pdata, dict) or 'sign' not in pdata:
|
||||
continue
|
||||
sign = pdata['sign']
|
||||
sign_idx = SIGNS.index(sign) if sign in SIGNS else 0
|
||||
if sign not in SIGNS:
|
||||
# An unknown sign used to become Aries silently.
|
||||
raise ValueError(f'Unknown sign in {chart_name}: {sign!r}')
|
||||
sign_idx = SIGNS.index(sign)
|
||||
house = None
|
||||
if asc_idx is not None:
|
||||
if isinstance(asc_idx, bool) or not isinstance(asc_idx, int) or not 0 <= asc_idx < 12:
|
||||
raise ValueError(f'Invalid ascendant sign index in {chart_name}: {asc_idx!r}')
|
||||
house = ((sign_idx - asc_idx) % 12) + 1
|
||||
lord = SIGN_LORDS.get(sign, '')
|
||||
result[chart_name] = {
|
||||
@@ -655,7 +661,7 @@ def calc_all_dispositor_chains(planets_data):
|
||||
return result
|
||||
|
||||
|
||||
def calc_all_inter_chart_linkages(d1_data, d9_data, d10_data, d12_data=None, d1_asc_idx=None, d9_asc_idx=None, d10_asc_idx=None):
|
||||
def calc_all_inter_chart_linkages(d1_data, d9_data, d10_data, d12_data=None, d1_asc_idx=None, d9_asc_idx=None, d10_asc_idx=None, d12_asc_idx=None):
|
||||
"""
|
||||
为所有行星计算 D1/D9/D10 分盘间飞星。
|
||||
需要各分盘的 asc_idx 来正确计算落宫。
|
||||
@@ -664,7 +670,7 @@ def calc_all_inter_chart_linkages(d1_data, d9_data, d10_data, d12_data=None, d1_
|
||||
for pname in ['Sun', 'Moon', 'Mars', 'Mercury', 'Jupiter', 'Venus', 'Saturn', 'Rahu', 'Ketu']:
|
||||
result[pname] = calc_inter_chart_linkage(
|
||||
pname, d1_data, d9_data, d10_data, d12_data,
|
||||
d1_asc_idx, d9_asc_idx, d10_asc_idx
|
||||
d1_asc_idx, d9_asc_idx, d10_asc_idx, d12_asc_idx
|
||||
)
|
||||
return result
|
||||
|
||||
@@ -13765,6 +13771,12 @@ def cmd_kp(args):
|
||||
_apply_ayanamsa(requested_report_ayanamsa)
|
||||
return {"error": "swisseph未安装"}
|
||||
|
||||
# The chart's julian_day is rounded for display. KP cusp and sub-lord
|
||||
# boundaries use the civil instant itself, seconds included (upstream
|
||||
# 26d5a52d, BUG-1543). Same formula as compute_chart_data.
|
||||
jd = swe.julday(args.year, args.month, args.day,
|
||||
_birth_hour_decimal(args.hour, args.minute, _arg_second(args)) - args.tz)
|
||||
|
||||
asc_sign = chart.get("ascendant", {}).get("sign", "Aries")
|
||||
planets = chart.get("planets", {})
|
||||
planet_lons = {
|
||||
@@ -13778,7 +13790,8 @@ def cmd_kp(args):
|
||||
from bhava_chalit import BhavaChalitCalculator
|
||||
kp_house_calculator = BhavaChalitCalculator()
|
||||
asc_lon = chart.get('ascendant', {}).get('degree_raw', chart.get('ascendant', {}).get('degree', 0.0))
|
||||
boundaries = kp_house_calculator.calculate_bhava_boundaries(
|
||||
# Unrounded cusps; calculate_bhava_boundaries rounds them to 4 decimals.
|
||||
raw_cusps = kp_house_calculator.calculate_cusps(
|
||||
float(asc_lon), 0.0, 'placidus', jd, args.lat, args.lon,
|
||||
)
|
||||
bhava_chart = kp_house_calculator.get_bhava_chalit_chart(
|
||||
@@ -13792,16 +13805,19 @@ def cmd_kp(args):
|
||||
for pname, pdata in planets.items():
|
||||
if isinstance(pdata, dict) and 'sign' in pdata:
|
||||
bhava_row = bhava_planets.get(pname) if isinstance(bhava_planets.get(pname), dict) else {}
|
||||
raw_lon = planet_lons.get(pname)
|
||||
planet_positions[pname] = {
|
||||
'sign': pdata['sign'],
|
||||
'degree': pdata.get('degree_in_sign', pdata.get('degree', 0) % 30),
|
||||
# degree_in_sign is rounded to 4 decimals for display.
|
||||
'degree': (float(raw_lon) % 30 if raw_lon is not None
|
||||
else pdata.get('degree_in_sign', pdata.get('degree', 0) % 30)),
|
||||
'house': bhava_row.get('bhava_house', pdata.get('house', 1)),
|
||||
}
|
||||
|
||||
result = calc_kp_analysis(
|
||||
planet_positions,
|
||||
asc_sign,
|
||||
house_cusps=boundaries.get('cusps'),
|
||||
house_cusps=raw_cusps,
|
||||
house_occupancy_basis='cusp_to_cusp',
|
||||
)
|
||||
moon_lon = planets.get('Moon', {}).get('degree_raw', planets.get('Moon', {}).get('degree', 0.0)) if isinstance(planets.get('Moon'), dict) else 0.0
|
||||
@@ -15856,7 +15872,7 @@ def cmd_full_reading(args):
|
||||
|
||||
ic_result = calc_all_inter_chart_linkages(
|
||||
d1_for_dc, d9_for_ic, d10_for_ic, d12_for_ic,
|
||||
asc_idx, d9_asc_idx, d10_asc_idx
|
||||
asc_idx, d9_asc_idx, d10_asc_idx, d12_asc_idx
|
||||
)
|
||||
report['modules']['inter_chart_linkage'] = ic_result
|
||||
|
||||
@@ -16124,7 +16140,10 @@ def cmd_full_reading(args):
|
||||
from narayana_dasha import attach_narayana_method_comparison, narayana_dasha_full_report
|
||||
# 计算当前年龄(从出生到 today)
|
||||
birth_dt = _birth_datetime_from_args(args)
|
||||
today_dt = datetime.strptime(args.today, '%Y-%m-%d') if hasattr(args, 'today') and args.today else datetime.now()
|
||||
# One observation date for the whole report (upstream 933f254e, BUG-1542).
|
||||
today_dt = datetime.strptime(
|
||||
getattr(args, 'transit_date', None) or getattr(args, 'today', None)
|
||||
or datetime.now().strftime('%Y-%m-%d'), '%Y-%m-%d')
|
||||
current_age = (today_dt - birth_dt).days / 365.25
|
||||
narayana_result = narayana_dasha_full_report(
|
||||
lagna_sign_idx=asc_idx,
|
||||
@@ -16451,7 +16470,9 @@ def cmd_full_reading(args):
|
||||
if nak_age is None:
|
||||
try:
|
||||
birth_date = datetime(args.year, args.month, args.day)
|
||||
nak_age = (datetime.now() - birth_date).days / 365.25
|
||||
nak_reference = getattr(args, 'transit_date', None) or getattr(args, 'today', None)
|
||||
observation = datetime.strptime(nak_reference, '%Y-%m-%d') if nak_reference else datetime.now()
|
||||
nak_age = (observation - birth_date).days / 365.25
|
||||
except:
|
||||
nak_age = None
|
||||
|
||||
@@ -16490,8 +16511,13 @@ def cmd_full_reading(args):
|
||||
if age is None:
|
||||
# 自动计算年龄
|
||||
try:
|
||||
birth_date = datetime(args.year, args.month, args.day)
|
||||
age = (datetime.now() - birth_date).days // 365
|
||||
# Calendar-birthday age on the report's observation date; days // 365
|
||||
# drifted about one day early every four years (upstream 933f254e).
|
||||
ref_today = datetime.strptime(
|
||||
getattr(args, 'transit_date', None) or getattr(args, 'today', None)
|
||||
or datetime.now().strftime('%Y-%m-%d'), '%Y-%m-%d')
|
||||
age = ref_today.year - int(args.year) - (
|
||||
(ref_today.month, ref_today.day) < (int(args.month), int(args.day)))
|
||||
report['warnings'].append(f"未提供年龄,自动计算为 {age} 岁")
|
||||
except:
|
||||
age = None
|
||||
|
||||
@@ -131,6 +131,7 @@ CORE_PYTEST_TARGETS = [
|
||||
# Summary lines by default; failure keeps the last 200 lines and a full log (BUG-1230).
|
||||
"tests/test_run_quality_gate_output.py",
|
||||
"tests/test_upstream_git_import_b9a0ef8f.py",
|
||||
"tests/test_upstream_git_import_5fb8379c.py",
|
||||
"tests/test_interpretation_template_registry.py",
|
||||
"tests/test_vedastro_external_technique_evidence.py",
|
||||
# Self-hosted heading font slices: 6500-character coverage, no overlap, 120 KB cap.
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
"""Git-mode import record for upstream main 5fb8379c (tenth sync, 2026-11-04). Does not replace the 5db72537 archive pin test."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
from jsonschema import Draft202012Validator, FormatChecker
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
RECORD = ROOT / "references/cross_project_contract/imports/commit-5fb8379c4f3e649cb4804065c9a3059e4bf633fe.json"
|
||||
SOURCE_MANIFEST = ROOT / "references/upstream/yinduzhanxing/source-manifest.json"
|
||||
SKILL_SNAPSHOT = ROOT / "references/upstream/yinduzhanxing/SKILL.md"
|
||||
SCHEMA = ROOT / "references/cross_project_contract/import_manifest.schema.json"
|
||||
COMMIT = "5fb8379c4f3e649cb4804065c9a3059e4bf633fe"
|
||||
|
||||
|
||||
def test_git_import_record_matches_mirrored_skill_and_manifest() -> None:
|
||||
record = json.loads(RECORD.read_text(encoding="utf-8"))
|
||||
manifest = json.loads(SOURCE_MANIFEST.read_text(encoding="utf-8"))
|
||||
schema = json.loads(SCHEMA.read_text(encoding="utf-8"))
|
||||
Draft202012Validator(schema, format_checker=FormatChecker()).validate(record)
|
||||
|
||||
assert record["source_mode"] == "git"
|
||||
assert record["source_commit"] == COMMIT
|
||||
assert re.fullmatch(r"[0-9a-f]{40}", record["source_commit"])
|
||||
assert re.fullmatch(r"[0-9a-f]{64}", record["source_tree_hash"])
|
||||
assert record["source_tree_hash"] == manifest["source_tree_sha256"]
|
||||
assert record["source_skill_sha256"] == manifest["source_skill_sha256"]
|
||||
snapshot_hash = hashlib.sha256(SKILL_SNAPSHOT.read_bytes()).hexdigest()
|
||||
assert snapshot_hash == record["source_skill_sha256"] == record["mirror_files"][0]["target_sha256_after"]
|
||||
assert record["mirror_files"][0]["status"] == "applied"
|
||||
assert manifest["source_mode"] == "git"
|
||||
assert manifest["source_commit"] == COMMIT
|
||||
assert all(row["status"] == "review_required" for row in record["semantic_merge_files"])
|
||||
@@ -1,8 +1,12 @@
|
||||
"""Git-mode import record for upstream b9a0ef8f. Does not replace the 5db72537 archive pin test."""
|
||||
"""Git-mode import record for upstream b9a0ef8f, kept as history.
|
||||
|
||||
原值: 本文件要求 source-manifest.json 与 SKILL.md 快照仍停在 b9a0ef8f
|
||||
新值: 只核对这份历史记录自身完整,且已不是当前镜像
|
||||
原因: 2026-11-04 第十轮同步把镜像移到 5fb8379c(tests/test_upstream_git_import_5fb8379c.py)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
@@ -12,12 +16,12 @@ from jsonschema import Draft202012Validator, FormatChecker
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
RECORD = ROOT / "references/cross_project_contract/imports/commit-b9a0ef8f0f0de8714982a5aa7100f5aea16c9d09.json"
|
||||
SOURCE_MANIFEST = ROOT / "references/upstream/yinduzhanxing/source-manifest.json"
|
||||
SKILL_SNAPSHOT = ROOT / "references/upstream/yinduzhanxing/SKILL.md"
|
||||
SCHEMA = ROOT / "references/cross_project_contract/import_manifest.schema.json"
|
||||
COMMIT = "b9a0ef8f0f0de8714982a5aa7100f5aea16c9d09"
|
||||
HISTORICAL_SKILL_SHA256 = "6bed459b8b971b189895e62aabfb90e41dbdf8f5b9e80a4b5330d40922fe21eb"
|
||||
|
||||
|
||||
def test_git_import_record_matches_mirrored_skill_and_manifest() -> None:
|
||||
def test_historical_git_import_record_stays_valid_and_is_not_the_current_mirror() -> None:
|
||||
record = json.loads(RECORD.read_text(encoding="utf-8"))
|
||||
manifest = json.loads(SOURCE_MANIFEST.read_text(encoding="utf-8"))
|
||||
schema = json.loads(SCHEMA.read_text(encoding="utf-8"))
|
||||
@@ -25,13 +29,9 @@ def test_git_import_record_matches_mirrored_skill_and_manifest() -> None:
|
||||
|
||||
assert record["source_mode"] == "git"
|
||||
assert record["source_commit"] == COMMIT
|
||||
assert re.fullmatch(r"[0-9a-f]{40}", record["source_commit"])
|
||||
assert re.fullmatch(r"[0-9a-f]{64}", record["source_tree_hash"])
|
||||
assert record["source_tree_hash"] == manifest["source_tree_sha256"]
|
||||
assert record["source_skill_sha256"] == manifest["source_skill_sha256"]
|
||||
snapshot_hash = hashlib.sha256(SKILL_SNAPSHOT.read_bytes()).hexdigest()
|
||||
assert snapshot_hash == record["source_skill_sha256"] == record["mirror_files"][0]["target_sha256_after"]
|
||||
assert record["source_skill_sha256"] == HISTORICAL_SKILL_SHA256
|
||||
assert record["mirror_files"][0]["target_sha256_after"] == HISTORICAL_SKILL_SHA256
|
||||
assert record["mirror_files"][0]["status"] == "applied"
|
||||
assert manifest["source_mode"] == "git"
|
||||
assert manifest["source_commit"] == COMMIT
|
||||
assert all(row["status"] == "review_required" for row in record["semantic_merge_files"])
|
||||
assert manifest["source_commit"] != COMMIT
|
||||
|
||||
@@ -41,16 +41,20 @@ EXPECTED_REJECTIONS = {
|
||||
"weaken_stability_gate",
|
||||
"remove_commercial_routes",
|
||||
}
|
||||
# 原值: b9a0ef8f(树 9ae737b0…、git 树 864cab47…、SKILL 6bed459b…、提交时间 2026-09-08T17:36:09Z)
|
||||
# 新值: 5fb8379c(上游 main 2026-11-04 的 HEAD)
|
||||
# 原因: 第十轮同步用导入器重新镜像 SKILL.md;旧记录留作历史,见 test_upstream_git_import_b9a0ef8f.py
|
||||
EXPECTED_UPSTREAM_IDENTITY = {
|
||||
"source_repository": "732642856/yinduzhanxing",
|
||||
"source_repository_url": "https://github.com/732642856/yinduzhanxing",
|
||||
"source_commit": "b9a0ef8f0f0de8714982a5aa7100f5aea16c9d09",
|
||||
"source_tree_sha256": "9ae737b02a48b38dca7d78094413b961a75e5abad17f2fe206f7dc3b1401d51a",
|
||||
"source_commit": "5fb8379c4f3e649cb4804065c9a3059e4bf633fe",
|
||||
"source_tree_sha256": "ee8bd9865cf11a6eb7f90705a262db8b2d145ae0cee6ee6eda32b311548f5aa2",
|
||||
}
|
||||
EXPECTED_SOURCE_GIT_TREE = "864cab471cadb31b71a7256c995c12b7552d7cb5"
|
||||
EXPECTED_SOURCE_SKILL_SHA256 = "6bed459b8b971b189895e62aabfb90e41dbdf8f5b9e80a4b5330d40922fe21eb"
|
||||
EXPECTED_SOURCE_GIT_TREE = "6cd6160804ea7419d609ccd639cc537a8a81c3c9"
|
||||
EXPECTED_SOURCE_SKILL_SHA256 = "5c1c0738fbe6f586fad36cfa13f602934dcea8f8d54c536655f6cb2091773d8d"
|
||||
EXPECTED_SOURCE_COMMITTED_AT = "2026-10-21T15:49:21Z"
|
||||
LEGACY_ARCHIVE_COMMIT = "5db72537741fcedaa7b5498502d4a31b0f9fc147"
|
||||
CURRENT_IMPORT_RECORD = ROOT / "references/cross_project_contract/imports/commit-b9a0ef8f0f0de8714982a5aa7100f5aea16c9d09.json"
|
||||
CURRENT_IMPORT_RECORD = ROOT / "references/cross_project_contract/imports/commit-5fb8379c4f3e649cb4804065c9a3059e4bf633fe.json"
|
||||
|
||||
|
||||
def _load(path: Path) -> dict:
|
||||
@@ -128,7 +132,7 @@ def test_source_manifest_pins_valid_git_commit_tree_and_root_skill_hash() -> Non
|
||||
assert manifest["source_git_tree"] == EXPECTED_SOURCE_GIT_TREE
|
||||
assert "archive_sha256" not in manifest
|
||||
assert "archive_file_count" not in manifest
|
||||
assert manifest["source_committed_at"] == "2026-09-08T17:36:09Z"
|
||||
assert manifest["source_committed_at"] == EXPECTED_SOURCE_COMMITTED_AT
|
||||
assert re.fullmatch(r"[0-9a-f]{40}", manifest["source_commit"])
|
||||
assert re.fullmatch(r"[0-9a-f]{64}", manifest["source_tree_sha256"])
|
||||
source_skill_sha256 = manifest.get("source_skill_sha256", manifest["skill_sha256"])
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
"""D12 houses in the inter-chart linkage count from the D12 ascendant.
|
||||
|
||||
Ported from upstream yinduzhanxing cf6c316d and f60568a0 (sync 10). Before
|
||||
the fix the D12 row always had house None, and an unknown sign became Aries.
|
||||
"""
|
||||
import ast
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / 'scripts'))
|
||||
from jyotish_engine import calc_all_inter_chart_linkages # noqa: E402
|
||||
|
||||
|
||||
@pytest.mark.parametrize('ascendant', range(12))
|
||||
def test_d12_every_house_from_its_own_ascendant(ascendant):
|
||||
frame = {'Sun': {'sign': 'Taurus'}}
|
||||
actual = calc_all_inter_chart_linkages(frame, frame, frame, frame, 0, 4, 8, ascendant)['Sun']
|
||||
assert actual['D12']['house'] == (1 - ascendant) % 12 + 1
|
||||
assert actual['D1']['house'] == 2
|
||||
assert actual['D9']['house'] == 10
|
||||
assert actual['D10']['house'] == 6
|
||||
|
||||
|
||||
def test_missing_d12_ascendant_is_not_aries():
|
||||
assert calc_all_inter_chart_linkages({}, {}, {}, {'Sun': {'sign': 'Taurus'}})['Sun']['D12']['house'] is None
|
||||
|
||||
|
||||
def test_bad_sign_does_not_become_aries():
|
||||
with pytest.raises(ValueError):
|
||||
calc_all_inter_chart_linkages({'Sun': {'sign': 'unknown'}}, {}, {}, d1_asc_idx=0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('bad', [True, -1, 12, 1.0])
|
||||
def test_bad_ascendant_index_is_rejected(bad):
|
||||
with pytest.raises(ValueError):
|
||||
calc_all_inter_chart_linkages({'Sun': {'sign': 'Taurus'}}, {}, {}, d1_asc_idx=bad)
|
||||
|
||||
|
||||
def test_full_reading_passes_the_precomputed_d12_index():
|
||||
tree = ast.parse((ROOT / 'scripts/jyotish_engine.py').read_text(encoding='utf-8'))
|
||||
calls = [n for n in ast.walk(tree) if isinstance(n, ast.Call) and isinstance(n.func, ast.Name)
|
||||
and n.func.id == 'calc_all_inter_chart_linkages']
|
||||
assert calls
|
||||
assert all(isinstance(c.args[-1], ast.Name) and c.args[-1].id == 'd12_asc_idx' for c in calls)
|
||||
@@ -0,0 +1,48 @@
|
||||
"""KP must not reuse display-rounded time, cusps or planet degrees (BUG-1543).
|
||||
|
||||
Ported from upstream yinduzhanxing 26d5a52d tests/test_kp_unrounded_inputs.py
|
||||
(sync 10). Synthetic chart only.
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / 'scripts'))
|
||||
import jyotish_engine as engine # noqa: E402
|
||||
from bhava_chalit import BhavaChalitCalculator # noqa: E402
|
||||
|
||||
|
||||
def test_kp_passes_raw_time_cusps_and_longitudes(monkeypatch):
|
||||
args = SimpleNamespace(year=2000, month=1, day=2, hour=3, minute=4, second=5,
|
||||
lat=20., lon=75., tz=5.5, ayanamsa='raman')
|
||||
chart = {'ascendant': {'sign': 'Aries', 'degree_raw': 12.123456789},
|
||||
'planets': {'Sun': {'sign': 'Aries', 'degree_raw': 1.234567891, 'degree_in_sign': 1.2346},
|
||||
'Moon': {'sign': 'Taurus', 'degree_raw': 42.987654321, 'degree_in_sign': 12.9877}}}
|
||||
raw_cusps = [12.123456789 + 30 * i for i in range(12)]
|
||||
seen = {}
|
||||
monkeypatch.setattr(engine, '_compute_chart_from_args', lambda a: (chart, 0, 2451545., 23.))
|
||||
|
||||
def cusps(self, asc, mc, hs, jd, lat, lon):
|
||||
seen['jd'] = jd
|
||||
return raw_cusps
|
||||
|
||||
monkeypatch.setattr(BhavaChalitCalculator, 'calculate_cusps', cusps)
|
||||
monkeypatch.setattr(BhavaChalitCalculator, 'get_bhava_chalit_chart',
|
||||
lambda *a, **k: {'planets': {'Sun': {'bhava_house': 12}, 'Moon': {'bhava_house': 2}}})
|
||||
|
||||
def analyze(planets, asc, **kwargs):
|
||||
seen['planets'] = planets
|
||||
seen.update(kwargs)
|
||||
return {}
|
||||
|
||||
monkeypatch.setattr(engine, 'calc_kp_analysis', analyze)
|
||||
monkeypatch.setattr(engine, 'attach_calculation_profile', lambda result, args: result)
|
||||
monkeypatch.setattr(engine, '_build_response_envelope', lambda command, result, **k: result)
|
||||
engine.cmd_kp(args)
|
||||
expected = engine.swe.julday(2000, 1, 2, 3 + 4 / 60 + 5 / 3600 - 5.5)
|
||||
assert seen['jd'] == expected and seen['jd'] != round(expected, 6)
|
||||
assert seen['house_cusps'] == raw_cusps
|
||||
assert seen['planets']['Sun']['degree'] == 1.234567891
|
||||
assert seen['planets']['Moon']['degree'] == 42.987654321 % 30
|
||||
assert seen['house_occupancy_basis'] == 'cusp_to_cusp'
|
||||
@@ -0,0 +1,109 @@
|
||||
"""A dated full reading uses one observation date everywhere (BUG-1542).
|
||||
|
||||
Ported from upstream yinduzhanxing 933f254e tests/test_full_reading_observation_date.py
|
||||
and tests/test_tajika_report_age.py (sync 10). The expressions are taken from
|
||||
scripts/jyotish_engine.py by name, so the real code is exercised without
|
||||
generating a report.
|
||||
"""
|
||||
import ast
|
||||
from datetime import datetime
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
ENGINE = Path(__file__).resolve().parents[1] / 'scripts/jyotish_engine.py'
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _tree():
|
||||
return ast.parse(ENGINE.read_text(encoding='utf-8'))
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def clock_expressions():
|
||||
found = {}
|
||||
for node in ast.walk(_tree()):
|
||||
if not isinstance(node, ast.Assign):
|
||||
continue
|
||||
names = [t.id for t in node.targets if isinstance(t, ast.Name)]
|
||||
for name in ('today_str', 'transit_reference_date', 'today_dt', 'ref_today'):
|
||||
if name in names:
|
||||
assert name not in found, f'{name} assigned twice; the test would read only one'
|
||||
found[name] = node.value
|
||||
return {k: compile(ast.Expression(v), '<report-clock>', 'eval') for k, v in found.items()}
|
||||
|
||||
|
||||
class _Clock(datetime):
|
||||
@classmethod
|
||||
def now(cls, tz=None):
|
||||
return cls(2030, 6, 7)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('arguments,expected', [
|
||||
({'transit_date': '2001-02-03', 'today': '2020-04-05'}, '2001-02-03'),
|
||||
({'transit_date': '2001-02-03'}, '2001-02-03'),
|
||||
({'today': '2020-04-05'}, '2020-04-05'),
|
||||
({}, '2030-06-07'),
|
||||
])
|
||||
def test_all_report_periods_observe_the_same_requested_date(arguments, expected):
|
||||
values = {k: eval(code, {'args': SimpleNamespace(**arguments), 'datetime': _Clock})
|
||||
for k, code in clock_expressions().items()}
|
||||
values = {k: v.strftime('%Y-%m-%d') if isinstance(v, datetime) else v for k, v in values.items()}
|
||||
assert values == dict.fromkeys(('today_str', 'transit_reference_date', 'today_dt', 'ref_today'), expected)
|
||||
|
||||
|
||||
def _block_after(predicate, length):
|
||||
for function in _tree().body:
|
||||
if not isinstance(function, ast.FunctionDef) or function.name not in ('_cmd_full_reading', 'cmd_full_reading'):
|
||||
continue
|
||||
for node in ast.walk(function):
|
||||
body = getattr(node, 'body', None)
|
||||
if not isinstance(body, list):
|
||||
continue
|
||||
for index, child in enumerate(body):
|
||||
if predicate(child):
|
||||
return compile(ast.Module(body=body[index:index + length], type_ignores=[]), '<block>', 'exec')
|
||||
raise AssertionError('block not found in cmd_full_reading')
|
||||
|
||||
|
||||
def _assigns_args_age(node, target):
|
||||
return (isinstance(node, ast.Assign) and [getattr(t, 'id', None) for t in node.targets] == [target]
|
||||
and isinstance(node.value, ast.Attribute) and node.value.attr == 'age'
|
||||
and isinstance(node.value.value, ast.Name) and node.value.value.id == 'args')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('extra,expected', [
|
||||
({'today': '2020-12-30'}, 20),
|
||||
({'today': '2021-01-01'}, 21),
|
||||
({'today': '2021-01-01', 'transit_date': '2020-12-30'}, 20),
|
||||
({'today': '2020-12-30', 'age': 18}, 18),
|
||||
])
|
||||
def test_fallback_annual_age_changes_at_the_calendar_birthday(extra, expected):
|
||||
code = _block_after(lambda n: _assigns_args_age(n, 'age'), 2)
|
||||
args = SimpleNamespace(**{'year': 2000, 'month': 1, 'day': 1, 'age': None, **extra})
|
||||
state = {'args': args, 'datetime': datetime, 'report': {'warnings': []}}
|
||||
exec(code, state)
|
||||
assert state['age'] == expected
|
||||
|
||||
|
||||
def test_fallback_annual_age_is_not_days_over_365():
|
||||
# 2000-01-01 to 2039-12-25 is 14603 days; 14603 // 365 = 40, but the person is 39.
|
||||
code = _block_after(lambda n: _assigns_args_age(n, 'age'), 2)
|
||||
args = SimpleNamespace(year=2000, month=1, day=1, age=None, today='2039-12-25')
|
||||
state = {'args': args, 'datetime': datetime, 'report': {'warnings': []}}
|
||||
exec(code, state)
|
||||
assert state['age'] == 39
|
||||
|
||||
|
||||
@pytest.mark.parametrize('extra,expected', [
|
||||
({'transit_date': '2010-01-01', 'today': '2020-01-01'}, 3653 / 365.25),
|
||||
({'today': '2020-01-01'}, 7305 / 365.25),
|
||||
])
|
||||
def test_nakshatra_dasha_age_uses_the_observation_date(extra, expected):
|
||||
code = _block_after(lambda n: _assigns_args_age(n, 'nak_age'), 2)
|
||||
args = SimpleNamespace(**{'year': 2000, 'month': 1, 'day': 1, 'age': None, **extra})
|
||||
state = {'args': args, 'datetime': _Clock}
|
||||
exec(code, state)
|
||||
assert state['nak_age'] == pytest.approx(expected)
|
||||
Reference in New Issue
Block a user