From 25000647e71f9d9cc36bc0d01631d6f73da20182 Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Mon, 29 Jun 2026 03:25:03 +0800 Subject: [PATCH] Land QA fixes and repository hygiene guardrails --- .gitignore | 3 +++ findings.md | 4 ++++ progress.md | 20 ++++++++++++++++++++ scripts/cmd_muhurta.py | 7 ++++++- scripts/jyotish_engine.py | 17 +++++++++++++++++ scripts/remedies.py | 7 ++++++- tests/test_api_server_security.py | 13 +++++++++++++ tests/test_cli_smoke.py | 31 +++++++++++++++++++++++++++++++ 8 files changed, 100 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 72082bb8..1f070d12 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ __pycache__/ .agents/ venv_vedastro/ scratch/local/ +scratch/test_*.json +scratch/test_*.txt +test_hooks.json hermes_memory.db/ *.egg-info/ dist/ diff --git a/findings.md b/findings.md index 48702953..3a3e2c32 100644 --- a/findings.md +++ b/findings.md @@ -161,3 +161,7 @@ - Round 7 后续审计发现:如果未来人工把 oracle JSON 某条 case 升级为 `external_verified`,旧队列生成器会重新生成 draft evidence packet,导致“已填外部真值仍过不了 validator”。已修为保留 `evidence_packet.status/metadata`,并用 `target_fields` 固定目标字段集合。 - 对标差距结论:相对 VedAstro/PyJHora/JHora,当前最实质缺口不是基础 D1/D9,而是 Dasha/Shadbala 外部真值样本库、合婚/Koota/Panchanga 的 API/产品深度、以及普通用户一键使用/校准状态可视化。PyJHora 因 AGPL 只能黑盒参照,JHora 因闭源只能截图级人工采集。 - 2026-06-26 Round 28/29 接力结论:Round 28 的 30 份研究报告已回到主仓待归档区,覆盖全球开源排名、PyJHora/JHora 广度差距、MIT 可复制资产、Dasha/Panchanga/Muhurta/Synastry/Shadbala/Jaimini/KP/Varga/Yoga 深度路线、skill 同步缺口、真新增技法最小集与 Round29 Top100;同时新增 `docs/research/antigravity_sidecar_work_order_round29_2026_06_26.md`,将副手任务继续加压到 skill 全量补齐差距、API/CLI/前端隐藏能力、整机碎片复用第二轮、云端同步白名单、外部 oracle 精度闭环与 Round30 Top120。 +- 2026-06-28 真实用户全功能 QA:使用 `REDACTED_DATE REDACTED_TIME`、河北REDACTED_PLACEREDACTED_PLACE矿区近似坐标 `36.4467,114.2` 跑完 CLI/API/前端点击/质量门矩阵。能力注册表 89 项有效、碎片审计 37 CLI + 41 API 无未注册高价值候选、前端 `--mode all` 浏览器点击通过、quick quality gate 通过;正式报告见 `docs/research/sample_user_full_function_qa_REDACTED_YEAR_redacted_place_2026_06_28.md`。 +- 本轮 QA 真 bug:`jyotish_engine.py muhurta` CLI 因 Sun/Moon tuple 进入 `calc_tithi` 崩溃;`varga-full --divisions ... D81/D108/D144` 仍走旧 `scripts/varga.py` 而失败,尽管 `--custom 81` 可算;`/api/remedies` 对数值型 Shadbala 简写会 500,应归一化或返回 400。 +- 本轮 QA 边界结论:`/api/technique_example` 用目录官方 example payload 可 200,普通出生资料直打 400 是合同误用而非后端坏;`db-stats` 返回数据库不存在,说明入口可用但本机 celebrity/validation DB 数据源缺席;外部 JHora/PyJHora/VedAstro oracle 精度仍未因此闭环。 +- VedAstro 强制雷达边界:官方 Events Builder 暴露 `SearchEvents / GetEventTiming / ListEventTypes` 三个事件端点、400+ 预定义事件和 `Scan precision (hours)`,API/Python surface 继续按 600+/596+ 计算节点理解。本项目不硬复刻 596 个函数,而是把 VedAstro range scan 作为 `career/relationship/finance` strict workflow 的必需外部高频 timing radar;缺失时进入 `vedastro_range_scan_missing` 和 Technique Audit blocked 行,不能再静默跳过。 diff --git a/progress.md b/progress.md index 578649b8..2a80bc84 100644 --- a/progress.md +++ b/progress.md @@ -423,3 +423,23 @@ - `oracle_functional_benefics.py` 新增 CLI JSON 合同测试;`python3 scripts/audit_fragments.py --strict` 显示 candidate_count 从 3 降到 0。 - Functional Benefic/Malefic 的 `Technique Audit Table` 与 real-reading checklist 现在显式要求/输出 `functional_neutrals` 与 `yogakarakas`。 - 合婚 strict bridge 修复 `additional_kutas.BadConstellations` 的 nested dict 形态,并把 mitigation exceptions 折叠成 `exception_mitigated_match`,防止已有 Ashtakoot 细节资产在 relationship adjudicator 中被吞掉。 + +## 2026-06-28T20:05:00+08:00 - REDACTED_YEAR REDACTED_PLACE真实用户全功能 QA + +- 按用户要求以 `REDACTED_DATE REDACTED_TIME`、中国河北REDACTED_PLACEREDACTED_PLACE矿区近似坐标 `lat=36.4467 lon=114.2 tz=8` 跑真实用户全功能验收;scratch 产物放在 `scratch/local/sample_user_qa_2026_06_28/`。 +- CLI 矩阵覆盖 30 条出生盘/事件/合盘/问事/年运/分盘命令,28 条通过;失败为 `varga-full --divisions` 高分盘 D81/D108/D144 路由旧实现、`muhurta` CLI tuple longitude 崩溃。 +- API 矩阵覆盖 42 个请求,40 个通过;`/api/remedies` 对数值型 Shadbala 简写返回 500,官方 catalog payload 可通过;`/api/technique_example` 用 catalog example payload 通过,普通出生资料直打 400 归类为合同边界。 +- 前端真实浏览器 `python3 tests/run_frontend_click_smoke.py --mode all --timeout 420` 通过,覆盖 core/mobile/offline/pdf/workspace/mobile-trust/import-files;`npm run build` 通过。 +- 工程守门通过:`python3 scripts/audit_capabilities.py --mode validate` 有效;`python3 scripts/audit_fragments.py --strict` 有效且 candidate_count=0;`python3 scripts/run_quality_gate.py --profile quick --skip-frontend-runtime` 通过,配置内 283 项 pytest 通过。 +- 新增正式报告 `docs/research/sample_user_full_function_qa_REDACTED_YEAR_redacted_place_2026_06_28.md`,下一步优先修复 `muhurta` CLI、`varga-full --divisions` 高分盘合同、`/api/remedies` 输入硬化,并单独处理当前 dirty worktree/scratch 残留。 + +## 2026-06-28T21:25:00+08:00 - VedAstro 596+/Events 高频雷达强制合同 + +- 用户明确要求必须使用外部 VedAstro 596+ 高频流年 API;本轮不把它误解成要本地硬复刻 596 个函数,而是把 VedAstro 作为外部高频 timing radar 接入 strict workflow 边界。 +- 复核官方公开面:`APIBuilder.html` 对应通用 calculator surface;`EventsChartAPIBuilder.html` 元数据写明 `SearchEvents / GetEventTiming / ListEventTypes`、400+ pre-defined events,并有 `Scan precision (hours)`;PyPI `vedastro` 当前观测版本为 `1.23.25`。 +- `scripts/vedastro_service_adapter.py --print-schema` 新增 `vedastro_calculation_coverage`,记录 `596+` Python calculations、`600+` API Builder calculators、`400+` Events Builder events、三事件方法,以及 `high_frequency_life_event_radar` 用途。 +- VedAstro range-scan preview 现在显式包含 `vedastro_event_method = SearchEvents`,并继续通过 `VEDASTRO_API_ENDPOINT` 与 `VEDASTRO_ENABLE_NETWORK` 做外部服务边界控制。 +- `mcp_server.py` 中 `career / relationship / finance` 的 strict workflow 现在把 `external_activation` 视为必需 VedAstro 外部雷达槽;缺失时输出 `missing_required_external_radar`、`vedastro_range_scan_missing` 和 `Technique Audit` blocked 行;有事件时输出 `used` 行和 event_count。 +- 守住边界:VedAstro 事件证据不直接替代本地双重大运、分盘、Shadbala/Ashtakavarga/Jaimini/Functional role,也不直接设置 `dominant_label / payout_label`;缺本地 promise 时仍受原评分上限约束。 +- 新增审计文档 `docs/research/vedastro_required_high_frequency_radar_contract_2026_06_28.md`。 +- 验证:`python3 -m pytest tests/test_vedastro_service_adapter_executor.py tests/test_vedastro_external_technique_evidence.py tests/test_vedastro_parity_matrix.py tests/test_vedastro_adapter_candidate_guard.py -q` 通过;`python3 -m pytest tests/test_mcp_strict_workflow_finance.py tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_career.py tests/test_life_event_graph_v1.py -q` 通过。 diff --git a/scripts/cmd_muhurta.py b/scripts/cmd_muhurta.py index 8751b150..a3d9707a 100644 --- a/scripts/cmd_muhurta.py +++ b/scripts/cmd_muhurta.py @@ -28,13 +28,18 @@ def _weekday_to_vara(py_weekday: int) -> int: def _get_sun_moon_lons(year: int, month: int, day: int, hour: int = 12, ayanamsa_name: str = 'lahiri') -> tuple: """获取太阳/月亮恒星黄经。优先 swisseph,退化为近似算法。""" + def _primary_longitude(value): + if isinstance(value, (list, tuple)): + return float(value[0]) + return float(value) + try: import swisseph as swe jd_ut = swe.julday(year, month, day, hour) flags = sidereal_flags(swe, ayanamsa_name) sun_res = swe.calc_ut(jd_ut, swe.SUN, flags) moon_res = swe.calc_ut(jd_ut, swe.MOON, flags) - return sun_res[0], moon_res[0], True + return _primary_longitude(sun_res[0]), _primary_longitude(moon_res[0]), True except Exception: pass # 近似算法 diff --git a/scripts/jyotish_engine.py b/scripts/jyotish_engine.py index 89ca4c12..08a122f9 100644 --- a/scripts/jyotish_engine.py +++ b/scripts/jyotish_engine.py @@ -2962,6 +2962,23 @@ def cmd_varga_full(args): result[pn] = calc.calc_varga_with_variant(lon, divisions[0], variant) return result + try: + sys.path.insert(0, SCRIPT_DIR) + from divisional_charts_extended import DivisionalChartsCalculator, VargaType + extended_available = {varga.division: varga for varga in VargaType} + if any(division not in {2, 3, 4, 7, 9, 10, 12, 16, 20, 24, 27, 30, 40, 45, 60} for division in (divisions or [])): + calc = DivisionalChartsCalculator() + selected = [extended_available[division] for division in divisions] + result = {} + for varga in selected: + key = f'D{varga.division}_{varga.varga_name}' + result[key] = calc._calculate_single_varga(varga, planet_lons, asc_deg) + return result + except KeyError as e: + return {"error": f"不支持的D{e.args[0]}。请使用 --custom N 计算任意D-N分盘。"} + except ImportError: + pass + return calc_all_vargas(planet_lons, asc_deg, divisions) diff --git a/scripts/remedies.py b/scripts/remedies.py index 9806c322..d43a3ca4 100644 --- a/scripts/remedies.py +++ b/scripts/remedies.py @@ -104,7 +104,12 @@ def recommend_remedies(shadbala_results: Dict, planet_dignities: Dict = None, evidence_chain = [] for planet, data in shadbala_results.items(): - rupas = data.get('total_rupas', data.get('rupas', 1.0)) + if isinstance(data, (int, float)) and not isinstance(data, bool): + rupas = float(data) + elif isinstance(data, dict): + rupas = data.get('total_rupas', data.get('rupas', 1.0)) + else: + rupas = 1.0 if rupas < STRENGTH_THRESHOLDS['weak']: weak_planets.append(planet) evidence_chain.append({ diff --git a/tests/test_api_server_security.py b/tests/test_api_server_security.py index 379ac1b5..eea8e771 100644 --- a/tests/test_api_server_security.py +++ b/tests/test_api_server_security.py @@ -368,6 +368,19 @@ def test_remedies_accepts_api_rupas_shape() -> None: assert result['recommendations']['mantras'] +def test_remedies_endpoint_accepts_numeric_shadbala_shorthand() -> None: + handler = _handler() + result = handler._compute_remedies({ + 'shadbala': {'Sun': 0.42, 'Moon': 0.68}, + 'dasha_lord': 'Saturn', + 'doshas': ['Mangal Dosha'], + }) + + assert result['weak_planets'] == ['Sun'] + assert 'Moon' in result['moderate_planets'] + assert any(item['source'] == 'shadbala' and item['planet'] == 'Sun' for item in result['evidence_chain']) + + def test_import_chart_accepts_plain_text() -> None: handler = _handler() result = handler._import_chart_text({ diff --git a/tests/test_cli_smoke.py b/tests/test_cli_smoke.py index c1824fd4..ded9e57b 100644 --- a/tests/test_cli_smoke.py +++ b/tests/test_cli_smoke.py @@ -398,6 +398,37 @@ def test_varga_cli_outputs_d9_and_d10() -> None: assert "Moon" in charts["D9_Navamsa"] +def test_varga_full_cli_divisions_supports_high_vargas() -> None: + result = run_engine( + "varga-full", + *BASE_BIRTH_ARGS, + "--divisions", + "D9,D60,D81,D108,D144", + ) + + assert "D81_Navamsa-Navamsa" in result + assert "D108_Dwadasamsa-Navamsa" in result + assert "D144_Dwadasamsa-Dwadasamsa" in result + assert result["D144_Dwadasamsa-Dwadasamsa"]["planets"]["Moon"]["house"] in range(1, 13) + + +def test_muhurta_cli_scan_days_outputs_panchanga_without_tuple_crash() -> None: + output = run_engine_text( + "muhurta", + "--date", + "2026-06-28", + "--activity", + "business", + "--scan-days", + "2", + ) + + assert "Muhurta" in output + assert "Panchanga" in output + assert "2026-06-28" in output + assert "unsupported operand type" not in output + + def test_ashtakavarga_cli_keeps_sav_invariant() -> None: result = run_engine("ashtakavarga", *BASE_BIRTH_ARGS) assert result["sav"]["total"] == 337