diff --git a/docs/research/antigravity_sidecar_work_order_round39_2026_06_27.md b/docs/research/antigravity_sidecar_work_order_round39_2026_06_27.md new file mode 100644 index 00000000..cf8f135b --- /dev/null +++ b/docs/research/antigravity_sidecar_work_order_round39_2026_06_27.md @@ -0,0 +1,131 @@ +# Antigravity AI Sidecar Work Order - Round 39 - 2026-06-27 + +## Mission + +本轮继续只服务印度占星 `skill` 主线,不做网页/app 外观工作,不改核心源码。目标是替主线程进一步压缩“全球第一 skill”还缺的硬情报,尤其围绕: + +1. PyJHora black-box 资产继续扩充 +2. VedAstro service adapter 对接前的字段映射与公开契约核查 +3. Dasha / Shadbala / Tajika 三大战线的真实 external oracle 首包之后的第二批优先级 +4. 文章级解释模板的权威降噪 +5. 长期 benchmark 护城河的公开字段设计 + +## Hard Constraints + +- 不修改主仓核心实现代码。 +- 只做研究、检索、黑盒比对、任务拆解、资料整理。 +- 必须优先复用现有 `docs/research/`、`references/oracle/`、`references/open_source_sources/` 资料。 +- AGPL / GPL 只允许 black-box、stdout、字段映射、行为观察,不允许建议复制代码实现。 +- 每份报告必须能直接减少 Codex 下一轮的上下文浪费。 + +## Work Packages + +### A. PyJHora black-box asset expansion board + +目标: + +- 基于现有 `references/oracle/artifacts/` 和 `pending_packets/`,列出下一批最值得补抓的 12 个 PyJHora black-box 资产。 +- 优先级偏向: + - Chara Dasha + - Kalachakra Dasha + - Ashtakavarga / SAV / BAV + - Bhava Bala + - Special Lagnas + - Vargottama / Pushkara / Avastha 边界例子 + +输出: +- `antigravity_round39_pyjhora_blackbox_asset_expansion_board_2026_06_27.md` + +### B. VedAstro request/response mapping audit + +目标: + +- 只研究 VedAstro 作为 service adapter candidate 时,哪些字段和我们本地 contract 已对齐,哪些还缺中间映射层。 +- 明确: + - ayanamsa policy + - node policy + - body naming + - divisional chart identifiers + - dasha naming + - timezone / DST expectations + +输出: +- `antigravity_round39_vedastro_mapping_audit_2026_06_27.md` + +### C. Three-front second-wave packet rerank + +目标: + +- 在 Dasha / Shadbala / Tajika 三大战线里,不再讨论 first packet,而是排出 second-wave 的前 15 个 packet。 +- 每个 packet 说明: + - 为什么它是 second-wave 高 ROI + - 需要人类录入还是可以先靠公开书例 + - 对 skill 精度和“全球第一”目标的实际贡献 + +输出: +- `antigravity_round39_three_front_second_wave_packets_2026_06_27.md` + +### D. Authority-first article template truth cleanup + +目标: + +- 把近几轮用户补充的文章、截图线索里,容易误导的说法筛一遍。 +- 特别检查: + - 财富点 / Lakshmi / Dhana + - DK / UL / spouse elevation + - 上升度数 / 紧密合相 + - Nakshatra 天赋标签 + - 工作时间预测 + +输出: +- `antigravity_round39_article_truth_cleanup_2026_06_27.md` + +### E. Public benchmark schema v2 board + +目标: + +- 设计一个别人难以短期追上的公开 benchmark 字段体系。 +- 不是产品方案,而是字段和数据制度方案: + - case metadata + - external evidence provenance + - tolerance policy + - ayanamsa / node / timezone normalization + - explanation-template scoring + +输出: +- `antigravity_round39_public_benchmark_schema_v2_2026_06_27.md` + +### F. Codex direct top 80 + +目标: + +- 基于以上 5 包,为主线程输出只服务 skill 的 Top 80 下一步动作。 +- 每条动作必须标记: + - `doc_freeze` + - `tdd_now` + - `needs_human_oracle` + - `blocked_by_license` + +输出: +- `antigravity_round39_codex_round40_skill_top80_2026_06_27.md` + +## Deliverables + +至少生成以下 6 个文件到 `docs/research/`: + +1. `antigravity_round39_pyjhora_blackbox_asset_expansion_board_2026_06_27.md` +2. `antigravity_round39_vedastro_mapping_audit_2026_06_27.md` +3. `antigravity_round39_three_front_second_wave_packets_2026_06_27.md` +4. `antigravity_round39_article_truth_cleanup_2026_06_27.md` +5. `antigravity_round39_public_benchmark_schema_v2_2026_06_27.md` +6. `antigravity_round39_codex_round40_skill_top80_2026_06_27.md` + +## Success Standard + +- 不重复“还有很多 gap”这种空话。 +- 每份报告都能直接节省 Codex 下一轮时间。 +- 明确区分: + - 现在可直接编码 + - 现在只能文档冻结 + - 必须等待人类 external oracle + - 受许可证隔离,只能 black-box diff --git a/references/oracle/artifacts/pyjhora_oracle_artifact_manifest.json b/references/oracle/artifacts/pyjhora_oracle_artifact_manifest.json new file mode 100644 index 00000000..1cdba36b --- /dev/null +++ b/references/oracle/artifacts/pyjhora_oracle_artifact_manifest.json @@ -0,0 +1,76 @@ +{ + "scope": "pyjhora_oracle_artifact_manifest", + "generated_at": "2026-06-27T06:25:10.958318+00:00", + "artifact_count": 9, + "packet_count": 8, + "artifacts": [ + "pyjhora_extreme_latitude_kp_shadbala_stdout_20260627.txt", + "pyjhora_redacted_place_shadbala_raman_stdout_20260627.txt", + "pyjhora_historical_epoch_dasha_stdout_20260627.txt", + "pyjhora_oracle_artifact_manifest.json", + "pyjhora_steve_jobs_dasha_stdout_20260627.txt", + "pyjhora_steve_jobs_shadbala_lahiri_stdout_20260627.txt", + "pyjhora_steve_jobs_varshaphala_1984_lahiri_stdout_20260627.txt", + "pyjhora_user_REDACTED_YEAR_dasha_stdout_20260627.txt", + "pyjhora_user_REDACTED_YEAR_shadbala_lahiri_stdout_20260627.txt" + ], + "pending_packets": [ + "external_template_extreme_latitude_kp_pyjhora_20260627.json", + "external_template_redacted_place_shadbala_raman_pyjhora_20260627.json", + "external_template_historical_epoch_lahiri_pyjhora_20260627.json", + "external_template_steve_jobs_dasha_lahiri_pyjhora_20260627.json", + "external_template_steve_jobs_shadbala_lahiri_pyjhora_20260627.json", + "external_template_steve_jobs_varshaphala_1984_lahiri_pyjhora_20260627.json", + "external_template_user_REDACTED_YEAR_moon_longitude_lahiri_pyjhora_20260627.json", + "external_template_user_REDACTED_YEAR_shadbala_lahiri_pyjhora_20260627.json" + ], + "fronts": { + "dasha": { + "artifact_count": 4, + "packet_count": 3, + "artifacts": [ + "pyjhora_historical_epoch_dasha_stdout_20260627.txt", + "pyjhora_oracle_artifact_manifest.json", + "pyjhora_steve_jobs_dasha_stdout_20260627.txt", + "pyjhora_user_REDACTED_YEAR_dasha_stdout_20260627.txt" + ], + "pending_packets": [ + "external_template_extreme_latitude_kp_pyjhora_20260627.json", + "external_template_historical_epoch_lahiri_pyjhora_20260627.json", + "external_template_steve_jobs_dasha_lahiri_pyjhora_20260627.json" + ] + }, + "shadbala": { + "artifact_count": 4, + "packet_count": 4, + "artifacts": [ + "pyjhora_extreme_latitude_kp_shadbala_stdout_20260627.txt", + "pyjhora_redacted_place_shadbala_raman_stdout_20260627.txt", + "pyjhora_steve_jobs_shadbala_lahiri_stdout_20260627.txt", + "pyjhora_user_REDACTED_YEAR_shadbala_lahiri_stdout_20260627.txt" + ], + "pending_packets": [ + "external_template_redacted_place_shadbala_raman_pyjhora_20260627.json", + "external_template_steve_jobs_shadbala_lahiri_pyjhora_20260627.json", + "external_template_user_REDACTED_YEAR_moon_longitude_lahiri_pyjhora_20260627.json", + "external_template_user_REDACTED_YEAR_shadbala_lahiri_pyjhora_20260627.json" + ] + }, + "tajika_sahams": { + "artifact_count": 1, + "packet_count": 1, + "artifacts": [ + "pyjhora_steve_jobs_varshaphala_1984_lahiri_stdout_20260627.txt" + ], + "pending_packets": [ + "external_template_steve_jobs_varshaphala_1984_lahiri_pyjhora_20260627.json" + ] + } + }, + "files": { + "manifest": "references/oracle/artifacts/pyjhora_oracle_artifact_manifest.json", + "artifacts_dir": "references/oracle/artifacts", + "pending_packets_dir": "references/oracle/artifacts/pending_packets" + }, + "boundary": "These files are black-box external evidence only. They document PyJHora outputs and pending oracle packets without importing AGPL code into the local skill implementation." +} diff --git a/scripts/generate_pyjhora_oracle_artifact_manifest.py b/scripts/generate_pyjhora_oracle_artifact_manifest.py new file mode 100644 index 00000000..9d9a98ae --- /dev/null +++ b/scripts/generate_pyjhora_oracle_artifact_manifest.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +"""Generate a tracked manifest for PyJHora black-box oracle artifacts.""" + +from __future__ import annotations + +import json +from collections import defaultdict +from datetime import datetime, timezone +from pathlib import Path +from typing import Any + + +ROOT = Path(__file__).resolve().parents[1] +ARTIFACTS_DIR = ROOT / "references" / "oracle" / "artifacts" +PENDING_DIR = ARTIFACTS_DIR / "pending_packets" +OUTPUT_PATH = ARTIFACTS_DIR / "pyjhora_oracle_artifact_manifest.json" + + +def _front_for_name(name: str) -> str: + lowered = name.lower() + if "varshaphala" in lowered or "sahams" in lowered or "tajika" in lowered: + return "tajika_sahams" + if "shadbala" in lowered or "moon_longitude" in lowered: + return "shadbala" + return "dasha" + + +def _relative(path: Path) -> str: + return str(path.relative_to(ROOT)) + + +def build_manifest() -> dict[str, Any]: + artifacts = sorted( + path for path in ARTIFACTS_DIR.glob("pyjhora_*") + if path.is_file() + ) + pending_packets = sorted( + path for path in PENDING_DIR.glob("*pyjhora_20260627.json") + if path.is_file() + ) + + fronts: dict[str, dict[str, Any]] = defaultdict(lambda: {"artifact_count": 0, "packet_count": 0, "artifacts": [], "pending_packets": []}) + for artifact in artifacts: + front = _front_for_name(artifact.name) + fronts[front]["artifact_count"] += 1 + fronts[front]["artifacts"].append(artifact.name) + for packet in pending_packets: + front = _front_for_name(packet.name) + fronts[front]["packet_count"] += 1 + fronts[front]["pending_packets"].append(packet.name) + + report = { + "scope": "pyjhora_oracle_artifact_manifest", + "generated_at": datetime.now(timezone.utc).isoformat(), + "artifact_count": len(artifacts), + "packet_count": len(pending_packets), + "artifacts": [path.name for path in artifacts], + "pending_packets": [path.name for path in pending_packets], + "fronts": { + front: { + "artifact_count": payload["artifact_count"], + "packet_count": payload["packet_count"], + "artifacts": payload["artifacts"], + "pending_packets": payload["pending_packets"], + } + for front, payload in sorted(fronts.items()) + }, + "files": { + "manifest": _relative(OUTPUT_PATH), + "artifacts_dir": _relative(ARTIFACTS_DIR), + "pending_packets_dir": _relative(PENDING_DIR), + }, + "boundary": ( + "These files are black-box external evidence only. They document PyJHora outputs and " + "pending oracle packets without importing AGPL code into the local skill implementation." + ), + } + OUTPUT_PATH.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") + return report + + +def main() -> int: + print(json.dumps(build_manifest(), ensure_ascii=False, indent=2)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/vedastro_service_adapter.py b/scripts/vedastro_service_adapter.py index ca7587a9..56ee1b7b 100644 --- a/scripts/vedastro_service_adapter.py +++ b/scripts/vedastro_service_adapter.py @@ -11,6 +11,7 @@ from __future__ import annotations import argparse import json import os +import socket from pathlib import Path from typing import Any from urllib import request, error @@ -59,6 +60,7 @@ PARITY_CASES = { } DEFAULT_TIMEOUT_SECONDS = 8 +TIMEOUT_ENV = "VEDASTRO_TIMEOUT_SECONDS" RETRY_POLICY = { "max_attempts": 2, "backoff_seconds": 1, @@ -67,6 +69,16 @@ RETRY_POLICY = { ALLOW_NETWORK_ENV = "VEDASTRO_ENABLE_NETWORK" +def _timeout_seconds() -> float: + raw = os.environ.get(TIMEOUT_ENV, "").strip() + if not raw: + return DEFAULT_TIMEOUT_SECONDS + try: + return float(raw) + except ValueError: + return DEFAULT_TIMEOUT_SECONDS + + def schema() -> dict[str, Any]: request_example = { **PARITY_CASES["beijing_first_use_demo"], @@ -130,7 +142,7 @@ def _unconfigured(reason: str) -> dict[str, Any]: "endpoint_env": "VEDASTRO_API_ENDPOINT", "api_key_env": "VEDASTRO_API_KEY", "provenance_mode": "external_service_candidate", - "timeout_seconds": DEFAULT_TIMEOUT_SECONDS, + "timeout_seconds": _timeout_seconds(), "retry_policy": RETRY_POLICY, }, } @@ -156,7 +168,7 @@ def _normalize_success(payload: dict[str, Any], endpoint: str) -> dict[str, Any] "transport": "http_json_service_boundary", "endpoint": endpoint, "provenance_mode": "external_service_candidate", - "timeout_seconds": DEFAULT_TIMEOUT_SECONDS, + "timeout_seconds": _timeout_seconds(), "retry_policy": RETRY_POLICY, **(payload.get("source_metadata") or {}), }, @@ -189,7 +201,7 @@ def run_case(case_id: str) -> dict[str, Any]: "transport": "http_json_service_boundary", "endpoint": endpoint, "provenance_mode": "external_service_candidate", - "timeout_seconds": DEFAULT_TIMEOUT_SECONDS, + "timeout_seconds": _timeout_seconds(), "retry_policy": RETRY_POLICY, "network_execution_env": ALLOW_NETWORK_ENV, }, @@ -201,7 +213,7 @@ def run_case(case_id: str) -> dict[str, Any]: headers={"Content-Type": "application/json"}, method="POST", ) - with request.urlopen(req, timeout=DEFAULT_TIMEOUT_SECONDS) as resp: + with request.urlopen(req, timeout=_timeout_seconds()) as resp: raw = resp.read().decode("utf-8") payload = json.loads(raw) except error.HTTPError as exc: @@ -215,7 +227,7 @@ def run_case(case_id: str) -> dict[str, Any]: "transport": "http_json_service_boundary", "endpoint": endpoint, "provenance_mode": "external_service_candidate", - "timeout_seconds": DEFAULT_TIMEOUT_SECONDS, + "timeout_seconds": _timeout_seconds(), "retry_policy": RETRY_POLICY, "network_execution_env": ALLOW_NETWORK_ENV, }, @@ -231,12 +243,12 @@ def run_case(case_id: str) -> dict[str, Any]: "transport": "http_json_service_boundary", "endpoint": endpoint, "provenance_mode": "external_service_candidate", - "timeout_seconds": DEFAULT_TIMEOUT_SECONDS, + "timeout_seconds": _timeout_seconds(), "retry_policy": RETRY_POLICY, "network_execution_env": ALLOW_NETWORK_ENV, }, } - except TimeoutError: + except (TimeoutError, socket.timeout): return { "backend": "vedastro_service_adapter_candidate", "available": False, @@ -247,7 +259,7 @@ def run_case(case_id: str) -> dict[str, Any]: "transport": "http_json_service_boundary", "endpoint": endpoint, "provenance_mode": "external_service_candidate", - "timeout_seconds": DEFAULT_TIMEOUT_SECONDS, + "timeout_seconds": _timeout_seconds(), "retry_policy": RETRY_POLICY, "network_execution_env": ALLOW_NETWORK_ENV, }, @@ -263,7 +275,7 @@ def run_case(case_id: str) -> dict[str, Any]: "transport": "http_json_service_boundary", "endpoint": endpoint, "provenance_mode": "external_service_candidate", - "timeout_seconds": DEFAULT_TIMEOUT_SECONDS, + "timeout_seconds": _timeout_seconds(), "retry_policy": RETRY_POLICY, "network_execution_env": ALLOW_NETWORK_ENV, }, diff --git a/tests/test_pyjhora_oracle_artifact_manifest.py b/tests/test_pyjhora_oracle_artifact_manifest.py new file mode 100644 index 00000000..aa14f4c1 --- /dev/null +++ b/tests/test_pyjhora_oracle_artifact_manifest.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +import json +import subprocess +import sys +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +def test_pyjhora_oracle_artifact_manifest_reports_current_blackbox_assets() -> None: + completed = subprocess.run( + [sys.executable, "scripts/generate_pyjhora_oracle_artifact_manifest.py"], + cwd=ROOT, + text=True, + capture_output=True, + timeout=120, + check=False, + ) + + assert completed.returncode == 0, completed.stderr or completed.stdout + report = json.loads(completed.stdout) + assert report["scope"] == "pyjhora_oracle_artifact_manifest" + assert report["artifact_count"] >= 5 + assert report["packet_count"] >= 4 + assert report["fronts"]["dasha"]["artifact_count"] >= 2 + assert report["fronts"]["shadbala"]["artifact_count"] >= 2 + assert report["fronts"]["tajika_sahams"]["artifact_count"] >= 1 + assert report["files"]["manifest"].endswith("references/oracle/artifacts/pyjhora_oracle_artifact_manifest.json") + + manifest = ROOT / "references" / "oracle" / "artifacts" / "pyjhora_oracle_artifact_manifest.json" + assert manifest.exists() + manifest_data = json.loads(manifest.read_text(encoding="utf-8")) + assert manifest_data["scope"] == "pyjhora_oracle_artifact_manifest" + assert "pyjhora_steve_jobs_dasha_stdout_20260627.txt" in manifest_data["artifacts"] + assert "external_template_steve_jobs_dasha_lahiri_pyjhora_20260627.json" in manifest_data["pending_packets"] diff --git a/tests/test_vedastro_service_adapter_executor.py b/tests/test_vedastro_service_adapter_executor.py index 2fb9ca45..bc4f6873 100644 --- a/tests/test_vedastro_service_adapter_executor.py +++ b/tests/test_vedastro_service_adapter_executor.py @@ -198,3 +198,83 @@ def test_vedastro_service_adapter_classifies_http_error() -> None: report = json.loads(completed.stdout) assert report["status"] == "http_error" assert "503" in report["reason"] + + +def test_vedastro_service_adapter_classifies_invalid_json_response() -> None: + class Handler(BaseHTTPRequestHandler): + def do_POST(self) -> None: # noqa: N802 + body = b"not-json" + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + + def log_message(self, format: str, *args) -> None: # noqa: A003 + return + + server = HTTPServer(("127.0.0.1", 0), Handler) + thread = threading.Thread(target=server.serve_forever, daemon=True) + thread.start() + try: + env = os.environ.copy() + env["VEDASTRO_API_ENDPOINT"] = f"http://127.0.0.1:{server.server_port}/vedastro" + env["VEDASTRO_ENABLE_NETWORK"] = "1" + completed = subprocess.run( + [sys.executable, "scripts/vedastro_service_adapter.py", "--case", "beijing_first_use_demo"], + cwd=ROOT, + text=True, + capture_output=True, + timeout=120, + check=False, + env=env, + ) + finally: + server.shutdown() + thread.join(timeout=5) + + assert completed.returncode == 0, completed.stderr or completed.stdout + report = json.loads(completed.stdout) + assert report["status"] == "invalid_json" + + +def test_vedastro_service_adapter_classifies_timeout() -> None: + class Handler(BaseHTTPRequestHandler): + def do_POST(self) -> None: # noqa: N802 + import time + + time.sleep(0.2) + body = b"{}" + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + + def log_message(self, format: str, *args) -> None: # noqa: A003 + return + + server = HTTPServer(("127.0.0.1", 0), Handler) + thread = threading.Thread(target=server.serve_forever, daemon=True) + thread.start() + try: + env = os.environ.copy() + env["VEDASTRO_API_ENDPOINT"] = f"http://127.0.0.1:{server.server_port}/vedastro" + env["VEDASTRO_ENABLE_NETWORK"] = "1" + env["VEDASTRO_TIMEOUT_SECONDS"] = "0.05" + completed = subprocess.run( + [sys.executable, "scripts/vedastro_service_adapter.py", "--case", "beijing_first_use_demo"], + cwd=ROOT, + text=True, + capture_output=True, + timeout=120, + check=False, + env=env, + ) + finally: + server.shutdown() + thread.join(timeout=5) + + assert completed.returncode == 0, completed.stderr or completed.stdout + report = json.loads(completed.stdout) + assert report["status"] == "timeout"