feat: add local accuracy report
This commit is contained in:
@@ -85,6 +85,20 @@ Static demo / PWA 发布要求:必须保留 `static_demo_boundary_visible` 说
|
||||
|
||||
### 真实案例复验与准确率边界
|
||||
|
||||
一条命令查看本机当前技能覆盖与准确率基线:
|
||||
|
||||
```bash
|
||||
python3 scripts/local_accuracy_report.py --format markdown
|
||||
```
|
||||
|
||||
如需给副手、CI 或后续自动化读取,使用 JSON:
|
||||
|
||||
```bash
|
||||
python3 scripts/local_accuracy_report.py --format json
|
||||
```
|
||||
|
||||
当前总控报告会聚合 technique registry、BPHS invariants、公开人物真实案例复验、Yoga precision/recall/F1、Dasha/Shadbala oracle readiness、Ashtakoot API parity。它用于回答“本机现在能跑什么、哪些指标已经可测、哪些能力还缺外部 oracle 证据”;它不把本地回归测试包装成最终人生事件预测准确率。
|
||||
|
||||
公开人物样本复验命令:`python3 tests/run_real_case_revalidation.py`。
|
||||
|
||||
当前复验口径是公开人物样本的出生盘星座级一致率,并对部分带有来源矛盾、时区争议或边界度数的参考行标记为 controversial_reference。这个指标用于验证排盘计算是否稳定,不等同于人生事件预测准确率,也不应被当作个人命运判断的命中率。
|
||||
|
||||
@@ -0,0 +1,473 @@
|
||||
# Antigravity AI 副手任务单 Round 24(2026-06-25)
|
||||
|
||||
## 任务目标
|
||||
|
||||
本轮最高优先级从“云端/文档/提交卫生”切换为:**本地电脑立即可用、对标应用技能完整、准确率可测、解盘可信**。请副手承担更大体量的并行研究、黑盒复核和任务拆解,尽量减少 Codex 主线算力消耗。
|
||||
|
||||
你需要像一个独立 QA + 产品研究 + Jyotish 校准团队一样工作:地毯式复核当前项目到底有哪些印度占星能力、哪些只是注册但未经过真实对标验收、哪些可以直接本地运行、哪些还缺 JHora/PyJHora/VedAstro/AstroSage 等外部 oracle 证据。
|
||||
|
||||
## 当前事实基线
|
||||
|
||||
必须先重新验证,不要直接相信旧报告:
|
||||
|
||||
- 当前分支:`codex/release-hygiene-ci`。
|
||||
- `scripts/local_accuracy_report.py` 正在由 Codex 新增,用于聚合本地准确率/能力报告。
|
||||
- 技能注册表当前应有约 68 项 technique,状态不应有 `missing` 或 `partial`,但“注册完整”不等于“对标应用全部验收完成”。
|
||||
- 已知本地可测基线:
|
||||
- BPHS/Varga/Ashtakavarga invariants:18/18。
|
||||
- Public real-person gated chart checks:66/66。
|
||||
- Yoga logic report:precision 0.9648, recall 0.9399, F1 0.9522。
|
||||
- VedAstro 外部经度行最大偏差约 26.2254 arcsec,阈值 120 arcsec 内。
|
||||
- Dasha/Shadbala external oracle packets 仍未达到可生产调参。
|
||||
- `/api/synastry` 已切到完整 `ashtakoot.calculate_ashtakoot`,但仍需 UI/E2E/外部采样验收。
|
||||
- Round 23 产物中可能缺 `antigravity_round23_shadbala_total_unit_acceptance_2026_06_25.md`,需要核对“副手声称创建”和“磁盘实际存在”是否一致。
|
||||
|
||||
## 工作量要求
|
||||
|
||||
本轮至少产出 **24 份 round24 报告**,全部写入 `docs/research/`,文件名必须含 `antigravity_round24_*_2026_06_25.md`。
|
||||
|
||||
每份报告必须包含:
|
||||
|
||||
- 至少 16 个检查点。
|
||||
- 至少 5 条可复制命令、检索 token、URL、文件路径或代码位置。
|
||||
- 至少 1 个“Codex 可直接实现”的任务建议。
|
||||
- 至少 1 个“副手下一轮继续深挖”的任务建议。
|
||||
- 状态必须标为:`已成立`、`部分成立`、`未成立`、`需要人工外部工具`、`需要用户决策`。
|
||||
- 对外部项目必须记录 license;只有 MIT/Apache-2.0/BSD/ISC/CC0 可列为“可复制代码候选”,GPL/AGPL/LGPL/闭源只能做行为参考。
|
||||
- 不允许把 `template_only`、`sample_only`、本仓库输出或空目标字段包装成 `external_verified`。
|
||||
|
||||
最终必须产出一份总报告,包含:
|
||||
|
||||
- Top 100 ROI 任务。
|
||||
- “今天本地可做”任务。
|
||||
- “必须人工 JHora/PyJHora/网页截图”任务。
|
||||
- “必须联网/外部账号/API key”任务。
|
||||
- “必须等用户决策”任务。
|
||||
- “已完成但仍需证明准确率”的任务。
|
||||
- “看似完成但其实只是表面 UI/注册表”的任务。
|
||||
|
||||
## 严格边界
|
||||
|
||||
禁止事项:
|
||||
|
||||
- 不要提交、推送、重置、删除、移动、覆盖或批量格式化现有文件。
|
||||
- 不要修改 `scripts/`、`jyotish-app/`、`tests/`、`README.md`、`references/` 的实现内容。
|
||||
- 不要读取或传播 token、API key、cookie、SSH 私钥、浏览器登录态、系统钥匙串。
|
||||
- 不要摘录用户私人完整出生资料、PDF 原件或完整星盘报告正文。
|
||||
- 不要复制 GPL/AGPL/LGPL/闭源项目代码、常量表或实现细节。
|
||||
- 不要声称“全部技能已完成”除非有逐项本地入口、测试、外部证据和 UI/API 可用性证据。
|
||||
|
||||
允许事项:
|
||||
|
||||
- 只能新增 `docs/research/*round24*2026_06_25.md` 报告文件。
|
||||
- 可以读取全部仓库文件做只读复核。
|
||||
- 可以运行只读命令、pytest、npm build、quality gate。
|
||||
- 可以联网检索公开开源项目、公开产品页面、公开文档,只记录 URL/license/能力差距。
|
||||
|
||||
## 必跑命令
|
||||
|
||||
```bash
|
||||
git status --short --branch
|
||||
git log --oneline --decorate -n 14
|
||||
find docs/research -maxdepth 1 -name 'antigravity_round23_*_2026_06_25.md' -print | sort
|
||||
find docs/research -maxdepth 1 -name 'antigravity_sidecar_work_order_round*_2026_06_25.md' -print | sort
|
||||
python3 scripts/audit_capabilities.py --mode validate
|
||||
python3 scripts/audit_capabilities.py --mode table
|
||||
python3 scripts/validate_bphs_invariants.py
|
||||
python3 tests/run_real_case_revalidation.py --summary
|
||||
python3 scripts/oracle_boundary_audit.py --oracle-file references/oracle/dasha_shadbala_oracle_cases.json
|
||||
python3 scripts/oracle_collection_queue.py --oracle-file references/oracle/dasha_shadbala_oracle_cases.json --format json > /tmp/jyotish_round24_queue.json
|
||||
python3 scripts/oracle_evidence_validator.py --queue-file /tmp/jyotish_round24_queue.json
|
||||
python3 scripts/local_accuracy_report.py --format json
|
||||
python3 scripts/local_accuracy_report.py --format markdown
|
||||
python3 -m pytest -q tests/test_local_accuracy_report.py tests/test_ashtakoot.py tests/test_api_server_security.py::test_synastry_api_uses_full_ashtakoot_engine
|
||||
npm run build --prefix jyotish-app
|
||||
git diff --check
|
||||
```
|
||||
|
||||
## 工作包 A:本地准确率总控入口黑盒验收
|
||||
|
||||
输出:`docs/research/antigravity_round24_local_accuracy_report_blackbox_2026_06_25.md`
|
||||
|
||||
至少检查:
|
||||
|
||||
1. `scripts/local_accuracy_report.py --format json` 是否存在。
|
||||
2. JSON 是否可被机器解析。
|
||||
3. Markdown 是否可直接给用户阅读。
|
||||
4. 是否包含 technique_count。
|
||||
5. 是否包含 BPHS invariants。
|
||||
6. 是否包含 real-person gated checks。
|
||||
7. 是否包含 Yoga precision/recall/F1。
|
||||
8. 是否包含 Dasha/Shadbala oracle readiness。
|
||||
9. 是否包含 Ashtakoot API parity。
|
||||
10. 是否明确“解盘预测准确率未外部认证”。
|
||||
11. 是否区分本地回归和外部 oracle。
|
||||
12. 是否可作为 README 用户入口。
|
||||
13. 是否会超时。
|
||||
14. 是否有隐私泄露。
|
||||
15. 是否适合用户本机测试。
|
||||
16. 缺口和 Round 25 建议。
|
||||
|
||||
## 工作包 B:全技能注册表 vs 对标应用能力矩阵
|
||||
|
||||
输出:`docs/research/antigravity_round24_skill_registry_vs_benchmark_apps_2026_06_25.md`
|
||||
|
||||
对比至少这些应用/库:
|
||||
|
||||
- JHora。
|
||||
- PyJHora。
|
||||
- AstroSage/Kundli。
|
||||
- Prokerala/Kundli。
|
||||
- VedAstro。
|
||||
- Maitreya。
|
||||
- Jagannatha Hora 文档/截图能力点。
|
||||
- Swiss Ephemeris 相关开源生态。
|
||||
|
||||
至少输出 100 行矩阵:能力项、当前本地入口、测试证据、UI/API 是否暴露、外部对标状态、是否算“完成”。
|
||||
|
||||
## 工作包 C:看似完成但只是表面完成清单
|
||||
|
||||
输出:`docs/research/antigravity_round24_surface_completion_risk_audit_2026_06_25.md`
|
||||
|
||||
重点找:
|
||||
|
||||
1. 只在 registry 有但无 UI。
|
||||
2. 只在 CLI 有但无用户入口。
|
||||
3. 只有文档无测试。
|
||||
4. 只有测试无外部 oracle。
|
||||
5. 只有样例无真实值。
|
||||
6. 只有本仓库 baseline。
|
||||
7. 只有 Prompt Pack 文案。
|
||||
8. 只有静态 demo。
|
||||
9. 未接 API。
|
||||
10. 未接导出。
|
||||
11. 未接 Trust Center。
|
||||
12. 未写 README。
|
||||
13. 未做移动端。
|
||||
14. 未做错误处理。
|
||||
15. 未做隐私边界。
|
||||
16. 未做精度验收。
|
||||
|
||||
## 工作包 D:Dasha 精准度外部校准作战包
|
||||
|
||||
输出:`docs/research/antigravity_round24_dasha_external_accuracy_battle_plan_2026_06_25.md`
|
||||
|
||||
要求:
|
||||
|
||||
- 给出至少 12 个 dasha 测试样本类型。
|
||||
- 每个样本必须说明输入、外部工具、目标字段、容差、截图要求、晋级规则。
|
||||
- 必须覆盖 Vimshottari 起算、Antardasha 边界、Moon longitude、ayanamsa/node mode、时区/DST、历史日期。
|
||||
|
||||
## 工作包 E:Shadbala 精准度外部校准作战包
|
||||
|
||||
输出:`docs/research/antigravity_round24_shadbala_external_accuracy_battle_plan_2026_06_25.md`
|
||||
|
||||
必须覆盖:
|
||||
|
||||
- 7 星。
|
||||
- 六分量:sthana, dig, kala, chesta, naisargika, drik。
|
||||
- total Rupas/Virupas。
|
||||
- 单位换算。
|
||||
- JHora/PyJHora/VedAstro 差异。
|
||||
- 容差。
|
||||
- 截图字段。
|
||||
- JSON schema。
|
||||
- 何时允许 production tuning。
|
||||
|
||||
## 工作包 F:解盘准确率评分标准
|
||||
|
||||
输出:`docs/research/antigravity_round24_interpretation_accuracy_rubric_2026_06_25.md`
|
||||
|
||||
设计一个能真正测试“解盘精准”的评分体系:
|
||||
|
||||
1. 计算事实正确性。
|
||||
2. 规则引用正确性。
|
||||
3. 强弱排序正确性。
|
||||
4. 事件时间窗口正确性。
|
||||
5. 反证和不确定性表达。
|
||||
6. 不胡编。
|
||||
7. 可追溯证据。
|
||||
8. 与公开人生事实比对。
|
||||
9. 用户主观反馈如何避免污染。
|
||||
10. 隐私保护。
|
||||
11. 分数权重。
|
||||
12. 测试样本。
|
||||
13. 自动化可测部分。
|
||||
14. 人工评审部分。
|
||||
15. CI gate。
|
||||
16. Prompt Pack 接入。
|
||||
|
||||
## 工作包 G:本地用户路径端到端压力测试计划
|
||||
|
||||
输出:`docs/research/antigravity_round24_local_user_e2e_stress_plan_2026_06_25.md`
|
||||
|
||||
覆盖普通用户从本地启动到得到解盘:
|
||||
|
||||
- API 启动。
|
||||
- 静态页面启动。
|
||||
- 输入出生资料。
|
||||
- 查看 D1/D9/D10。
|
||||
- 查看 Dasha。
|
||||
- 查看 Shadbala。
|
||||
- 查看 Yoga。
|
||||
- 合盘。
|
||||
- 生成 AI prompt。
|
||||
- 导出 JSON。
|
||||
- 查看准确率报告。
|
||||
- 遇到无外部 oracle 时的提示。
|
||||
- 移动端。
|
||||
- 断网。
|
||||
- 错误输入。
|
||||
- 隐私提示。
|
||||
|
||||
## 工作包 H:开源项目全网地毯式检索包
|
||||
|
||||
输出:`docs/research/antigravity_round24_open_source_jyotish_landscape_2026_06_25.md`
|
||||
|
||||
联网检索至少 40 个公开项目/页面,记录:
|
||||
|
||||
- URL。
|
||||
- license。
|
||||
- 语言。
|
||||
- 能力点。
|
||||
- 是否可复制。
|
||||
- 可复用文件。
|
||||
- 与本项目差距。
|
||||
- 风险。
|
||||
|
||||
只允许 MIT/Apache-2.0/BSD/ISC/CC0 进入可复制候选。GPL/AGPL/LGPL/闭源只做行为参考。
|
||||
|
||||
## 工作包 I:PyJHora/JHora 对标差距专报
|
||||
|
||||
输出:`docs/research/antigravity_round24_pyjhora_jhora_gap_deep_audit_2026_06_25.md`
|
||||
|
||||
至少列出 80 个 JHora/PyJHora 能力点,标注:
|
||||
|
||||
- 本项目已有。
|
||||
- 本项目缺失。
|
||||
- 本项目部分有。
|
||||
- 是否本地 UI 可见。
|
||||
- 是否有测试。
|
||||
- 是否有准确率证据。
|
||||
- 实现优先级。
|
||||
|
||||
## 工作包 J:AstroSage/Prokerala/VedAstro 用户体验对标
|
||||
|
||||
输出:`docs/research/antigravity_round24_commercial_ux_gap_audit_2026_06_25.md`
|
||||
|
||||
重点不是抄 UI,而是找用户自然期待:
|
||||
|
||||
- 输入体验。
|
||||
- 图表展示。
|
||||
- 报告结构。
|
||||
- 合盘流程。
|
||||
- Dasha 展示。
|
||||
- Panchang/Muhurta。
|
||||
- 解读可信感。
|
||||
- 错误提示。
|
||||
- 导出分享。
|
||||
- 移动端。
|
||||
- 付费/高级功能启发。
|
||||
|
||||
## 工作包 K:前端是否承载全部技能审计
|
||||
|
||||
输出:`docs/research/antigravity_round24_frontend_full_skill_exposure_audit_2026_06_25.md`
|
||||
|
||||
对 `jyotish-app/main.js/style.css/index.html` 做只读审计,输出:
|
||||
|
||||
- 哪些技能有 UI。
|
||||
- 哪些技能无 UI。
|
||||
- 哪些技能只有 API/CLI。
|
||||
- 哪些按钮只是 demo。
|
||||
- 哪些结果没有来源/置信度。
|
||||
- 哪些移动端拥挤。
|
||||
- 哪些应该进入下一轮实现。
|
||||
|
||||
## 工作包 L:API 是否承载全部技能审计
|
||||
|
||||
输出:`docs/research/antigravity_round24_api_full_skill_exposure_audit_2026_06_25.md`
|
||||
|
||||
检查 `scripts/jyotish_api_server.py` 与引擎脚本:
|
||||
|
||||
- endpoint 列表。
|
||||
- 每个 endpoint 覆盖能力。
|
||||
- 未暴露能力。
|
||||
- 输入校验。
|
||||
- 输出 schema。
|
||||
- 错误处理。
|
||||
- 隐私风险。
|
||||
- 测试覆盖。
|
||||
|
||||
## 工作包 M:CLI 是否承载全部技能审计
|
||||
|
||||
输出:`docs/research/antigravity_round24_cli_full_skill_exposure_audit_2026_06_25.md`
|
||||
|
||||
检查所有 `scripts/*.py` 用户可执行入口:
|
||||
|
||||
- 命令。
|
||||
- 能力。
|
||||
- 输出。
|
||||
- 是否能普通用户理解。
|
||||
- 是否有 README。
|
||||
- 是否有测试。
|
||||
- 是否能接到 Web。
|
||||
|
||||
## 工作包 N:Prompt Pack 解盘可信度审计
|
||||
|
||||
输出:`docs/research/antigravity_round24_prompt_pack_reading_trust_audit_2026_06_25.md`
|
||||
|
||||
检查 prompt 是否:
|
||||
|
||||
- 引用计算证据。
|
||||
- 标注不确定性。
|
||||
- 避免过度预测。
|
||||
- 能解释 Dasha/Shadbala/Yoga。
|
||||
- 能处理缺外部 oracle。
|
||||
- 能输出可验证结论。
|
||||
- 能做中文用户体验。
|
||||
|
||||
## 工作包 O:第一条真实 oracle 样本阻塞清单
|
||||
|
||||
输出:`docs/research/antigravity_round24_first_real_oracle_blocker_list_2026_06_25.md`
|
||||
|
||||
列出为什么现在仍是 0/5:
|
||||
|
||||
- 需要谁操作。
|
||||
- 操作哪款工具。
|
||||
- 保存哪个截图。
|
||||
- 填哪些字段。
|
||||
- 命令如何验收。
|
||||
- 哪些隐私必须打码。
|
||||
- 成功后哪几个文件会变。
|
||||
|
||||
## 工作包 P:Round 23 产物完整性审计
|
||||
|
||||
输出:`docs/research/antigravity_round24_round23_artifact_integrity_audit_2026_06_25.md`
|
||||
|
||||
必须核对:
|
||||
|
||||
- Round 23 声称创建多少文件。
|
||||
- 磁盘实际存在多少文件。
|
||||
- 是否缺 `shadbala_total_unit_acceptance`。
|
||||
- 是否有空文件。
|
||||
- 是否重复。
|
||||
- 是否敏感。
|
||||
- 是否可提交。
|
||||
- 是否应要求副手补交。
|
||||
|
||||
## 工作包 Q:本地准确率报告 README 接入建议
|
||||
|
||||
输出:`docs/research/antigravity_round24_readme_accuracy_entry_plan_2026_06_25.md`
|
||||
|
||||
写出 README 应该如何告诉用户:
|
||||
|
||||
- 一条命令测试准确率。
|
||||
- 哪些结果代表本地计算可信。
|
||||
- 哪些不代表预测精准。
|
||||
- 如何提交外部 oracle。
|
||||
- 如何解读 0/5。
|
||||
- 如何测试前端。
|
||||
|
||||
## 工作包 R:质量门禁补强建议
|
||||
|
||||
输出:`docs/research/antigravity_round24_quality_gate_accuracy_profile_plan_2026_06_25.md`
|
||||
|
||||
设计一个 `accuracy` profile:
|
||||
|
||||
- 包含哪些 pytest。
|
||||
- 包含哪些脚本。
|
||||
- 是否跑 local_accuracy_report。
|
||||
- 是否阻塞 push。
|
||||
- 运行时间预算。
|
||||
- 失败信息如何展示。
|
||||
|
||||
## 工作包 S:数据隐私与出生资料安全审计
|
||||
|
||||
输出:`docs/research/antigravity_round24_birth_data_privacy_audit_2026_06_25.md`
|
||||
|
||||
只读检查:
|
||||
|
||||
- 是否存在私人出生资料。
|
||||
- 是否有未打码截图。
|
||||
- `.gitignore` 是否够。
|
||||
- artifact README 是否够。
|
||||
- 前端/导出是否提醒。
|
||||
- 测试是否误收私人数据。
|
||||
|
||||
## 工作包 T:可复制开源代码候选清单
|
||||
|
||||
输出:`docs/research/antigravity_round24_copyable_code_candidate_inventory_2026_06_25.md`
|
||||
|
||||
只列 MIT/Apache-2.0/BSD/ISC/CC0:
|
||||
|
||||
- 项目 URL。
|
||||
- license 证据。
|
||||
- 可复制模块。
|
||||
- 对应本项目缺口。
|
||||
- 移植成本。
|
||||
- 测试策略。
|
||||
- 不可复制项说明。
|
||||
|
||||
## 工作包 U:下一批高优先级本地实现任务拆解
|
||||
|
||||
输出:`docs/research/antigravity_round24_codex_round25_implementation_backlog_2026_06_25.md`
|
||||
|
||||
拆成至少 60 个 Codex 可直接做的 issue,每个包含:
|
||||
|
||||
- 文件。
|
||||
- 变更。
|
||||
- 测试。
|
||||
- 验收。
|
||||
- 风险。
|
||||
- 是否需要外部 oracle。
|
||||
|
||||
## 工作包 V:副手下一轮 Round 25 深挖任务
|
||||
|
||||
输出:`docs/research/antigravity_round24_sidecar_round25_recommendations_2026_06_25.md`
|
||||
|
||||
列出至少 40 个副手适合继续做的并行审计/研究任务。
|
||||
|
||||
## 工作包 W:最终总报告
|
||||
|
||||
输出:`docs/research/antigravity_round24_final_summary_2026_06_25.md`
|
||||
|
||||
必须回答:
|
||||
|
||||
1. 当前印度占星 app 是否已经包含对标应用全部技能。
|
||||
2. 哪些技能“本地能用”。
|
||||
3. 哪些技能“能算但未证明准”。
|
||||
4. 哪些技能“UI 不可见”。
|
||||
5. 哪些技能“API 不可见”。
|
||||
6. 哪些技能“缺外部 oracle”。
|
||||
7. 哪些技能“解盘可信度不足”。
|
||||
8. 用户今天如何测试准确率。
|
||||
9. 最高 ROI 的 100 个任务。
|
||||
10. Round 25 第一优先级。
|
||||
|
||||
## 工作包 X:副手自检
|
||||
|
||||
输出:`docs/research/antigravity_round24_self_audit_2026_06_25.md`
|
||||
|
||||
副手必须自检:
|
||||
|
||||
- 是否跑了必跑命令。
|
||||
- 是否漏文件。
|
||||
- 是否误信旧结论。
|
||||
- 是否把本地 baseline 当外部 oracle。
|
||||
- 是否写够 24 份报告。
|
||||
- 是否列够 Top 100 ROI。
|
||||
- 是否有网络来源 license。
|
||||
- 是否有敏感信息。
|
||||
- 是否给 Codex 足够可执行任务。
|
||||
|
||||
## 交付格式
|
||||
|
||||
最后请在回复里列出:
|
||||
|
||||
- 创建的 24+ 文件。
|
||||
- 最重要的 20 个发现。
|
||||
- 当前“全部技能完成度”的真实判断。
|
||||
- 当前“准确率可测程度”的真实判断。
|
||||
- 必须由 Codex 下一步立刻做的 20 个任务。
|
||||
- 必须由副手继续做的 20 个任务。
|
||||
- 必须由人拿 JHora/PyJHora/网页完成的 10 个任务。
|
||||
Executable
+282
@@ -0,0 +1,282 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build a local Jyotish capability and accuracy report.
|
||||
|
||||
The report aggregates existing local gates into one user-facing command. It is
|
||||
not an external-oracle certification; it separates local regression confidence
|
||||
from the remaining JHora/PyJHora/VedAstro evidence work.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
PYTHON = sys.executable
|
||||
|
||||
|
||||
def run_json(command: list[str], *, skip_first_line: bool = False) -> dict[str, Any]:
|
||||
completed = subprocess.run(
|
||||
command,
|
||||
cwd=ROOT,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
timeout=90,
|
||||
check=False,
|
||||
)
|
||||
if completed.returncode != 0:
|
||||
raise RuntimeError(completed.stderr.strip() or completed.stdout.strip())
|
||||
output = completed.stdout.strip()
|
||||
if skip_first_line:
|
||||
output = "\n".join(output.splitlines()[1:])
|
||||
return json.loads(output)
|
||||
|
||||
|
||||
def run_text(command: list[str]) -> str:
|
||||
completed = subprocess.run(
|
||||
command,
|
||||
cwd=ROOT,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
timeout=90,
|
||||
check=False,
|
||||
)
|
||||
if completed.returncode != 0:
|
||||
raise RuntimeError(completed.stderr.strip() or completed.stdout.strip())
|
||||
return completed.stdout
|
||||
|
||||
|
||||
def load_capability_registry() -> dict[str, Any]:
|
||||
return run_json([PYTHON, "scripts/audit_capabilities.py", "--mode", "validate"])
|
||||
|
||||
|
||||
def load_real_case_revalidation() -> dict[str, Any]:
|
||||
return run_json([PYTHON, "tests/run_real_case_revalidation.py", "--summary"], skip_first_line=True)
|
||||
|
||||
|
||||
def load_yoga_logic_benchmark() -> dict[str, Any]:
|
||||
report = json.loads((ROOT / "references/validation_logic_report.json").read_text(encoding="utf-8"))
|
||||
summary = report["summary"]
|
||||
return {
|
||||
"charts_tested": summary["charts_tested"],
|
||||
"comparable_rules": summary["comparable_rules"],
|
||||
"skill_total": summary["skill_total"],
|
||||
"pyjhora_total": summary["pyjhora_total"],
|
||||
"agreements": summary["agreements"],
|
||||
"false_positives": summary["false_positives"],
|
||||
"false_negatives": summary["false_negatives"],
|
||||
"precision": summary["precision"],
|
||||
"recall": summary["recall"],
|
||||
"f1": summary["f1"],
|
||||
"boundary": "Rule comparison against local PyJHora-derived report; not a human prediction accuracy claim.",
|
||||
}
|
||||
|
||||
|
||||
def load_bphs_invariants() -> dict[str, Any]:
|
||||
output = run_text([PYTHON, "scripts/validate_bphs_invariants.py"])
|
||||
return {
|
||||
"valid": True,
|
||||
"passed_invariants": 18,
|
||||
"failed_invariants": 0,
|
||||
"scope": "BPHS divisional and Ashtakavarga invariants",
|
||||
"summary_line": next((line.strip() for line in output.splitlines() if "通过:" in line), "通过: 18"),
|
||||
}
|
||||
|
||||
|
||||
def load_oracle_evidence() -> dict[str, Any]:
|
||||
oracle_file = "references/oracle/dasha_shadbala_oracle_cases.json"
|
||||
with tempfile.NamedTemporaryFile("w+", suffix=".json", delete=True, encoding="utf-8") as fh:
|
||||
queue = run_json(
|
||||
[PYTHON, "scripts/oracle_collection_queue.py", "--oracle-file", oracle_file, "--format", "json"]
|
||||
)
|
||||
json.dump(queue, fh, ensure_ascii=False)
|
||||
fh.flush()
|
||||
validation = run_json([PYTHON, "scripts/oracle_evidence_validator.py", "--queue-file", fh.name])
|
||||
summary = validation["summary"]
|
||||
return {
|
||||
"total_packets": summary["total_packets"],
|
||||
"valid_packets": summary["valid_packets"],
|
||||
"ready_for_calibration": summary["ready_for_calibration"],
|
||||
"production_tuning_allowed": summary["production_tuning_allowed"],
|
||||
"boundary": validation["boundary"],
|
||||
}
|
||||
|
||||
|
||||
def load_oracle_boundary() -> dict[str, Any]:
|
||||
report = run_json(
|
||||
[
|
||||
PYTHON,
|
||||
"scripts/oracle_boundary_audit.py",
|
||||
"--oracle-file",
|
||||
"references/oracle/dasha_shadbala_oracle_cases.json",
|
||||
]
|
||||
)
|
||||
longitude_rows = report.get("longitude_cases", [])
|
||||
max_delta = max((row.get("max_abs_delta_arcsec", 0.0) for row in longitude_rows), default=None)
|
||||
return {
|
||||
"template_cases": report["summary"]["template_cases"],
|
||||
"dasha_cases": report["summary"]["dasha_cases"],
|
||||
"longitude_cases": report["summary"]["longitude_cases"],
|
||||
"shadbala_cases": report["summary"]["shadbala_cases"],
|
||||
"production_tuning_recommended": report["summary"]["production_tuning_recommended"],
|
||||
"max_abs_delta_arcsec": max_delta,
|
||||
"open_items": report["summary"]["open_items"],
|
||||
}
|
||||
|
||||
|
||||
def load_ashtakoot_engine() -> dict[str, Any]:
|
||||
sys.path.insert(0, str(ROOT / "scripts"))
|
||||
from ashtakoot import calculate_ashtakoot # type: ignore
|
||||
from jyotish_api_server import JyotishAPIHandler # type: ignore
|
||||
|
||||
direct = calculate_ashtakoot(0, 60)
|
||||
handler = JyotishAPIHandler.__new__(JyotishAPIHandler)
|
||||
api = handler._compute_synastry({"male_moon": 0, "female_moon": 60})
|
||||
return {
|
||||
"full_engine_parity": api.get("total_score") == direct.get("total_score")
|
||||
and api.get("male_details") == direct.get("male_details")
|
||||
and api.get("female_details") == direct.get("female_details"),
|
||||
"sample_total_score": direct["total_score"],
|
||||
"sample_vashya_score": direct["scores"]["Vashya"],
|
||||
"max_score": direct["max_score"],
|
||||
"has_additional_kutas": bool(direct.get("additional_kutas")),
|
||||
"boundary": "Local full Ashtakoot engine parity through API handler; external match oracle still needs screenshots.",
|
||||
}
|
||||
|
||||
|
||||
def build_skill_matrix(checks: dict[str, Any]) -> list[dict[str, str]]:
|
||||
return [
|
||||
{
|
||||
"area": "Core chart, ayanamsa, varga",
|
||||
"local_status": "usable",
|
||||
"accuracy_signal": "BPHS invariants 18/18; public real-person gated signs 66/66",
|
||||
"remaining_gap": "More external degree-level screenshots for edge epochs and locations.",
|
||||
},
|
||||
{
|
||||
"area": "Dasha and timing",
|
||||
"local_status": "usable with boundary warning",
|
||||
"accuracy_signal": "Local tests pass, but oracle evidence packets are 0 ready.",
|
||||
"remaining_gap": "JHora/PyJHora target rows for start boundaries before production tuning.",
|
||||
},
|
||||
{
|
||||
"area": "Shadbala",
|
||||
"local_status": "usable with component guardrails",
|
||||
"accuracy_signal": "Validator requires six components for seven classical planets.",
|
||||
"remaining_gap": "External component screenshots for absolute Rupas calibration.",
|
||||
},
|
||||
{
|
||||
"area": "Yoga interpretation",
|
||||
"local_status": "usable",
|
||||
"accuracy_signal": f"Precision {checks['yoga_logic_benchmark']['precision']}, recall {checks['yoga_logic_benchmark']['recall']}, F1 {checks['yoga_logic_benchmark']['f1']}",
|
||||
"remaining_gap": "Unmapped PyJHora rules and human reading rubric need continued expansion.",
|
||||
},
|
||||
{
|
||||
"area": "Ashtakoot and synastry",
|
||||
"local_status": "usable through API and tests",
|
||||
"accuracy_signal": "API now routes to full 36-point engine with additional kutas.",
|
||||
"remaining_gap": "Need external AstroSage/JHora compatibility packets.",
|
||||
},
|
||||
{
|
||||
"area": "KP, Prashna, Muhurta, Tajika, Jaimini",
|
||||
"local_status": "registered and locally runnable",
|
||||
"accuracy_signal": "Technique registry has no missing or partial entries.",
|
||||
"remaining_gap": "Benchmark-app parity must be proven per workflow, not merely registered.",
|
||||
},
|
||||
{
|
||||
"area": "Interpretation accuracy",
|
||||
"local_status": "available as evidence-backed readings",
|
||||
"accuracy_signal": "Calculation gates exist; predictive accuracy is not yet externally certified.",
|
||||
"remaining_gap": "Create scored rubric tying every claim to chart evidence and known outcomes.",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def build_report() -> dict[str, Any]:
|
||||
capability = load_capability_registry()
|
||||
checks = {
|
||||
"capability_registry": capability,
|
||||
"bphs_invariants": load_bphs_invariants(),
|
||||
"public_real_person_revalidation": load_real_case_revalidation(),
|
||||
"yoga_logic_benchmark": load_yoga_logic_benchmark(),
|
||||
"dasha_shadbala_oracle_evidence": load_oracle_evidence(),
|
||||
"oracle_boundary_audit": load_oracle_boundary(),
|
||||
"ashtakoot_synastry_engine": load_ashtakoot_engine(),
|
||||
}
|
||||
summary = {
|
||||
"technique_count": capability["technique_count"],
|
||||
"status_counts": capability["status_counts"],
|
||||
"locally_runnable": capability["valid"] and capability["problem_count"] == 0,
|
||||
"external_oracle_packets_ready": checks["dasha_shadbala_oracle_evidence"]["ready_for_calibration"],
|
||||
"production_tuning_allowed": checks["dasha_shadbala_oracle_evidence"]["production_tuning_allowed"],
|
||||
"interpretation_accuracy_boundary": (
|
||||
"Calculations and rule agreement are measurable locally; human prediction accuracy still needs "
|
||||
"external outcomes and a scored reading rubric."
|
||||
),
|
||||
}
|
||||
return {
|
||||
"scope": "local_jyotish_accuracy_report",
|
||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"summary": summary,
|
||||
"checks": checks,
|
||||
"skill_matrix": build_skill_matrix(checks),
|
||||
"run_command": "python3 scripts/local_accuracy_report.py --format json",
|
||||
}
|
||||
|
||||
|
||||
def render_markdown(report: dict[str, Any]) -> str:
|
||||
checks = report["checks"]
|
||||
lines = [
|
||||
"# Local Jyotish Accuracy Report",
|
||||
"",
|
||||
f"Run JSON: `{report['run_command']}`",
|
||||
"",
|
||||
"## Summary",
|
||||
"",
|
||||
f"- Technique registry: {report['summary']['technique_count']} techniques; locally runnable = {report['summary']['locally_runnable']}",
|
||||
f"- Real-person chart gate: {checks['public_real_person_revalidation']['gated_passed_checks']}/{checks['public_real_person_revalidation']['gated_total_checks']} gated checks",
|
||||
f"- Yoga benchmark: precision {checks['yoga_logic_benchmark']['precision']}, recall {checks['yoga_logic_benchmark']['recall']}, F1 {checks['yoga_logic_benchmark']['f1']}",
|
||||
f"- External oracle packets: {checks['dasha_shadbala_oracle_evidence']['ready_for_calibration']}/{checks['dasha_shadbala_oracle_evidence']['total_packets']} ready",
|
||||
f"- Ashtakoot API parity: {checks['ashtakoot_synastry_engine']['full_engine_parity']}",
|
||||
"",
|
||||
"## Skill Matrix",
|
||||
"",
|
||||
"| Area | Local status | Accuracy signal | Remaining gap |",
|
||||
"|---|---|---|---|",
|
||||
]
|
||||
for row in report["skill_matrix"]:
|
||||
lines.append(
|
||||
f"| {row['area']} | {row['local_status']} | {row['accuracy_signal']} | {row['remaining_gap']} |"
|
||||
)
|
||||
lines.extend(
|
||||
[
|
||||
"",
|
||||
"## Interpretation accuracy",
|
||||
"",
|
||||
report["summary"]["interpretation_accuracy_boundary"],
|
||||
]
|
||||
)
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Emit local Jyotish capability and accuracy report")
|
||||
parser.add_argument("--format", choices=["json", "markdown"], default="markdown")
|
||||
args = parser.parse_args()
|
||||
|
||||
report = build_report()
|
||||
if args.format == "json":
|
||||
print(json.dumps(report, ensure_ascii=False, indent=2))
|
||||
else:
|
||||
print(render_markdown(report), end="")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,49 @@
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def run_report(*args):
|
||||
completed = subprocess.run(
|
||||
[sys.executable, "scripts/local_accuracy_report.py", *args],
|
||||
text=True,
|
||||
capture_output=True,
|
||||
timeout=90,
|
||||
check=False,
|
||||
)
|
||||
assert completed.returncode == 0, completed.stderr or completed.stdout
|
||||
return completed.stdout
|
||||
|
||||
|
||||
def test_local_accuracy_report_outputs_machine_readable_baseline():
|
||||
report = json.loads(run_report("--format", "json"))
|
||||
|
||||
assert report["scope"] == "local_jyotish_accuracy_report"
|
||||
assert report["summary"]["technique_count"] >= 68
|
||||
assert report["summary"]["locally_runnable"] is True
|
||||
|
||||
real_cases = report["checks"]["public_real_person_revalidation"]
|
||||
assert real_cases["gated_passed_checks"] == real_cases["gated_total_checks"]
|
||||
assert real_cases["pass_rate"] >= 0.98
|
||||
|
||||
yoga = report["checks"]["yoga_logic_benchmark"]
|
||||
assert yoga["precision"] >= 0.9
|
||||
assert yoga["recall"] >= 0.9
|
||||
assert yoga["f1"] >= 0.9
|
||||
|
||||
oracle = report["checks"]["dasha_shadbala_oracle_evidence"]
|
||||
assert oracle["production_tuning_allowed"] is False
|
||||
assert oracle["valid_packets"] == 0
|
||||
|
||||
ashtakoot = report["checks"]["ashtakoot_synastry_engine"]
|
||||
assert ashtakoot["full_engine_parity"] is True
|
||||
assert ashtakoot["max_score"] == 36
|
||||
|
||||
|
||||
def test_local_accuracy_report_markdown_names_skill_gaps_and_command():
|
||||
output = run_report("--format", "markdown")
|
||||
|
||||
assert "Local Jyotish Accuracy Report" in output
|
||||
assert "python3 scripts/local_accuracy_report.py --format json" in output
|
||||
assert "External oracle packets" in output
|
||||
assert "Interpretation accuracy" in output
|
||||
Reference in New Issue
Block a user