chore: add engineering quality gate

This commit is contained in:
732642856
2026-06-05 15:58:06 +08:00
parent 8da45c56b3
commit 625deb4007
14 changed files with 437 additions and 18 deletions
+84
View File
@@ -0,0 +1,84 @@
#!/usr/bin/env python3
"""Run the Jyotish skill quality gate used by local development and CI."""
from __future__ import annotations
import argparse
import json
import os
import py_compile
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
PYTHON = sys.executable
COMPILE_TARGETS = [
ROOT / "scripts" / "jyotish_engine.py",
ROOT / "scripts" / "varga.py",
ROOT / "scripts" / "ashtakavarga.py",
ROOT / "scripts" / "yoga_engine.py",
ROOT / "scripts" / "audit_capabilities.py",
ROOT / "scripts" / "validate_bphs_invariants.py",
ROOT / "tests" / "run_golden_cases.py",
]
def run(cmd: list[str], *, optional: bool = False) -> bool:
print(f"\n$ {' '.join(cmd)}")
completed = subprocess.run(cmd, cwd=ROOT, text=True)
if completed.returncode == 0:
return True
if optional:
print(f"Optional step failed with exit code {completed.returncode}; continuing.")
return False
raise SystemExit(completed.returncode)
def compile_targets() -> None:
print("\n== Compile core Python files ==")
for target in COMPILE_TARGETS:
print(f"compile {target.relative_to(ROOT)}")
py_compile.compile(str(target), doraise=True)
def validate_json_files() -> None:
print("\n== Validate critical JSON files ==")
for relative in [
"references/technique_registry.json",
"references/yoga_rules.json",
"references/standard_test_charts.json",
"references/validation_logic_report.json",
"tests/golden/golden_cases.json",
]:
path = ROOT / relative
if not path.exists():
continue
with path.open("r", encoding="utf-8") as handle:
json.load(handle)
print(f"json ok {relative}")
def main() -> int:
parser = argparse.ArgumentParser(description="Run Jyotish skill quality gate")
parser.add_argument("--skip-slow", action="store_true", help="Skip slow golden-case regressions")
parser.add_argument("--skip-yoga-logic", action="store_true", help="Skip Yoga logic comparison report refresh")
args = parser.parse_args()
os.environ.setdefault("PYTHONPATH", str(ROOT / "scripts"))
compile_targets()
validate_json_files()
run([PYTHON, "scripts/audit_capabilities.py", "--mode", "validate"])
run([PYTHON, "scripts/validate_bphs_invariants.py"])
run([PYTHON, "-m", "pytest", "tests"])
if not args.skip_slow:
run([PYTHON, "tests/run_golden_cases.py", "--python", PYTHON])
if not args.skip_yoga_logic:
run([PYTHON, "scripts/validate_logic_v2.py"], optional=True)
print("\nQuality gate passed.")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+7 -1
View File
@@ -78,8 +78,14 @@ def calc_varga(lon, div):
si=_si(lon); d=lon-si*30; ps=30.0/div; pi=int(d/ps)
# For all vargas, degree within divisional sign is scaled to 0-30 degrees.
dp=(d-pi*ps)*div
# Keep the displayed divisional degree inside [0, 30). Values such as
# 29.9999997 can round to 30.0000 at sign boundaries, which breaks
# downstream range invariants while the underlying sign mapping is valid.
dp_display = round(dp, 4)
if dp_display >= 30:
dp_display = 0.0
vsi=varga_map(si,pi,div)
r={'sign':_sn(vsi),'sign_idx':vsi,'degree_in_sign':round(dp,4),
r={'sign':_sn(vsi),'sign_idx':vsi,'degree_in_sign':dp_display,
'part_index':pi,'lord':SIGN_LORDS.get(_sn(vsi),'')}
if div==9: r['pada']=pi+1
return r