fix(tajika): sync the astrologer's 3509ccd7: oppositions, no factor promotion, annual cases back to template (BUG-1655)
From yinduzhanxing branch codex/local-web-verification-20261026 (remote SHA checked): - kernel: a 180-degree opposition keeps its 180 target (it was matched as 0); exact and equal-speed states are no longer called applying or separating - named-yoga authority rows carry source_review_status and factor_promotion_allowed: false; the annual year-chart layer honours the flag, so no Tajika yoga (Ithasala / Easarapha included) becomes a factor - the five annual oracle cases go back to template_only (archived text kept); the dashboards no longer claim annual closure Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
This commit is contained in:
@@ -22694,3 +22694,20 @@
|
||||
- 关联记录:BUG-1644、BUG-1648、BUG-1649。
|
||||
- 复发自:无
|
||||
- 修复版本:分支 `codex/rectification-rebuild-20261106`。
|
||||
|
||||
## BUG-1655 | 对冲(180°)被当成合相算;Tajika yoga 未核定就当支持/压力因素;年盘案例「已外部验证」证据不足:同步占星师 skill 仓 3509ccd7
|
||||
|
||||
- 状态:fixed-pending-verify(同步 + 回归测试)
|
||||
- 首次发现 / 最近更新:2026-11-06(占星师在 skill 仓 yinduzhanxing 分支 `codex/local-web-verification-20261026` 推送 d66d13ce、3509ccd7,远端提交号已核对)/ 2026-11-06
|
||||
- 影响面:`scripts/tajika_kernel.py`、`scripts/tajika_named_yoga_governed_draft.py`、`scripts/tajika_named_yoga_authority.py`、`references/tajika_named_yoga_rules.json`、`references/oracle/tajika_annual_oracle_cases.json` 与 6 个 pending packet、`scripts/annual_service/report_facts.py`、`frontend/src/lib/annual-report-generate.ts`(附录一行)。
|
||||
- 现象:
|
||||
- BUG-1652 移植的内核里,180° 对冲的目标角写成 `{0.0}`,对冲按合相算;残差为 0 或相对速度为 0 时仍被判成入相/离相。
|
||||
- 年运年盘层仍让 Ithasala / Easarapha 产生支持/压力因素,而占星师核对发现九种都有来源差异(如 Manahoo 的合相限制、Khallasara 的成立条件)。
|
||||
- 5 个年盘案例标 `external_verified`,相关脚本据此宣称年盘闭合;实际证据只有自报软件版本,交点设置、历史时区或年度对应不全。
|
||||
- 根因:BUG-1652 按 fb8fe915 移植,之后占星师在新分支修正了对冲与精确状态(d66d13ce)、给每行加了 `factor_promotion_allowed: false` 与核查记录路径、把案例降回模板(3509ccd7)。
|
||||
- 修复:内核、两个 yoga 模块与规则记录取该分支 3509ccd7 版本(import 改本仓写法);6 个 pending packet 与案例表套用上游数据补丁(降回 `template_only`,原始输出、目标值、证据路径保留)。年运层:每条联系带 `source_review`(上游状态)与 `factor_promotion_allowed`,只有允许的行才产生因素——目前一条都没有;附录口径改为「来源未核定,只列联系、不作因素」。
|
||||
- 验证:上游三个 Tajika 测试原样同步(18 条通过);`test_tajika_annual_benchmark_dashboard`、`closure_status`、`oracle_queue`、`first_packet_operator_card`、`annual_tajika_pack` 按降级后的实际输出更新(不再能宣称闭合、可校准 0、优先案例为 Jobs 1984、yoga 行 11 条;原值已注明);`test_annual_report_facts` 断言联系都不允许升级、没有 Tajika 因素。Tajika 与年运相关 Python 测试 357 条通过;`tests/test_oracle_benchmark_inventory.py` 在未改动的 staging 上已失败(8 ≥ 9),与本条无关,未改。
|
||||
- 防复发:skill 仓 Tajika/年运模块的改动按提交号同步并对照测试;规则:authority 行不允许时,产品不得把 yoga 升为因素。
|
||||
- 相关记录:BUG-1652、BUG-1650。
|
||||
- 复发自:BUG-1652(同一移植的后续修正)
|
||||
- 修复版本:分支 `fix/tajika-sync-1655`。
|
||||
|
||||
@@ -176,7 +176,7 @@ export function buildAppendix(facts: unknown, range: AnnualSnapshot["range"], bi
|
||||
"只判断了部分领域时只写这些领域,不概括整段;和前一段相同的写「延续前一阶段的主题」;「平稳」暂不使用",
|
||||
"宫主的功能吉凶、所管宫、所落宫、尊贵、燃烧分别记录;Maraka 单独记录,不作为负分;罗睺计都参考定位星,保留自身位置",
|
||||
"各领域方向一致才有主调,不一致就分领域写,看不出就写看不出;基调只决定建议的方向,正文不写顺紧总评",
|
||||
"年内展开看 Mudda 和 Patyayini,不参与本命运限判断;年盘分四层记:事项关联、Tajika 联系(Ithasala / Easarapha)、阻碍、五分力(偏弱不等于压力);只列支持与压力因素,不下成败结论",
|
||||
"年内展开看 Mudda 和 Patyayini,不参与本命运限判断;年盘分四层记:事项关联、Tajika 联系(九种结构判断,来源未核定,只列联系、不作因素)、阻碍、五分力(偏弱不等于压力);只列支持与压力因素,不下成败结论",
|
||||
"行运只算木星、土星、罗睺计都的换宫、停滞和精确经过本命点,只收与本命或报告领域有关的;木星、土星按 Parashari 星座级相照(木星 5、7、9,土星 3、7、10,同座另记)关联各领域的本命星,相照只是关联,不代表好坏;不用统一容许度;天象日期不等于事情发生的日子",
|
||||
`转折窗口:${String(config.window_cluster_days ?? 21)} 天内、指向同一领域、至少 ${String(config.window_min_independent_systems ?? 2)} 个互相独立的来源;罗睺计都算一条轴,Mudda 和 Patyayini 算一层,同一颗慢星的几次经过算一个来源;这些是展示参数,不是统计验证`,
|
||||
"精确相照时刻(木星 120°/180°/240°、土星 60°/180°/270°,及同座)单独列表:只记达到角度的时刻,同一次顺逆往返算一个序列,不设影响范围,也不进转折窗口",
|
||||
|
||||
+247
-264
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"capture_id": "external_template_einstein_varshaphala_1905_lahiri",
|
||||
"status": "external_verified",
|
||||
"status": "template_only",
|
||||
"case_id": "template_einstein_varshaphala_1905_lahiri",
|
||||
"birth": {
|
||||
"year": 1879,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"capture_id": "external_template_historical_dst_london_varshaphala_1943_lahiri",
|
||||
"status": "external_verified",
|
||||
"status": "template_only",
|
||||
"case_id": "template_historical_dst_london_varshaphala_1943_lahiri",
|
||||
"birth": {
|
||||
"year": 1910,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"capture_id": "external_template_marilyn_monroe_varshaphala_1962_lahiri",
|
||||
"status": "external_verified",
|
||||
"status": "template_only",
|
||||
"case_id": "template_marilyn_monroe_varshaphala_1962_lahiri",
|
||||
"birth": {
|
||||
"year": 1926,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"capture_id": "external_template_steve_jobs_varshaphala_1984_lahiri",
|
||||
"status": "external_verified",
|
||||
"status": "template_only",
|
||||
"case_id": "template_steve_jobs_varshaphala_1984_lahiri",
|
||||
"birth": {
|
||||
"year": 1955,
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"capture_id": "external_template_steve_jobs_varshaphala_1984_lahiri",
|
||||
"status": "external_verified",
|
||||
"status": "template_only",
|
||||
"provenance_review": "docs/research/tajika_source_adjudication_2026_11_06.md",
|
||||
"case_id": "template_steve_jobs_varshaphala_1984_lahiri",
|
||||
"birth": {
|
||||
"year": 1955,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"capture_id": "external_template_synthetic_extreme_latitude_varshaphala_kp",
|
||||
"status": "external_verified",
|
||||
"status": "template_only",
|
||||
"case_id": "template_synthetic_extreme_latitude_varshaphala_kp",
|
||||
"birth": {
|
||||
"year": 2000,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"provenance_review": "docs/research/tajika_source_adjudication_2026_11_06.md",
|
||||
"scope": "external_tajika_sahams_annual_oracle_cases",
|
||||
"notes": [
|
||||
"These rows collect external annual-chart evidence for the Jyotish skill, not web/app UI fixtures.",
|
||||
@@ -9,8 +10,8 @@
|
||||
"template_cases": [
|
||||
{
|
||||
"id": "template_steve_jobs_varshaphala_1984_lahiri",
|
||||
"status": "external_verified",
|
||||
"source": "JHora Varshaphala screenshot / PyJHora black-box annual output / printed example",
|
||||
"status": "template_only",
|
||||
"source": "Archived PyJHora text output; runtime settings and independent verification pending",
|
||||
"privacy": "public_figure_template",
|
||||
"birth": {
|
||||
"year": 1955,
|
||||
@@ -120,7 +121,7 @@
|
||||
"verification_note": "Fill only from external annual-chart output. Local scripts/varshaphala.py output is not valid evidence.",
|
||||
"evidence_packet": {
|
||||
"capture_id": "external_template_steve_jobs_varshaphala_1984_lahiri",
|
||||
"status": "external_verified",
|
||||
"status": "template_only",
|
||||
"metadata": {
|
||||
"tool_name": "PyJHora",
|
||||
"tool_version_or_url": "PyJHora 4.8.7 isolated /tmp black-box run",
|
||||
@@ -137,8 +138,8 @@
|
||||
},
|
||||
{
|
||||
"id": "template_einstein_varshaphala_1905_lahiri",
|
||||
"status": "external_verified",
|
||||
"source": "JHora Varshaphala screenshot / PyJHora black-box annual output / printed example",
|
||||
"status": "template_only",
|
||||
"source": "Archived PyJHora text output; runtime settings and independent verification pending",
|
||||
"privacy": "public_figure_template",
|
||||
"birth": {
|
||||
"year": 1879,
|
||||
@@ -267,7 +268,7 @@
|
||||
"verification_note": "Historical timezone and source convention must be documented beside the external annual output.",
|
||||
"evidence_packet": {
|
||||
"capture_id": "external_template_einstein_varshaphala_1905_lahiri",
|
||||
"status": "external_verified",
|
||||
"status": "template_only",
|
||||
"metadata": {
|
||||
"tool_name": "PyJHora",
|
||||
"tool_version_or_url": "PyJHora 4.8.6 isolated workbuddy black-box run",
|
||||
@@ -284,8 +285,8 @@
|
||||
},
|
||||
{
|
||||
"id": "template_marilyn_monroe_varshaphala_1962_lahiri",
|
||||
"status": "external_verified",
|
||||
"source": "JHora Varshaphala screenshot / PyJHora black-box annual output / printed example",
|
||||
"status": "template_only",
|
||||
"source": "Archived PyJHora text output; runtime settings and independent verification pending",
|
||||
"privacy": "public_figure_template",
|
||||
"birth": {
|
||||
"year": 1926,
|
||||
@@ -507,7 +508,7 @@
|
||||
,
|
||||
"evidence_packet": {
|
||||
"capture_id": "external_template_marilyn_monroe_varshaphala_1962_lahiri",
|
||||
"status": "external_verified",
|
||||
"status": "template_only",
|
||||
"metadata": {
|
||||
"tool_name": "PyJHora",
|
||||
"tool_version_or_url": "PyJHora 4.8.6 isolated workbuddy black-box run",
|
||||
@@ -524,8 +525,8 @@
|
||||
},
|
||||
{
|
||||
"id": "template_historical_dst_london_varshaphala_1943_lahiri",
|
||||
"status": "external_verified",
|
||||
"source": "JHora Varshaphala screenshot / PyJHora black-box annual output / printed example",
|
||||
"status": "template_only",
|
||||
"source": "Archived PyJHora text output; runtime settings and independent verification pending",
|
||||
"privacy": "synthetic_historical_dst_template",
|
||||
"birth": {
|
||||
"year": 1910,
|
||||
@@ -652,7 +653,7 @@
|
||||
"verification_note": "This row exists to force historical DST documentation before annual-chart accuracy claims.",
|
||||
"evidence_packet": {
|
||||
"capture_id": "external_template_historical_dst_london_varshaphala_1943_lahiri",
|
||||
"status": "external_verified",
|
||||
"status": "template_only",
|
||||
"metadata": {
|
||||
"tool_name": "PyJHora",
|
||||
"tool_version_or_url": "PyJHora 4.8.6 isolated workbuddy black-box run",
|
||||
@@ -669,8 +670,8 @@
|
||||
},
|
||||
{
|
||||
"id": "template_synthetic_extreme_latitude_varshaphala_kp",
|
||||
"status": "external_verified",
|
||||
"source": "JHora Varshaphala screenshot / PyJHora black-box annual output / printed example",
|
||||
"status": "template_only",
|
||||
"source": "Archived PyJHora text output; runtime settings and independent verification pending",
|
||||
"privacy": "synthetic_extreme_latitude_template",
|
||||
"birth": {
|
||||
"year": 2000,
|
||||
@@ -802,7 +803,7 @@
|
||||
"verification_note": "High-latitude annual chart row; external source must document house and ascendant assumptions.",
|
||||
"evidence_packet": {
|
||||
"capture_id": "external_template_synthetic_extreme_latitude_varshaphala_kp",
|
||||
"status": "external_verified",
|
||||
"status": "template_only",
|
||||
"metadata": {
|
||||
"tool_name": "PyJHora",
|
||||
"tool_version_or_url": "PyJHora 4.8.6 isolated workbuddy black-box run",
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
{
|
||||
"schema": "jyotish.tajika_named_yoga_rules.v1",
|
||||
"scope": "Sixteen PL9 Tajika Yoga structural presence rows; not event verdicts",
|
||||
"source_review_status": "pending_profile_adjudication",
|
||||
"factor_promotion_allowed": false,
|
||||
"source_review_path": "docs/research/tajika_source_adjudication_2026_11_06.md",
|
||||
"sources": [
|
||||
"P.V.R. Narasimha Rao, Vedic Astrology: An Integrated Approach, Part 4, sections 29.2.5-29.2.8",
|
||||
"M.S. Mehta, Annual Horoscope (Varshaphala or Tajak), Tajak Yogas pages 139-140",
|
||||
@@ -15,8 +18,8 @@
|
||||
"Kamboola": "A non-lunar Ithasala is strengthened when Moon forms Ithasala with either participant.",
|
||||
"Gairi-Kamboola": "An unqualified Moon in the last degree of a sign, on entering the next sign, forms Ithasala with one member of an existing non-lunar Ithasala and with another powerful planet. This producer defines powerful as own-sign or exalted and records that boundary.",
|
||||
"Khallsara": "A non-lunar Ithasala has an unqualified Moon that is neither associated with nor in a Deeptamsa Tajika link with either member.",
|
||||
"Rudda": "An Ithasala is Rudda when either participant is retrograde, combust, debilitated, dusthana-placed, in an inimical Tajika rasi relation, or receives a Mars/Saturn Tajika aspect. The producer records every satisfied subcondition and only evaluates the latter four when annual house and Panchavargiya rasi-relation evidence are complete.",
|
||||
"Duphali-Kutta": "An Ithasala has a slower planet that is own-sign, exalted, strong, or otherwise strong and a faster planet that is weak but neither own-sign nor exalted. This producer uses the native annual combined-strength grade for strong/weak and records the trace.",
|
||||
"Rudda": "An Ithasala is Rudda when either participant is retrograde, combust, debilitated, dusthana-placed, in an inimical Tajika rasi relation, or receives a Mars/Saturn Tajika aspect. The producer records every satisfied subcondition and only evaluates the latter four when annual house and Panchavargiya rasi-relation evidence are complete."
|
||||
,"Duphali-Kutta": "An Ithasala has a slower planet that is own-sign, exalted, strong, or otherwise strong and a faster planet that is weak but neither own-sign nor exalted. This producer uses the native annual combined-strength grade for strong/weak and records the trace.",
|
||||
"Dutthotta-Daivira": "Two weak planets have one member in Ithasala with a strong helper that is own-sign or exalted. This producer uses the native annual combined-strength grade for weak/strong and records the trace.",
|
||||
"Tambira": "Under the annual-general Karyesh profile (the annual 10th lord), Lagnesh and Karyesh lack an aspect/Ithasala; the Karyesh is at the last degree and after sign entry forms Ithasala with two strong planets, at least one own-sign or exalted.",
|
||||
"Kutta": "Under the annual-general Karyesh profile (the annual 10th lord), Lagnesh and Karyesh are strong in Kendras or Panapharas with benefic Tajika links and no malefic Tajika links.",
|
||||
|
||||
@@ -98,7 +98,7 @@ CONFIG: dict[str, Any] = {
|
||||
"window_birth_range_rule": "keep_full_moving_range",
|
||||
"transit_relation_rule": "parashari_sign_graha_drishti_jupiter_5_7_9_saturn_3_7_10_no_orb",
|
||||
# BUG-1652:九种 Tajika 结构判断已接入(上游 yinduzhanxing fb8fe915),逐项来源核对未完成,只记联系不出因素
|
||||
"tajika_yoga_rule_review": "pending: deeptamsa orbs, actual motion, third-planet transfer, blocking",
|
||||
"tajika_yoga_rule_review": "pending_profile_adjudication (astrologer yinduzhanxing 3509ccd7): no Tajika yoga may become a factor",
|
||||
"lookback_months": ap.LOOKBACK_MONTHS,
|
||||
}
|
||||
|
||||
@@ -1084,15 +1084,18 @@ def _annual_unfolding(chart: dict, lo: float, hi: float) -> list[dict]:
|
||||
connections.append({
|
||||
"yoga": yoga.get("named_yoga"), "with": other, "domain": domain,
|
||||
"motion": yoga.get("motion"), "review_status": yoga.get("review_status"),
|
||||
# BUG-1652 (astrologer 2026-11-06): computed is not ruled. Orbs, actual
|
||||
# motion, third-planet transfer and blocking still need item-by-item review.
|
||||
"source_review": "pending",
|
||||
# BUG-1652 / BUG-1655 (astrologer 3509ccd7): computed is not ruled. The
|
||||
# authority row says whether it may become a factor; today none may.
|
||||
"source_review": yoga.get("source_review_status") or "pending",
|
||||
"factor_promotion_allowed": yoga.get("factor_promotion_allowed") is True,
|
||||
})
|
||||
score = ((strength.get("panchavargiya_bala") or {}).get(lord) or {}).get("score") if lord else None
|
||||
# Only Ithasala / Easarapha turn into factors (as before BUG-1652); the seven newly
|
||||
# available yogas stay connections until their rules are reviewed.
|
||||
support_factors = [f"ithasala_with_{c['domain']}_lord" for c in connections if c["yoga"] == "Ithasala"]
|
||||
pressure_factors = [f"separating_from_{c['domain']}_lord" for c in connections if c["yoga"] == "Easarapha"]
|
||||
# BUG-1655: a Tajika yoga becomes a factor only when its authority row allows it. Since
|
||||
# the astrologer's 3509ccd7 no row does (source differences, e.g. Manahoo, Khallasara).
|
||||
support_factors = [f"ithasala_with_{c['domain']}_lord" for c in connections
|
||||
if c["yoga"] == "Ithasala" and c["factor_promotion_allowed"]]
|
||||
pressure_factors = [f"separating_from_{c['domain']}_lord" for c in connections
|
||||
if c["yoga"] == "Easarapha" and c["factor_promotion_allowed"]]
|
||||
if house in (6, 8, 12):
|
||||
pressure_factors.append(f"annual_house_{house}_difficulty_cost_or_adjustment")
|
||||
out.append({
|
||||
@@ -1101,7 +1104,7 @@ def _annual_unfolding(chart: dict, lo: float, hi: float) -> list[dict]:
|
||||
"year_relevance": [name for name, value in (("year_lord", year_lord), ("annual_lagna_lord", asc_lord),
|
||||
("muntha_lord", muntha_lord)) if value and value == lord],
|
||||
"connections": connections,
|
||||
"connections_checked": "tajika_named_yoga_authority rows (nine named yogas; seven still blocked upstream); none reviewed against sources yet",
|
||||
"connections_checked": "tajika_named_yoga_authority rows (nine named yogas); source adjudication pending (yinduzhanxing docs/research/tajika_source_adjudication_2026_11_06.md); no row may become a factor yet",
|
||||
"capability": {"panchavargiya": score, "scale": "sum_of_five_div_4",
|
||||
"weak": bool(isinstance(score, (int, float)) and score < PANCHAVARGIYA_WEAK_BELOW),
|
||||
"note": "weak is not pressure; strong is not success"},
|
||||
|
||||
@@ -22,7 +22,7 @@ def _signed_angle(value: float) -> float:
|
||||
def _nearest_aspect(delta: float) -> tuple[float, float]:
|
||||
candidates = []
|
||||
for aspect in ASPECT_ANGLES:
|
||||
for target in ({0.0} if aspect in (0.0, 180.0) else {aspect, -aspect}):
|
||||
for target in ({aspect} if aspect in (0.0, 180.0) else {aspect, -aspect}):
|
||||
candidates.append((target, _signed_angle(delta - target)))
|
||||
return min(candidates, key=lambda item: abs(item[1]))
|
||||
|
||||
@@ -50,18 +50,27 @@ def evaluate_tajika_pair(
|
||||
if abs(residual) > orb:
|
||||
return None
|
||||
relative_speed = float(right_payload["speed"]) - float(left_payload["speed"])
|
||||
# Ported from yinduzhanxing fb8fe915 (BUG-1652). Applying/separating is an
|
||||
# instantaneous relation. A full-day step makes fast bodies (especially the
|
||||
# Moon) leap over an exact aspect and reverses a still-applying relation.
|
||||
# The signed residual approaches zero iff its derivative, the relative
|
||||
# speed, has the opposite sign.
|
||||
# Synced from yinduzhanxing 3509ccd7 / d66d13ce (BUG-1655): oppositions keep their 180-degree
|
||||
# target, and exact or equal-speed states are not called applying or separating.
|
||||
# Applying/separating is an instantaneous relation. A full-day step makes
|
||||
# fast bodies (especially the Moon) leap over an exact aspect and reverses
|
||||
# a still-applying relation. The signed residual approaches zero iff its
|
||||
# derivative, the relative speed, has the opposite sign.
|
||||
applying = residual * relative_speed < 0.0
|
||||
# Exact/equal-speed states do not establish an applying or separating
|
||||
# named Yoga. Preserve the geometry without inventing a direction.
|
||||
if residual == 0.0:
|
||||
motion = "exact"
|
||||
elif relative_speed == 0.0:
|
||||
motion = "stationary_relative"
|
||||
else:
|
||||
motion = "applying" if applying else "separating"
|
||||
return {
|
||||
"planets": [left, right],
|
||||
"aspect": abs(aspect),
|
||||
"residual": round(residual, 6),
|
||||
"average_deeptamsa": orb,
|
||||
"motion": "applying" if applying else "separating",
|
||||
"motion": motion,
|
||||
"within_deeptamsa": True,
|
||||
}
|
||||
|
||||
@@ -98,7 +107,7 @@ def calculate_tajika_interactions(planets: dict[str, dict[str, Any]]) -> dict[st
|
||||
"rule_source": "references/tajika-yoga-complete-guide.md#2.1-2.2",
|
||||
"status": "partial",
|
||||
}
|
||||
for row in interactions
|
||||
for row in interactions if row["motion"] in {"applying", "separating"}
|
||||
],
|
||||
"supported_named_yogas": ["Ithasala", "Easarapha"],
|
||||
"blocked_named_yogas": ["Nakta", "Yamaya", "Manahoo", "Kamboola"],
|
||||
|
||||
@@ -5,8 +5,8 @@ the seven-planet Tajika kernel and the annual whole-sign house categories. It
|
||||
does not infer broader Tajika event verdicts or unsupported named-yoga chains.
|
||||
"""
|
||||
|
||||
# Ported from yinduzhanxing fb8fe915 (2026-09-07) for BUG-1652: the product still ran the
|
||||
# 2026-09-03 two-yoga version and reported Nakta / Yamaya / Manahoo / Kamboola as blocked.
|
||||
# Synced from yinduzhanxing 3509ccd7 (astrologer branch codex/local-web-verification-20261026,
|
||||
# 2026-11-06) for BUG-1655, on top of the fb8fe915 port (BUG-1652).
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -82,6 +82,9 @@ def build_tajika_named_yoga_authority(planets: dict[str, dict[str, Any]]) -> dic
|
||||
"review_status": "governed_authority_ready",
|
||||
"resolution_state": "authority_promoted_from_shared_motion_contract",
|
||||
"authority_status": "supported",
|
||||
"source_review_status": "pending_profile_adjudication",
|
||||
"factor_promotion_allowed": False,
|
||||
"source_review_path": "docs/research/tajika_source_adjudication_2026_11_06.md",
|
||||
"claim_boundary": "named_yoga_present_absent_only_no_event_verdict",
|
||||
}
|
||||
)
|
||||
@@ -89,11 +92,14 @@ def build_tajika_named_yoga_authority(planets: dict[str, dict[str, Any]]) -> dic
|
||||
return {
|
||||
"schema_version": SCHEMA_VERSION,
|
||||
"status": "authority_ready",
|
||||
"source_review_status": "pending_profile_adjudication",
|
||||
"factor_promotion_allowed": False,
|
||||
"authority_ready": True,
|
||||
"supported_named_yogas": supported_named_yogas,
|
||||
"blocked_named_yogas": blocked_named_yogas,
|
||||
"kernel_status": draft.get("kernel_status"),
|
||||
"kernel_boundary": draft.get("kernel_boundary"),
|
||||
"interactions": list(draft.get("interactions") or []),
|
||||
"rows": rows,
|
||||
"pl9_forming_pairs": _pl9_forming_pairs(rows),
|
||||
"summary": {
|
||||
|
||||
@@ -5,8 +5,8 @@ candidate relations into a review-ready draft so the remaining closure can be
|
||||
resolved under one governed vocabulary.
|
||||
"""
|
||||
|
||||
# Ported from yinduzhanxing fb8fe915 (2026-09-07) for BUG-1652: the product still ran the
|
||||
# 2026-09-03 two-yoga version and reported Nakta / Yamaya / Manahoo / Kamboola as blocked.
|
||||
# Synced from yinduzhanxing 3509ccd7 (astrologer branch codex/local-web-verification-20261026,
|
||||
# 2026-11-06) for BUG-1655, on top of the fb8fe915 port (BUG-1652).
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -94,6 +94,7 @@ def build_tajika_named_yoga_governed_draft(planets: dict[str, dict[str, Any]]) -
|
||||
"claim_boundary": "governed_named_yoga_draft_only_no_named_yoga_verdict_or_promotion",
|
||||
"kernel_status": kernel.get("status"),
|
||||
"kernel_boundary": kernel.get("boundary"),
|
||||
"interactions": list(kernel.get("interactions") or []),
|
||||
"rows": rows,
|
||||
"summary": {
|
||||
"row_count": len(rows),
|
||||
|
||||
@@ -211,12 +211,12 @@ def test_year_chart_factors_are_layers_not_verdicts() -> None:
|
||||
assert not {"verdict", "label", "lean"} & set(row)
|
||||
for factor in row["pressure_factors"]:
|
||||
assert factor.startswith(("separating_from_", "annual_house_"))
|
||||
# BUG-1652: every Tajika connection waits for source review; only Ithasala / Easarapha make factors.
|
||||
# BUG-1652 / BUG-1655: every Tajika connection waits for source review and none may
|
||||
# become a factor (astrologer 3509ccd7: factor_promotion_allowed is false on every row).
|
||||
for connection in row["connections"]:
|
||||
assert connection["source_review"] == "pending"
|
||||
yogas = {c["yoga"] for c in row["connections"]}
|
||||
if not yogas & {"Ithasala"}:
|
||||
assert not any(f.startswith("ithasala_") for f in row["support_factors"])
|
||||
assert connection["source_review"] in ("pending", "pending_profile_adjudication")
|
||||
assert connection["factor_promotion_allowed"] is False
|
||||
assert not any(f.startswith(("ithasala_", "separating_from_")) for f in row["support_factors"] + row["pressure_factors"])
|
||||
|
||||
|
||||
def test_sign_aspects_follow_parashari_and_stay_geometry() -> None:
|
||||
|
||||
@@ -221,8 +221,8 @@ def test_annual_tajika_pack_promotes_governed_named_yoga_authority_when_motion_i
|
||||
assert authority["blocked_named_yogas"] == [
|
||||
"Iqabala", "Induvara", "Duphali-Kutta", "Dutthotta-Daivira", "Tambira", "Kutta", "Durupha",
|
||||
]
|
||||
# 原值:Ithasala/Easarapha (8 rows);新值:九种 13 行(BUG-1652,与上游 fb8fe915 一致)
|
||||
assert appendix["field_briefs"]["tajika_yogas"] == "Tajika Yogas: governed authority surface visible for Ithasala/Easarapha/Nakta/Yamaya/Manahoo/Kamboola/Gairi-Kamboola/Khallsara/Rudda (13 rows)"
|
||||
# 原值:Ithasala/Easarapha (8 rows);BUG-1652 九种 13 行;BUG-1655 11 行(占星师 d66d13ce:精确与相对静止不成 yoga,只保留入相/离相)
|
||||
assert appendix["field_briefs"]["tajika_yogas"] == "Tajika Yogas: governed authority surface visible for Ithasala/Easarapha/Nakta/Yamaya/Manahoo/Kamboola/Gairi-Kamboola/Khallsara/Rudda (11 rows)"
|
||||
assert pack["audit"]["technique_audit"][5] == {"technique": "Tajika Yogas", "status": "partial_verified"}
|
||||
|
||||
|
||||
|
||||
@@ -37,12 +37,13 @@ def test_tajika_annual_dashboard_outputs_stable_json_summary() -> None:
|
||||
report = json.loads(completed.stdout)
|
||||
assert report["scope"] == "tajika_sahams_annual_benchmark_dashboard"
|
||||
assert report["schema_version"] == 1
|
||||
# BUG-1655:占星师 3509ccd7 把 5 个年盘案例降回 template_only(证据只有自报版本,交点、历史时区或年度对应不全),
|
||||
# 年盘不再能宣称闭合;下列断言的原值是 5 / True / external_verified / Einstein 1905。
|
||||
assert report["summary"]["total_tasks"] == 5
|
||||
assert report["summary"]["ready_for_calibration"] == 5
|
||||
assert report["summary"]["ready_for_calibration"] == 0
|
||||
assert report["summary"]["production_tuning_allowed"] is False
|
||||
assert report["annual_claim"]["can_claim_tajika_sahams_closure"] is True
|
||||
assert "target set is closed" in report["remaining_gap"]
|
||||
assert "predictive claim" in report["remaining_gap"]
|
||||
assert report["annual_claim"]["can_claim_tajika_sahams_closure"] is False
|
||||
assert "still need external" in report["remaining_gap"]
|
||||
|
||||
|
||||
def test_tajika_annual_dashboard_outputs_markdown_and_can_write_file(tmp_path: Path) -> None:
|
||||
@@ -53,5 +54,5 @@ def test_tajika_annual_dashboard_outputs_markdown_and_can_write_file(tmp_path: P
|
||||
assert output.exists()
|
||||
markdown = output.read_text(encoding="utf-8")
|
||||
assert "# Tajika/Sahams Annual Benchmark Dashboard" in markdown
|
||||
assert "can_claim_tajika_sahams_closure: `true`" in markdown
|
||||
assert "can_claim_tajika_sahams_closure: `false`" in markdown
|
||||
assert "production_tuning_allowed: `false`" in markdown
|
||||
|
||||
@@ -36,14 +36,16 @@ def test_tajika_annual_closure_status_identifies_first_annual_packet() -> None:
|
||||
report = json.loads(completed.stdout)
|
||||
assert report["scope"] == "tajika_sahams_annual_closure_status"
|
||||
assert report["schema_version"] == 1
|
||||
# BUG-1655:占星师 3509ccd7 把 5 个年盘案例降回 template_only(证据只有自报版本,交点、历史时区或年度对应不全),
|
||||
# 年盘不再能宣称闭合;下列断言的原值是 5 / True / external_verified / Einstein 1905。
|
||||
assert report["summary"]["annual_task_count"] == 5
|
||||
assert report["summary"]["external_verified_annual_tasks"] == 5
|
||||
assert report["summary"]["can_claim_tajika_sahams_closure"] is True
|
||||
assert report["summary"]["external_verified_annual_tasks"] == 0
|
||||
assert report["summary"]["can_claim_tajika_sahams_closure"] is False
|
||||
from scripts import tajika_annual_closure_status as module
|
||||
assert module.FIRST_PRIORITY_CASE_ID == "template_einstein_varshaphala_1905_lahiri"
|
||||
assert module.FIRST_PRIORITY_TEMPLATE_PATH.endswith("external_template_einstein_varshaphala_1905_lahiri.json")
|
||||
assert report["first_priority"]["case_id"] == "template_einstein_varshaphala_1905_lahiri"
|
||||
assert report["first_priority"]["capture_id"] == "external_template_einstein_varshaphala_1905_lahiri"
|
||||
assert report["first_priority"]["case_id"] == "template_steve_jobs_varshaphala_1984_lahiri"
|
||||
assert report["first_priority"]["capture_id"] == "external_template_steve_jobs_varshaphala_1984_lahiri"
|
||||
assert report["first_priority"]["required_target_fields"] == [
|
||||
"target.solar_return_datetime",
|
||||
"target.varsha_lagna_deg",
|
||||
@@ -61,17 +63,17 @@ def test_tajika_annual_closure_status_identifies_first_annual_packet() -> None:
|
||||
assert report["first_priority"]["missing_groups"]["target"]["count"] == 0
|
||||
assert report["first_priority"]["prefilled_fields"]["metadata"]["tool_name"] == "PyJHora"
|
||||
assert report["first_priority"]["prefilled_fields"]["metadata"]["annual_system"] == "Varshaphala/Tajika"
|
||||
assert report["first_priority"]["prefilled_fields"]["metadata"]["target_year"] == 1905
|
||||
assert report["first_priority"]["prefilled_fields"]["settings"]["node_mode"] == "mean"
|
||||
assert report["first_priority"]["prefilled_fields"]["metadata"]["target_year"] == 1984
|
||||
assert report["first_priority"]["prefilled_fields"]["settings"]["node_mode"] == "true"
|
||||
assert report["first_priority"]["manual_fill_plan"]["status_value"] == "external_verified"
|
||||
assert report["first_priority"]["manual_fill_plan"]["manual_entry_count"] == 0
|
||||
assert report["first_priority"]["validate_command"]
|
||||
packet_path = ROOT / report["first_priority"]["packet_path"]
|
||||
assert packet_path.exists(), report["first_priority"]["packet_path"]
|
||||
packet = json.loads(packet_path.read_text(encoding="utf-8"))
|
||||
assert packet["capture_id"] == "external_template_einstein_varshaphala_1905_lahiri"
|
||||
assert packet["status"] == "external_verified"
|
||||
assert packet["target_placeholders"]["target.solar_return_datetime"] == "1905-03-15T03:44:51+00:53"
|
||||
assert packet["capture_id"] == "external_template_steve_jobs_varshaphala_1984_lahiri"
|
||||
assert packet["status"] == "template_only"
|
||||
assert packet["target_placeholders"]["target.solar_return_datetime"] == "1984-02-25T05:41:37-08:00"
|
||||
|
||||
|
||||
def test_tajika_annual_closure_status_markdown_can_be_written(tmp_path: Path) -> None:
|
||||
@@ -82,8 +84,8 @@ def test_tajika_annual_closure_status_markdown_can_be_written(tmp_path: Path) ->
|
||||
assert output.exists()
|
||||
markdown = output.read_text(encoding="utf-8")
|
||||
assert "# Tajika/Sahams Annual Closure Status" in markdown
|
||||
assert "can_claim_tajika_sahams_closure: `true`" in markdown
|
||||
assert "external_template_einstein_varshaphala_1905_lahiri" in markdown
|
||||
assert "can_claim_tajika_sahams_closure: `false`" in markdown
|
||||
assert "external_template_steve_jobs_varshaphala_1984_lahiri" in markdown
|
||||
assert "## Missing Summary" in markdown
|
||||
assert "## Prefilled Fields" in markdown
|
||||
assert "## Manual Fill Plan" in markdown
|
||||
|
||||
@@ -31,18 +31,20 @@ def test_tajika_annual_queue_outputs_collection_tasks() -> None:
|
||||
queue = json.loads(completed.stdout)
|
||||
assert queue["scope"] == "tajika_sahams_annual_oracle_collection_queue"
|
||||
assert queue["schema_version"] == 1
|
||||
# BUG-1655:占星师 3509ccd7 把 5 个年盘案例降回 template_only(证据只有自报版本,交点、历史时区或年度对应不全),
|
||||
# 年盘不再能宣称闭合;下列断言的原值是 5 / True / external_verified / Einstein 1905。
|
||||
assert queue["summary"]["total_tasks"] == 5
|
||||
assert queue["summary"]["ready_for_calibration"] == 5
|
||||
assert queue["summary"]["current_target_set_closed"] is True
|
||||
assert queue["summary"]["ready_for_calibration"] == 0
|
||||
assert queue["summary"]["current_target_set_closed"] is False
|
||||
assert queue["summary"]["production_tuning_allowed"] is False
|
||||
assert "solar return" in queue["boundary"].lower()
|
||||
|
||||
first = queue["tasks"][0]
|
||||
assert first["task_id"].startswith("collect_")
|
||||
assert first["case_id"] == "template_steve_jobs_varshaphala_1984_lahiri"
|
||||
assert first["status"] == "external_verified"
|
||||
assert first["status"] == "template_only"
|
||||
assert first["ready_for_collection"] is False
|
||||
assert first["ready_for_calibration"] is True
|
||||
assert first["ready_for_calibration"] is False
|
||||
assert "target.solar_return_datetime" in first["target_fields"]
|
||||
assert first["missing_target_fields"] == []
|
||||
assert first["target_fields"] == [
|
||||
@@ -66,7 +68,7 @@ def test_tajika_annual_queue_outputs_collection_tasks() -> None:
|
||||
second = queue["tasks"][1]
|
||||
assert second["case_id"] == "template_einstein_varshaphala_1905_lahiri"
|
||||
assert second["ready_for_collection"] is False
|
||||
assert second["ready_for_calibration"] is True
|
||||
assert second["ready_for_calibration"] is False
|
||||
assert second["missing_target_fields"] == []
|
||||
|
||||
|
||||
|
||||
@@ -30,8 +30,10 @@ def test_tajika_first_packet_operator_card_is_actionable() -> None:
|
||||
def test_tajika_first_packet_template_contains_only_annual_targets() -> None:
|
||||
packet = json.loads(PACKET.read_text(encoding="utf-8"))
|
||||
|
||||
# BUG-1655:占星师 3509ccd7 把 5 个年盘案例降回 template_only(证据只有自报版本,交点、历史时区或年度对应不全),
|
||||
# 年盘不再能宣称闭合;下列断言的原值是 5 / True / external_verified / Einstein 1905。
|
||||
assert packet["capture_id"] == "external_template_einstein_varshaphala_1905_lahiri"
|
||||
assert packet["status"] == "external_verified"
|
||||
assert packet["status"] == "template_only"
|
||||
assert packet["case_id"] == "template_einstein_varshaphala_1905_lahiri"
|
||||
assert packet["metadata"]["source_artifact"] == "references/oracle/artifacts/pyjhora_einstein_varshaphala_1905_lahiri_partial_20260629.txt"
|
||||
assert packet["settings"]["target_year"] == 1905
|
||||
|
||||
@@ -1,6 +1,38 @@
|
||||
# Synced from yinduzhanxing 3509ccd7 for BUG-1655.
|
||||
import pytest
|
||||
|
||||
from scripts.tajika_kernel import calculate_tajika_interactions, evaluate_tajika_pair
|
||||
|
||||
|
||||
@pytest.mark.parametrize('longitude,motion', [(179.0, 'applying'), (181.0, 'separating'), (180.0, 'exact')])
|
||||
def test_opposition_is_retained_instead_of_tested_as_conjunction(longitude, motion):
|
||||
pair = evaluate_tajika_pair('Sun', 'Moon', {
|
||||
'Sun': {'longitude': 0.0, 'speed': 1.0},
|
||||
'Moon': {'longitude': longitude, 'speed': 13.0},
|
||||
})
|
||||
assert pair is not None
|
||||
assert pair['aspect'] == 180.0
|
||||
assert pair['motion'] == motion
|
||||
|
||||
|
||||
def test_equal_speed_contact_is_not_a_separating_yoga():
|
||||
planets = _seven()
|
||||
planets['Moon'] = {'longitude': 59.0, 'speed': 1.0}
|
||||
result = calculate_tajika_interactions(planets)
|
||||
pair = next(row for row in result['interactions'] if row['planets'] == ['Sun', 'Moon'])
|
||||
assert pair['motion'] == 'stationary_relative'
|
||||
assert not any(row['planets'] == ['Sun', 'Moon'] for row in result['candidate_yogas'])
|
||||
|
||||
|
||||
def test_exact_contact_is_preserved_without_inventing_separation():
|
||||
planets = _seven()
|
||||
planets['Moon']['longitude'] = 60.0
|
||||
result = calculate_tajika_interactions(planets)
|
||||
pair = next(row for row in result['interactions'] if row['planets'] == ['Sun', 'Moon'])
|
||||
assert pair['motion'] == 'exact'
|
||||
assert not any(row['planets'] == ['Sun', 'Moon'] for row in result['candidate_yogas'])
|
||||
|
||||
|
||||
def _seven():
|
||||
return {
|
||||
"Sun": {"longitude": 0, "speed": 1.0}, "Moon": {"longitude": 49, "speed": 13.0},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Ported from yinduzhanxing fb8fe915 for BUG-1652.
|
||||
# Synced from yinduzhanxing 3509ccd7 for BUG-1655.
|
||||
from __future__ import annotations
|
||||
|
||||
from scripts.tajika_named_yoga_authority import build_tajika_named_yoga_authority
|
||||
@@ -20,6 +20,9 @@ def test_tajika_named_yoga_authority_promotes_only_governed_supported_rows() ->
|
||||
assert report["schema_version"] == "jyotish.tajika_named_yoga_authority.v1"
|
||||
assert report["status"] == "authority_ready"
|
||||
assert report["authority_ready"] is True
|
||||
assert report["source_review_status"] == "pending_profile_adjudication"
|
||||
assert report["factor_promotion_allowed"] is False
|
||||
assert all(row["factor_promotion_allowed"] is False for row in report["rows"])
|
||||
assert report["supported_named_yogas"] == ["Ithasala", "Easarapha", "Nakta", "Yamaya", "Manahoo", "Kamboola", "Gairi-Kamboola", "Khallsara", "Rudda"]
|
||||
assert report["blocked_named_yogas"] == [
|
||||
"Iqabala",
|
||||
@@ -30,8 +33,14 @@ def test_tajika_named_yoga_authority_promotes_only_governed_supported_rows() ->
|
||||
"Kutta",
|
||||
"Durupha",
|
||||
]
|
||||
assert report["summary"]["row_count"] == 13
|
||||
assert report["summary"]["named_yoga_counts"] == {"Ithasala": 3, "Easarapha": 5, "Yamaya": 1, "Manahoo": 2, "Kamboola": 2}
|
||||
# Exact pairs and the equal-speed Sun/Venus pair are not separating.
|
||||
# The previously omitted Moon/Saturn opposition supplies the third separation.
|
||||
assert report["summary"]["row_count"] == 11
|
||||
assert report["summary"]["named_yoga_counts"] == {"Ithasala": 3, "Easarapha": 3, "Yamaya": 1, "Manahoo": 2, "Kamboola": 2}
|
||||
separating = {tuple(row['planets']) for row in report['rows'] if row['named_yoga'] == 'Easarapha'}
|
||||
assert separating == {('Moon', 'Jupiter'), ('Moon', 'Venus'), ('Moon', 'Saturn')}
|
||||
assert any(row['planets'] == ['Sun', 'Mars'] and row['motion'] == 'exact'
|
||||
for row in report['interactions'])
|
||||
assert report["pl9_forming_pairs"]
|
||||
assert any(row["named_yoga"] == "Ithasala" for row in report["pl9_forming_pairs"])
|
||||
assert any(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Ported from yinduzhanxing fb8fe915 for BUG-1652.
|
||||
# Synced from yinduzhanxing 3509ccd7 for BUG-1655.
|
||||
from __future__ import annotations
|
||||
|
||||
from scripts.tajika_named_yoga_governed_draft import build_tajika_named_yoga_governed_draft
|
||||
@@ -21,9 +21,9 @@ def test_governed_named_yoga_draft_wraps_kernel_candidates_without_authority() -
|
||||
assert report["schema_version"] == "jyotish.tajika_named_yoga_governed_draft.v1"
|
||||
assert report["status"] == "draft_only"
|
||||
assert report["authority_ready"] is False
|
||||
assert report["summary"]["row_count"] == 13
|
||||
assert report["summary"]["named_yoga_counts"] == {"Ithasala": 3, "Easarapha": 5, "Yamaya": 1, "Manahoo": 2, "Kamboola": 2}
|
||||
assert report["summary"]["motion_counts"] == {"applying": 3, "separating": 5}
|
||||
assert report["summary"]["row_count"] == 11
|
||||
assert report["summary"]["named_yoga_counts"] == {"Ithasala": 3, "Easarapha": 3, "Yamaya": 1, "Manahoo": 2, "Kamboola": 2}
|
||||
assert report["summary"]["motion_counts"] == {"applying": 3, "separating": 3}
|
||||
assert all(row["review_status"] == "governed_seed_resolution_review_required" for row in report["rows"])
|
||||
assert {row["named_yoga"] for row in report["rows"]} == {"Ithasala", "Easarapha", "Yamaya", "Manahoo", "Kamboola"}
|
||||
assert "named_yoga_verdict" not in report
|
||||
|
||||
Reference in New Issue
Block a user