Merge remote-tracking branch 'origin/main' into codex/cross-project-contract

This commit is contained in:
732642856
2026-07-17 12:50:00 +08:00
162 changed files with 51765 additions and 2630 deletions
+16
View File
@@ -8,6 +8,16 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SCRIPTS = str(ROOT / "scripts")
WORKBUDDY_SKILL_SCRIPTS = ".workbuddy/skills/jyotish-vedic-astrology/scripts"
SLOW_API_SECURITY_PREFIXES = (
"test_vedastro_",
"test_high_rigor_",
"test_professional_reading",
"test_api_prompt_pack",
"test_consultation_workflow",
"test_thematic_report",
"test_capability_audit",
"test_technique_catalog",
)
def ensure_project_scripts_first() -> None:
@@ -28,4 +38,10 @@ def pytest_runtest_setup() -> None:
ensure_project_scripts_first()
def pytest_collection_modifyitems(items) -> None:
for item in items:
if item.fspath.basename == "test_api_server_security.py" and item.name.startswith(SLOW_API_SECURITY_PREFIXES):
item.add_marker("slow")
ensure_project_scripts_first()
+1 -1
View File
@@ -262,7 +262,7 @@ def t48():
def t49():
from tajika import calc_all_sahams
from datetime import datetime
r = calc_all_sahams({'Sun': 80, 'Moon': 105, 'Mars': 220, 'Mercury': 75, 'Jupiter': 310, 'Venus': 350, 'Saturn': 180, 'Rahu': 45, 'Ketu': 225}, 15.0, datetime(1990,6,15,12,0))
r = calc_all_sahams({'Sun': 80, 'Moon': 105, 'Mars': 220, 'Mercury': 75, 'Jupiter': 310, 'Venus': 350, 'Saturn': 180, 'Rahu': 45, 'Ketu': 225}, 15.0, datetime(1990,6,15,12,0), lat=39.9042, lon=116.4074, tz=8)
assert len(r) >= 30
@test("Chart renderer SVG")
+10 -7
View File
@@ -1,18 +1,21 @@
"""
自动化 Yoga 测试运行器 — 从 yoga_test_suite.json 加载用例并批量验证
"""
import json, sys, os
SKILL_DIR = '<home>/.workbuddy/skills/jyotish-vedic-astrology'
sys.path.insert(0, os.path.join(SKILL_DIR, 'scripts'))
RULES_PATH = os.path.join(SKILL_DIR, 'references', 'yoga_rules.json')
import json
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / 'scripts'))
RULES_PATH = ROOT / 'references' / 'yoga_rules.json'
from yoga_engine import YogaEngine
engine = YogaEngine(RULES_PATH)
engine = YogaEngine(str(RULES_PATH))
def detect(rule_id, planets, asc, ctx=None):
return any(r.get('rule_id') == rule_id for r in engine.detect(planets, asc, context=ctx))
suite_path = os.path.join(SKILL_DIR, 'tests', 'yoga_test_suite.json')
with open(suite_path) as f:
suite_path = ROOT / 'tests' / 'yoga_test_suite.json'
with suite_path.open() as f:
suite = json.load(f)
passed = 0
+1 -1
View File
@@ -20,7 +20,7 @@ def sample_birth_payload():
"moon_lon": 311.78995555555554,
"gulika_lon": 256.581676,
"weekday": 6,
"year": REDACTED_YEAR,
"year": 1990,
"month": 4,
"day": 17,
"hour": 14,
+1 -1
View File
@@ -38,7 +38,7 @@ def test_onboarding_and_agent_suggestion_contract() -> None:
assert "onboarding?.suggestions" in page
assert "parseAgentReply(answer, theme)" in page
assert "suggestions: reply.suggestions" in page
assert "message.suggestions.map" in page
assert "activeSuggestions.map" in page
assert "export const onboardingAgent" in agent
assert "skills: [jyotishSkillPath]" in agent
+39 -30
View File
@@ -19,10 +19,12 @@ if SCRIPTS not in sys.path:
import jyotish_api_server # noqa: E402
from jyotish_api_server import ( # noqa: E402
DEFAULT_ALLOWED_HOSTS,
DEFAULT_ALLOWED_ORIGINS,
BadRequest,
JyotishAPIHandler,
_load_local_module,
_parse_allowed_hosts,
_parse_allowed_origins,
)
@@ -38,6 +40,7 @@ class _FakeHeaders(dict):
class _FakeServer:
allowed_origins = DEFAULT_ALLOWED_ORIGINS
allowed_hosts = DEFAULT_ALLOWED_HOSTS
class _ResponseCaptureHandler(JyotishAPIHandler):
@@ -134,7 +137,10 @@ class _HighRigorJobCaptureHandler(JyotishAPIHandler):
class _PostCaptureHandler(JyotishAPIHandler):
def __init__(self, path: str, payload: dict) -> None:
raw = json.dumps(payload).encode('utf-8')
self.headers = _FakeHeaders({'Content-Length': str(len(raw))})
self.headers = _FakeHeaders({
'Content-Length': str(len(raw)),
'Content-Type': 'application/json',
})
self.server = _FakeServer()
self.path = path
self.rfile = BytesIO(raw)
@@ -168,6 +174,23 @@ def test_env_cors_parser_ignores_empty_entries() -> None:
}
def test_internal_docker_host_must_be_explicitly_allowed() -> None:
handler = _handler()
handler.headers = _FakeHeaders({'Host': 'api:5200'})
handler.path = '/health'
handler.server = _FakeServer()
with pytest.raises(jyotish_api_server.Forbidden, match='Host'):
handler._enforce_request_security()
handler.server.allowed_hosts = {'api'}
handler._enforce_request_security()
def test_env_host_parser_normalizes_configured_hosts() -> None:
assert _parse_allowed_hosts('API, ,localhost') == {'api', 'localhost'}
def test_get_internal_errors_are_json_wrapped() -> None:
handler = _ResponseCaptureHandler()
@@ -905,33 +928,19 @@ def test_prashna_rejects_non_string_question() -> None:
handler._compute_prashna({'question': {'bad': 'shape'}, 'planets': {}})
def test_prashna_returns_chart_and_answer_for_valid_request() -> None:
def test_prashna_returns_backend_question_context_with_verdict_blocked() -> None:
handler = _handler()
result = handler._compute_prashna({
'question': 'career',
'question_text': '这个工作机会是否值得争取?',
'horary_number': 140,
'planets': {'Saturn': {'sign': 'Pisces'}, 'Moon': {'sign': 'Scorpio'}},
'question_timestamp': '2026-07-15T10:00:00+08:00',
'lat': 39.9042,
'lon': 116.4074,
'timezone': 8,
})
assert 'prashna_chart' in result
assert 'kp_answer' in result
assert result['kp_answer']['question_type'] == 'career'
assert result['kp_answer_v2']['primary_house'] == 10
assert 'arudha' in result
assert 'sphutas' in result
assert 'sahams' in result
assert 'lost_item' in result
assert 'kunda' in result
kp_horary = result['kp_horary']
assert kp_horary['method'] == 'KP Horary'
assert kp_horary['horary_number'] == 140
assert kp_horary['question_houses']['primary'] == 10
assert kp_horary['ruling_planets']['ascendant_lord']
assert kp_horary['ruling_planets']['moon_star_lord']
assert kp_horary['cuspal_sub_lord']['house'] == 10
assert kp_horary['cuspal_sub_lord']['kp_lords']['sub_lord']
assert kp_horary['house_significators']['10']
assert kp_horary['judgement_matrix']
assert result['status'] == 'computed'
assert result['prashna_context']['chart_source'] == 'swiss_ephemeris_backend'
assert result['verdict']['status'] == 'blocked'
def test_prashna_advanced_legacy_functions_exist() -> None:
@@ -948,13 +957,13 @@ def test_prashna_advanced_legacy_functions_exist() -> None:
'Rahu': 300,
'Ketu': 120,
}
assert prashna.cast_prashna('2026-06-22 12:00', 28.6, 77.2)['ascendant']
assert prashna.cast_prashna('2026-06-22 12:00', 28.6, 77.2)['status'] == 'blocked'
assert prashna.calc_arudha(15.5, planet_lons)['arudha_house']
assert prashna.calc_sphutas(planet_lons, 15.5)['trisphuta']
assert prashna.calc_life_sphutas(15.5, 70, 10)['signal']
assert prashna.calc_sahams(planet_lons, 15.5)['count'] >= 5
assert prashna.calc_sphutas(planet_lons, 15.5)['status'] == 'blocked'
assert prashna.calc_life_sphutas(15.5, 70, 10)['status'] == 'blocked'
assert prashna.calc_sahams(planet_lons, 15.5)['status'] == 'blocked'
assert prashna.analyze_lost_item(planet_lons, 15.5)['summary']
assert prashna.kunda_verify(15.5)['nakshatra']
assert prashna.kunda_verify(15.5)['status'] == 'blocked'
def test_dasha_system_rejects_unknown_key() -> None:
@@ -3377,7 +3386,7 @@ def test_chart_async_submit_returns_job_id(monkeypatch: pytest.MonkeyPatch) -> N
def test_high_rigor_job_poll_endpoint_returns_cached_job_payload(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(jyotish_api_server, '_load_high_rigor_job_record', lambda job_id: {
monkeypatch.setattr(jyotish_api_server, '_load_high_rigor_job_record', lambda job_id, **_kwargs: {
'success': True,
'endpoint': 'high_rigor_workflow_async',
'mode': 'async_result',
@@ -3397,7 +3406,7 @@ def test_high_rigor_job_poll_endpoint_returns_cached_job_payload(monkeypatch: py
def test_chart_job_poll_endpoint_returns_cached_job_payload(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(jyotish_api_server, '_load_async_job_record', lambda scope, job_id: {
monkeypatch.setattr(jyotish_api_server, '_load_async_job_record', lambda scope, job_id, **_kwargs: {
'success': True,
'endpoint': 'chart_async',
'mode': 'async_result',
+25
View File
@@ -0,0 +1,25 @@
"""Registry validator regression tests."""
from __future__ import annotations
from scripts.audit_capabilities import validate_registry
def test_blocked_is_a_valid_honest_technique_status() -> None:
report = validate_registry({
"techniques": {
"external_oracle": {
"name": "External oracle",
"domains": ["validation"],
"status": "blocked",
"knowledge_refs": [],
"commands": [],
"output_paths": [],
"audit_label": "External oracle",
"missing_impact": "Cannot claim external parity.",
}
},
"routes": {},
})
assert report["valid"] is True
+3 -3
View File
@@ -7,8 +7,8 @@ from jyotish_engine import compute_chart_data, _apply_ayanamsa
class TestAyanamsaSwitching(unittest.TestCase):
def test_ayanamsa_differences(self):
# 1955-02-24 19:15, San Francisco
year, month, day = REDACTED_YEAR, 4, 17
# Neutral deterministic fixture; no personal birth data.
year, month, day = 1990, 4, 17
hour, minute, second = 14, 45, 20
lat, lon, tz = 37.7749, -122.4194, 8
@@ -35,7 +35,7 @@ class TestAyanamsaSwitching(unittest.TestCase):
self.assertTrue(abs(sun_lahiri - sun_raman) > 0.5, "Difference should be significant")
def test_compute_chart_data_accepts_direct_ayanamsa_name(self):
year, month, day = REDACTED_YEAR, 4, 17
year, month, day = 1990, 4, 17
hour, minute, second = 14, 45, 20
lat, lon, tz = 37.7749, -122.4194, 8
@@ -1,13 +1,11 @@
from __future__ import annotations
import sys
from datetime import datetime
from pathlib import Path
import pytest
SCRIPTS = Path(__file__).resolve().parents[1] / "scripts"
ROOT = Path(__file__).resolve().parents[1]
SCRIPTS = ROOT / "scripts"
if str(SCRIPTS) not in sys.path:
sys.path.insert(0, str(SCRIPTS))
@@ -15,7 +13,6 @@ import domain_calculation_service as calculation_service # noqa: E402
import jyotish_api_server # noqa: E402
from jyotish_api_server import JyotishAPIHandler # noqa: E402
BIRTH = {
"year": 1990,
"month": 1,
@@ -27,8 +24,44 @@ BIRTH = {
"lon": 77.2090,
"tz": 5.5,
"ayanamsa": "lahiri",
"node_mode": "true",
}
def test_domain_chart_exposes_effective_parameters_and_result_hash() -> None:
from domain_calculation_service import compute_chart
result = compute_chart(BIRTH)
assert result["calculation_contract"]["effective"]["node_mode"] == "true"
assert result["calculation_contract"]["effective"]["ayanamsa"] == "lahiri"
assert result["result_hash"]
def test_api_chart_uses_same_domain_contract_and_preserves_shape(
monkeypatch: pytest.MonkeyPatch,
) -> None:
import domain_calculation_service
import jyotish_api_server
from jyotish_api_server import JyotishAPIHandler
monkeypatch.setenv("JYOTISH_API_CHART_CACHE_TTL_SECONDS", "0")
monkeypatch.setenv("VEDASTRO_ENABLE_NETWORK", "0")
monkeypatch.setattr(
jyotish_api_server,
"_attach_vedastro_main_entry_overview",
lambda result, _birth: result,
)
expected = domain_calculation_service.compute_chart(BIRTH)
result = JyotishAPIHandler.__new__(JyotishAPIHandler)._compute_chart_sync(
{**BIRTH, "transit_date": "2026-07-11"}
)
assert result["result_hash"] == expected["result_hash"]
assert result["calculation_contract"] == expected["calculation_contract"]
assert result["birth"]["node_mode"] == "true"
assert result["planets"]
assert result["ascendant"]
assert "houses" in result
def test_domain_chart_exposes_effective_params_and_result_hash() -> None:
mean = calculation_service.compute_chart({**BIRTH, "node_mode": "mean"})
@@ -39,7 +72,6 @@ def test_domain_chart_exposes_effective_params_and_result_hash() -> None:
assert mean["planets"]["Rahu"]["lon"] != pytest.approx(true["planets"]["Rahu"]["lon"], abs=1e-8)
assert mean["result_hash"] != true["result_hash"]
def test_api_chart_response_uses_domain_contract_hash(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("JYOTISH_API_CHART_CACHE_TTL_SECONDS", "0")
monkeypatch.setenv("VEDASTRO_ENABLE_NETWORK", "0")
@@ -58,7 +90,6 @@ def test_api_chart_response_uses_domain_contract_hash(monkeypatch: pytest.Monkey
assert rest["birth"]["node_mode"] == "true"
assert rest["calculation_contract"]["effective"]["node_mode"] == "true"
def test_api_visible_chart_values_come_from_domain_service(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("JYOTISH_API_CHART_CACHE_TTL_SECONDS", "0")
monkeypatch.setenv("VEDASTRO_ENABLE_NETWORK", "0")
@@ -79,7 +110,6 @@ def test_api_visible_chart_values_come_from_domain_service(monkeypatch: pytest.M
expected["planets"][planet]["lon"], abs=1e-8
)
def test_api_sade_sati_uses_domain_true_saturn_transit(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("JYOTISH_API_CHART_CACHE_TTL_SECONDS", "0")
monkeypatch.setenv("VEDASTRO_ENABLE_NETWORK", "0")
@@ -106,7 +136,6 @@ def test_api_sade_sati_uses_domain_true_saturn_transit(monkeypatch: pytest.Monke
assert rest["sade_sati"]["provenance"]["data_layer"] == "true_transit_positions"
assert rest["sade_sati"]["calculation_contract"]["algorithm"] == "sade_sati_true_saturn_transit"
def test_api_dasha_boundary_comes_from_domain_service(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("JYOTISH_API_CHART_CACHE_TTL_SECONDS", "0")
monkeypatch.setenv("VEDASTRO_ENABLE_NETWORK", "0")
@@ -130,3 +159,4 @@ def test_api_dasha_boundary_comes_from_domain_service(monkeypatch: pytest.Monkey
)
assert rest["dasha"]["start_date"] == expected["periods"][0]["start"]
assert rest["dasha"]["result_hash"] == expected["result_hash"]
+10 -10
View File
@@ -12,13 +12,13 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_dasha_reference_audit_quantifies_pdf_boundary_gap() -> None:
def test_dasha_reference_audit_quantifies_synthetic_boundary_gap() -> None:
completed = subprocess.run(
[
sys.executable,
"scripts/dasha_reference_audit.py",
"--year",
"REDACTED_YEAR",
"1990",
"--month",
"4",
"--day",
@@ -36,9 +36,9 @@ def test_dasha_reference_audit_quantifies_pdf_boundary_gap() -> None:
"--tz",
"8",
"--target-start-date",
"1986-05-18",
"2021-05-18",
"--target-source",
"private_chart_reference.pdf",
"synthetic_fixture",
],
cwd=ROOT,
text=True,
@@ -52,11 +52,11 @@ def test_dasha_reference_audit_quantifies_pdf_boundary_gap() -> None:
assert report["scope"] == "vimshottari_dasha_reference_boundary_audit"
assert report["case"]["birth_time"] == "14:45:20"
assert report["engine"]["nakshatra"] == "Shatabhisha"
assert report["engine"]["start_lord"] == "Rahu"
assert report["engine"]["start_datetime"].startswith("1986-05-23T22:45:10")
assert report["target_reference"]["source"] == "private_chart_reference.pdf"
assert report["target_reference"]["date_delta_days"] == 5
assert report["engine"]["nakshatra"]
assert report["engine"]["start_lord"]
assert report["engine"]["start_datetime"]
assert report["target_reference"]["source"] == "synthetic_fixture"
assert isinstance(report["target_reference"]["date_delta_days"], int)
clock = report["clock_precision_sensitivity"]
assert clock["with_seconds"]["birth_time"] == "14:45:20"
@@ -70,7 +70,7 @@ def test_dasha_reference_audit_quantifies_pdf_boundary_gap() -> None:
assert 365.0 in year_lengths
assert 365.2422 in year_lengths
assert 365.25 in year_lengths
assert year_lengths[365.25]["start_datetime"].startswith("1986-05-23T22:45:10")
assert year_lengths[365.25]["start_datetime"] == report["engine"]["start_datetime"]
moon_gap = report["target_reference"]["required_moon_delta_arcmin_range"]
assert moon_gap["min"] > 0
@@ -36,7 +36,10 @@ def test_external_engine_adapter_diagnostics_aggregates_three_engines() -> None:
assert "official_raw_response" in contract["expected_oracle_fields"]["VedAstro"]
assert "raw_output_path" in contract["expected_oracle_fields"]["PyJHora/JHora"]
assert contract["engine_states"]["jyotishganit"]["available"] is True
assert contract["engine_states"]["PyJHora/JHora"]["tested"] is False
assert contract["engine_states"]["PyJHora/JHora"]["tested"] is True
pyjhora = contract["partial_verifications"]["PyJHora/JHora"]
assert pyjhora["status"] == "partial_verified"
assert pyjhora["missing_required_outputs"] == ["D2", "D4", "Shadbala", "Ashtakavarga"]
assert contract["replay_manifest"]["tested"] is False
assert contract["replay_manifest"]["blocked_reason"] == "no_same_chart_oracle_rows_imported"
assert report["status"] in {"complete", "partial"}
@@ -1,83 +1,39 @@
#!/usr/bin/env python3
"""Acceptance guard for the final JHora/PDF evidence packet artifacts."""
"""Acceptance guard for the versioned public JHora evidence manifest."""
from __future__ import annotations
import json
import re
from pathlib import Path
import scripts.sync_final_evidence_packet_status as sync_status
ROOT = Path(__file__).resolve().parents[1]
WORK_DIR = ROOT / "scratch" / "local" / "pdf_review_123456"
MANIFEST_PATH = ROOT / "references" / "evidence_manifests" / "jhora_master_evidence_manifest.json"
ERROR_LOG = ROOT / "docs" / "research" / "final_output_acceptance_error_log_2026_07_04.md"
def _latest_packet() -> tuple[int, Path, dict]:
sync_status.main()
packets: list[tuple[int, Path]] = []
for path in WORK_DIR.glob("jhora_master_evidence_packet_public_sample_19550224_1915.v*.json"):
match = re.search(r"\.v(\d+)\.json$", path.name)
if match:
packets.append((int(match.group(1)), path))
assert packets, "no versioned JHora master evidence packets found"
version, path = max(packets)
return version, path, json.loads(path.read_text(encoding="utf-8"))
def _manifest() -> dict:
return json.loads(MANIFEST_PATH.read_text(encoding="utf-8"))
def test_latest_master_packet_has_consistent_final_status_and_version_metadata() -> None:
version, path, packet = _latest_packet()
metadata = packet["metadata"]
def test_versioned_manifest_declares_public_release_boundary() -> None:
manifest = _manifest()
assert version >= 24
assert packet["status"] == "final_output_v1"
assert metadata["status"] == "final_output_v1"
assert metadata["current_version"] == f"v{version}"
assert metadata["packet_version"] == f"v{version}"
assert metadata["canonical_packet"] == path.name
assert packet["structured_v13_final_integrated_report"]["status"] == "final_output_v1"
assert manifest["schema_version"] == 1
assert manifest["artifact_id"] == "jhora_master_evidence"
assert manifest["source_scope"] == "public_release"
assert manifest["release_gate"]["local_scratch_required"] is False
assert manifest["release_gate"]["external_raw_required_for_official_verified"] is True
def test_latest_master_packet_links_all_final_report_artifacts() -> None:
_, _, packet = _latest_packet()
required_sections = {
"structured_v21_raman_full_report_complete": ("source", "compiled-full-report-v1"),
"structured_v22_raman_full_report_pdf_artifact": ("pdf", "pdf-rendered-qa-pass"),
"structured_v23_raman_full_report_raw_data_appendix": ("source", "raw-data-appendix-v1"),
}
for section, (artifact_key, status) in required_sections.items():
payload = packet[section]
assert payload["status"] == status
artifact = ROOT / payload[artifact_key]
assert artifact.exists(), f"missing artifact for {section}: {artifact}"
assert artifact.stat().st_size > 1000, f"artifact too small for {section}: {artifact}"
pdf_payload = packet["structured_v22_raman_full_report_pdf_artifact"]
for rel_path in pdf_payload["qa_rendered_pages"]:
qa_page = WORK_DIR / rel_path
assert qa_page.exists(), f"missing PDF QA render page: {qa_page}"
assert qa_page.stat().st_size > 1000
def test_status_ledger_points_to_latest_packet_and_has_fresh_next_step() -> None:
version, path, _ = _latest_packet()
ledger = (WORK_DIR / "evidence_packet_status_ledger_public_sample_19550224_1915.md").read_text(
encoding="utf-8"
)
assert path.name in ledger
assert f"`{path.name}` | active" in ledger
assert "Raman full report complete" in ledger
assert "Raman full report PDF" in ledger
assert "Raman full report raw data appendix" in ledger
assert "Chapter 04 Parashari Dasha layer - Vimshottari" not in ledger
assert "Acceptance/error-log gate" in ledger
assert f"v{version}" in ledger
def test_manifest_keeps_external_jhora_raw_state_honest() -> None:
evidence = _manifest()["evidence"]
assert evidence["engine"] == "JHora"
assert evidence["raw_status"] in {"not_collected", "partial", "verified"}
assert evidence["raw_status"] != "verified"
def test_acceptance_error_log_records_known_failures_and_prevention_rules() -> None:
text = ERROR_LOG.read_text(encoding="utf-8")
@@ -93,7 +49,7 @@ def test_acceptance_error_log_records_known_failures_and_prevention_rules() -> N
assert phrase in text
def test_sync_script_repairs_latest_packet_metadata_and_ledger(tmp_path, monkeypatch) -> None:
def test_sync_script_repairs_latest_packet_metadata_only_when_explicitly_requested(tmp_path, monkeypatch) -> None:
for version in (2, 10):
packet = {
"status": "final_output_v1",
@@ -115,9 +71,9 @@ def test_sync_script_repairs_latest_packet_metadata_and_ledger(tmp_path, monkeyp
encoding="utf-8",
)
monkeypatch.setattr(sync_status, "WORK_DIR", tmp_path)
monkeypatch.setattr(sync_status, "LOCAL_EVIDENCE_DIR", tmp_path)
assert sync_status.main() == 0
assert sync_status.main(["--sync-local"]) == 0
latest = json.loads(
(tmp_path / "jhora_master_evidence_packet_public_sample_19550224_1915.v10.json").read_text(
encoding="utf-8"
@@ -132,3 +88,9 @@ def test_sync_script_repairs_latest_packet_metadata_and_ledger(tmp_path, monkeyp
assert "jhora_master_evidence_packet_public_sample_19550224_1915.v10.json" in ledger.read_text(
encoding="utf-8"
)
def test_sync_script_succeeds_without_local_scratch(monkeypatch, tmp_path) -> None:
monkeypatch.setattr(sync_status, "LOCAL_EVIDENCE_DIR", tmp_path)
assert sync_status.main([]) == 0
+17 -1
View File
@@ -675,7 +675,7 @@ def test_trust_center_exposes_oracle_evidence_intake_cards() -> None:
"必须打码",
"missing_shadbala_component",
"template_steve_jobs_dasha_lahiri",
"template_steve_jobs_dasha_lahiri",
"template_bv_raman_vimshottari_boundary_series",
"template_synthetic_north_china_shadbala_raman",
"template_extreme_latitude_kp",
"template_historical_epoch_lahiri",
@@ -692,6 +692,22 @@ def test_trust_center_exposes_oracle_evidence_intake_cards() -> None:
]:
assert token in main
intake_block = re.search(
r"const ORACLE_EVIDENCE_INTAKE_TASKS = \[(.*?)\n\];",
main,
re.DOTALL,
)
assert intake_block is not None
intake_case_ids = re.findall(r"caseId: '([^']+)'", intake_block.group(1))
assert intake_case_ids == [
"template_steve_jobs_dasha_lahiri",
"template_synthetic_north_china_shadbala_raman",
"template_extreme_latitude_kp",
"template_historical_epoch_lahiri",
"template_bv_raman_vimshottari_boundary_series",
]
assert len(set(intake_case_ids)) == 5
assert "validateOracleEvidence" in api_bridge
assert "postJson('/api/oracle_evidence'" in api_bridge
assert "'/api/oracle_evidence'" in api_server
+41
View File
@@ -0,0 +1,41 @@
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
CSS = ROOT / "frontend" / "src" / "app" / "globals.css"
def selector_rule(css: str, selector: str) -> str:
start = css.index(f"{selector} {{")
end = css.index("}", start)
return css[start:end]
def test_lightweight_warm_palette_contract() -> None:
css = CSS.read_text(encoding="utf-8")
for token in (
"--color-canvas: #fbfaf7;",
"--color-canvas-soft: #f3f2ee;",
"--color-canvas-muted: #ebe9e3;",
"--color-ink: #1d1d1f;",
"--color-ink-secondary: #676762;",
"--color-ink-tertiary: #8a8983;",
"--color-action: #85432f;",
"--color-action-soft: #f4e8e2;",
"--color-border: #d8d6cf;",
"--color-border-strong: #b8b5ad;",
):
assert token in css
assert "--color-sidebar: rgba(235, 233, 227, .86);" in css
assert "backdrop-filter: saturate(130%) blur(20px);" in css
for selector in (
".sidebar",
".starter-list button:first-child",
".account-summary",
".auth-story",
".admin-table-wrap",
):
assert "var(--color-surface-dark)" not in selector_rule(css, selector)
@@ -0,0 +1,9 @@
from pathlib import Path
def test_high_rigor_workflow_exposes_external_parity_for_plan_and_execution() -> None:
source = (Path(__file__).resolve().parents[1] / "scripts" / "jyotish_api_server.py").read_text(encoding="utf-8")
assert source.count("'high_rigor_external_parity'") >= 2
assert source.count("'external_parity_not_passed'") >= 2
assert "'external_parity_gate': external_parity_gate" in source
@@ -104,20 +104,19 @@ def test_interpretation_source_inventory_gate_classifies_full_candidate_pool() -
classification = report["full_classification"]
assert classification["status"] == "classified"
assert classification["candidate_count"] >= 900
assert classification["unclassified_candidate_count"] == 0
assert classification["priority_bucket_counts"]["priority_1"] >= 50
assert classification["priority_bucket_counts"]["priority_2"] >= 50
assert classification["priority_bucket_counts"]["priority_3"] >= 100
by_path = classification["by_path"]
assert classification["candidate_count"] == len(by_path)
assert classification["classified_candidate_count"] == len(by_path)
assert by_path["references/real_case_studies/vedicka/career-success-poverty-prosperity.md"]["classification"] == "real_case_calibration"
assert by_path["references/open_source_sources/rishi-ai-mcp/.agents/skills/career-analysis/SKILL.md"]["classification"] == "open_source_reference"
assert by_path["references/open_source_sources/vedic-astro-skills/codex/skills/vedic-core/resources/qa_rules.md"]["classification"] == "runtime_reference_layer"
assert by_path["references/advanced-techniques.md"]["classification"] == "reference_candidate"
assert by_path["docs/research/local_drafts/2026-06/antigravity_round31_api_completion_top50_2026_06_26.md"]["classification"] == "quarantined_draft"
assert by_path["docs/research/ACTIVE_FRONTS.md"]["classification"] == "research_governance"
assert by_path["references/open_source_sources/rishi-ai-mcp/.agents/skills/career-analysis/SKILL.md"]["priority"] == "priority_1"
assert by_path["references/real_case_studies/vedicka/career-success-poverty-prosperity.md"]["priority"] == "priority_1"
assert by_path["docs/research/local_drafts/2026-06/antigravity_round31_api_completion_top50_2026_06_26.md"]["promotion_status"] == "not_truth_source"
+3 -3
View File
@@ -185,7 +185,7 @@ class TestSpecialLagnas:
def test_precise_special_lagnas_include_varnada_crosscheck(self):
result = calc_special_lagnas_precise(
4, REDACTED_YEAR, 4, 17, 14, 45, lat=36.466667, lon=114.2, tz_offset=8
4, 1990, 4, 17, 14, 45, lat=36.466667, lon=114.2, tz_offset=8
)
assert result['VL']['sign_idx'] == (4 * 3) % 12
assert 'vl_from_hl' in result['VL']
@@ -208,10 +208,10 @@ class TestSpecialLagnas:
def test_precise_special_lagnas_preserve_fractional_minutes(self):
minute_only = calc_special_lagnas_precise(
4, REDACTED_YEAR, 4, 17, 14, 45, lat=36.466667, lon=114.2, tz_offset=8
4, 1990, 4, 17, 14, 45, lat=36.466667, lon=114.2, tz_offset=8
)
with_seconds = calc_special_lagnas_precise(
4, REDACTED_YEAR, 4, 17, 14, 45 + 20 / 60.0, lat=36.466667, lon=114.2, tz_offset=8
4, 1990, 4, 17, 14, 45 + 20 / 60.0, lat=36.466667, lon=114.2, tz_offset=8
)
assert with_seconds['birth_utc_hours'] > minute_only['birth_utc_hours']
assert with_seconds['ghatis_elapsed_from_sunrise'] > minute_only['ghatis_elapsed_from_sunrise']
+166
View File
@@ -661,3 +661,169 @@ def test_career_narrative_payload_forces_monthly_adjudication_layers_into_final_
assert any("月度主状态" in item for item in payload["strengths"])
assert any("阻力来源" in item for item in payload["risks"])
assert "时间置信度" in payload["markdown"]
def test_career_vedastro_radar_audit_never_lifts_score_or_final_label() -> None:
result = _base_career_result()
result["modules"]["vedastro_range_scan_result"] = {
"backend": "vedastro_service_adapter_candidate",
"status": "ok",
"operation": "range_scan",
"domain": "career",
"evidence_ledger": [
{
"source": "vedastro_service_adapter_candidate",
"operation": "range_scan",
"domain": "career",
"event_id": "CareerExpansionWindow",
"score": 80,
}
],
"adjudicator_policy": {"can_change_score": False, "can_set_dominant_label": False},
}
strict = _collect_strict_evidence("career", result)
radar_rows = [
row
for row in strict["technique_audit"]
if row.get("technique") == "VedAstro EventsAtRange / 596+ Calculator Radar"
]
assert radar_rows
assert radar_rows[0]["status"] == "used"
assert radar_rows[0]["role"] == "external_timing_evidence"
assert radar_rows[0]["effect"] == "activation_context_only_no_score_or_label_lift"
def test_career_vedastro_radar_audit_exposes_candidate_windows_for_report_display() -> None:
result = _base_career_result()
result["modules"]["vedastro_range_scan_result"] = {
"backend": "vedastro_service_adapter_candidate",
"status": "ok",
"operation": "range_scan",
"domain": "career",
"evidence_ledger": [],
"daily_windows": [
{
"date": "2026-08-12",
"domain": "career",
"score": 8,
"confidence": "high",
"event_ids": ["CareerExpansionWindow"],
"signal_families": ["career_trigger"],
"top_signal_label": "Career expansion window",
}
],
"top_daily_window": {
"date": "2026-08-12",
"domain": "career",
"score": 8,
"confidence": "high",
"event_ids": ["CareerExpansionWindow"],
"signal_families": ["career_trigger"],
"top_signal_label": "Career expansion window",
},
"adjudicator_policy": {"can_change_score": False, "can_set_dominant_label": False},
}
strict = _collect_strict_evidence("career", result)
radar_row = next(
row
for row in strict["technique_audit"]
if row.get("technique") == "VedAstro EventsAtRange / 596+ Calculator Radar"
)
assert radar_row["candidate_windows"] == ["2026-08-12"]
assert radar_row["top_window"]["date"] == "2026-08-12"
assert radar_row["local_agreement"] == "pending_local_adjudication"
def test_career_vedastro_radar_local_agreement_agrees_when_local_career_convergence_is_strong() -> None:
result = _base_career_result()
result["modules"]["dasa_convergence"]["domain_activations"]["career_status"] = {
"convergence_level": "L4",
"probability": "70-85%",
}
result["modules"]["vedastro_range_scan_result"] = {
"backend": "vedastro_service_adapter_candidate",
"status": "ok",
"operation": "range_scan",
"domain": "career",
"evidence_ledger": [
{
"source": "vedastro_service_adapter_candidate",
"operation": "range_scan",
"domain": "career",
"event_id": "CareerExpansionWindow",
"score": 80,
}
],
}
strict = _collect_strict_evidence("career", result)
radar_row = next(
row
for row in strict["technique_audit"]
if row.get("technique") == "VedAstro EventsAtRange / 596+ Calculator Radar"
)
assert radar_row["local_agreement"] == "agree"
def test_career_vedastro_radar_local_agreement_conflicts_when_local_career_convergence_is_weak() -> None:
result = _base_career_result()
result["modules"]["dasa_convergence"]["domain_activations"]["career_status"] = {
"convergence_level": "L1",
"probability": "0-20%",
}
result["modules"]["vedastro_range_scan_result"] = {
"backend": "vedastro_service_adapter_candidate",
"status": "ok",
"operation": "range_scan",
"domain": "career",
"evidence_ledger": [
{
"source": "vedastro_service_adapter_candidate",
"operation": "range_scan",
"domain": "career",
"event_id": "CareerExpansionWindow",
"score": 80,
}
],
}
strict = _collect_strict_evidence("career", result)
radar_row = next(
row
for row in strict["technique_audit"]
if row.get("technique") == "VedAstro EventsAtRange / 596+ Calculator Radar"
)
assert radar_row["local_agreement"] == "conflict"
def test_career_strict_workflow_exposes_prashna_context_as_guarded_evidence() -> None:
result = _base_career_result()
result["modules"]["prashna_context"] = {
"scope": "prashna_context",
"status": "ok",
"supporting_indicators": {
"gulika": {"status": "partial"},
"sphuta": {"status": "ok", "trisphuta": {"longitude": 123.4}},
},
}
strict = _collect_strict_evidence("career", result)
prashna = strict["present_evidence"]["prashna_context"]
rows = [row for row in strict["technique_audit"] if row.get("technique") == "Prashna Context"]
risk_rows = [row for row in strict["technique_audit"] if row.get("technique") == "Gulika/Maandi"]
assert prashna["status"] == "ok"
assert rows
assert rows[0]["status"] == "guarded"
assert rows[0]["role"] == "question_moment_evidence"
assert rows[0]["effect"] == "context_only_no_score_or_final_verdict"
assert risk_rows
assert risk_rows[0]["status"] == "partial"
assert risk_rows[0]["role"] == "risk_supporting_indicator"
assert risk_rows[0]["effect"] == "risk_context_only_no_final_verdict"
@@ -0,0 +1,109 @@
#!/usr/bin/env python3
"""Guardrails for Prashna question-moment evidence in strict reports."""
from __future__ import annotations
from copy import deepcopy
import mcp_server
def _strict_report() -> dict:
return {
"question_type": "career",
"present_evidence": {},
"event_judgement": {
"score": 72,
"verdict": "supportive_window",
"dominant_label": "career_status",
"primary_drivers": ["dasha_support"],
},
"score": 72,
"verdict": "supportive_window",
"dominant_label": "career_status",
"confidence_cap": "medium",
"technique_audit": [],
"technique_audit_summary": {},
}
def _judgement(strict: dict) -> dict:
event = strict["event_judgement"]
return {
"score": strict["score"],
"verdict": strict["verdict"],
"dominant_label": strict["dominant_label"],
"confidence_cap": strict["confidence_cap"],
"event_score": event["score"],
"event_verdict": event["verdict"],
"event_label": event["dominant_label"],
"primary_drivers": deepcopy(event["primary_drivers"]),
}
def test_prashna_request_adds_guarded_evidence_without_adjudication_effect(monkeypatch) -> None:
monkeypatch.setattr(
"scripts.prashna_context.build_prashna_context",
lambda payload: {
"scope": "prashna_context",
"status": "computed",
"chart_source": "swiss_ephemeris_backend",
"result_hash": "prashna-hash",
"blocked_layers": ["Prashna verdict"],
},
)
strict = _strict_report()
before = _judgement(strict)
result = mcp_server._attach_prashna_guarded_evidence(
"career",
strict,
question="Will this project succeed?",
prashna_request={
"question_timestamp": "2026-07-16T12:00:00+08:00",
"lat": 31.2304,
"lon": 121.4737,
"timezone": 8,
},
)
assert _judgement(result) == before
assert result["present_evidence"]["prashna_context"]["result_hash"] == "prashna-hash"
integration = result["present_evidence"]["prashna_integration"]
assert integration["status"] == "guarded_evidence"
assert integration["adjudication_effect"] == "none"
row = next(item for item in result["technique_audit"] if item["technique"] == "Prashna Integration")
assert row["effect_on_score"] == "none"
def test_prashna_request_rejects_client_chart_injection() -> None:
result = mcp_server._attach_prashna_guarded_evidence(
"career",
_strict_report(),
question="Will this project succeed?",
prashna_request={
"question_timestamp": "2026-07-16T12:00:00+08:00",
"lat": 31.2304,
"lon": 121.4737,
"timezone": 8,
"planets": {"Sun": 0},
},
)
integration = result["present_evidence"]["prashna_integration"]
assert integration["status"] == "blocked"
assert integration["reason"] == "client_supplied_prashna_chart_forbidden:planets"
assert "prashna_context" not in result["present_evidence"]
def test_prashna_request_requires_question_moment_location() -> None:
result = mcp_server._attach_prashna_guarded_evidence(
"career",
_strict_report(),
question="Will this project succeed?",
prashna_request={"question_timestamp": "2026-07-16T12:00:00+08:00"},
)
integration = result["present_evidence"]["prashna_integration"]
assert integration["status"] == "blocked"
assert integration["reason"] == "missing_prashna_fields:lat,lon,timezone"
+10
View File
@@ -0,0 +1,10 @@
from __future__ import annotations
from scripts.muntha import calc_muntha_from_sun_sign
def test_standalone_muntha_module_imports_and_calculates() -> None:
result = calc_muntha_from_sun_sign(0, 12)
assert result["muntha_sign"] == 11
assert result["muntha_lord"] == "Jupiter"
+23
View File
@@ -0,0 +1,23 @@
from __future__ import annotations
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_prashna_registry_keeps_verdict_guarded_and_integration_guarded() -> None:
registry = json.loads((ROOT / "references/technique_registry.json").read_text(encoding="utf-8"))
prashna = registry["techniques"]["prashna"]
integration = registry["techniques"]["prashna_integration"]
assert prashna["status"] == "guarded"
assert prashna["verification_level"]["calculation"] == "verified"
assert prashna["verification_level"]["rule"] == "verified"
assert prashna["verification_level"]["prediction"] == "support_only"
assert "cannot set final verdict" in prashna["conclusion_policy"]
assert integration["status"] == "guarded"
assert integration["verification_level"]["calculation"] == "partial"
assert integration["verification_level"]["rule"] == "partial"
assert "guarded" in integration["conclusion_policy"].lower()
+1
View File
@@ -27,6 +27,7 @@ def test_pre_work_check_runs_governance_test_set() -> None:
def test_pre_work_check_requires_error_ledger_and_fragment_sweeps() -> None:
assert "docs/research/pre_work_error_ledger.md" in PRE_WORK_DOCS
assert "docs/research/whole_machine_fragment_sweep_2026_07_05.md" in PRE_WORK_DOCS
assert "docs/research/whole_machine_fragment_sweep_2026_07_14.md" in PRE_WORK_DOCS
assert "docs/research/whole_machine_fragment_sweep_round25_2026_06_25.md" in PRE_WORK_DOCS
+3 -2
View File
@@ -51,13 +51,14 @@ def test_preflight_fragment_scan_reports_authority_layers_and_risk_buckets(repor
assert layers["distribution_mirror"]["status"] == "mirror_do_not_reverse_sync"
findings = report["findings"]
assert findings["high_value_unpromoted_count"] >= 1
assert findings["high_value_unpromoted_count"] == len(report["high_value_unpromoted"])
assert findings["redundant_or_mirror_count"] >= 1
assert findings["workspace_residue_count"] >= 0
assert findings["real_capability_risk_count"] >= 1
categories = {item["category"] for item in report["high_value_unpromoted"]}
assert "repo_local_draft" in categories or "external_work_brain" in categories
if categories:
assert "repo_local_draft" in categories or "external_work_brain" in categories
mirror_paths = [item["path"] for item in report["redundant_or_mirror"]]
assert any(".workbuddy/skills/jyotish-vedic-astrology" in path for path in mirror_paths)
+13
View File
@@ -29,3 +29,16 @@ def test_public_release_privacy_scan_supports_unpacked_zip_without_git(tmp_path:
assert [path.name for path in iter_release_files(tmp_path)] == ["INSTALL.md"]
report = build_report(tmp_path)
assert report["status"] == "pass", report["findings"]
def test_public_release_privacy_scan_rejects_executable_redaction_placeholder(tmp_path: Path) -> None:
(tmp_path / "unsafe.py").write_text("year = REDACTED_YEAR\n", encoding="utf-8")
report = build_report(tmp_path)
assert report["status"] == "fail"
assert report["findings"][0]["rule_id"] == "executable_redaction_placeholder"
def test_private_workspace_directories_are_gitignored() -> None:
gitignore = (Path(__file__).resolve().parents[1] / ".gitignore").read_text(encoding="utf-8").splitlines()
assert "/scratch/" in gitignore
assert "/.serena/" in gitignore
+57
View File
@@ -0,0 +1,57 @@
import subprocess
import sys
from datetime import datetime, timezone
from pathlib import Path
from benchmarks.jyotish.scripts.run_pyjhora_compare import write_report
from benchmarks.jyotish.scripts.run_pyjhora_compare import compare_one
ROOT = Path(__file__).resolve().parents[1]
RUNNER = ROOT / "benchmarks" / "jyotish" / "scripts" / "run_pyjhora_compare.py"
def test_pyjhora_compare_help_is_non_executing():
result = subprocess.run(
[sys.executable, str(RUNNER), "--help"], cwd=ROOT, capture_output=True, text=True, timeout=15
)
assert result.returncode == 0
assert "--build-local" in result.stdout
assert "--refresh-local" in result.stdout
assert "--output-prefix" in result.stdout
assert "FileNotFoundError" not in result.stderr
def test_pyjhora_report_uses_supplied_utc_generation_timestamp():
report = write_report(
[],
[],
generated_at=datetime(2026, 7, 15, 4, 30, tzinfo=timezone.utc),
)
assert "生成时间:2026-07-15T04:30:00+00:00" in report
assert "生成时间:2026-06-03" not in report
def test_pyjhora_comparison_includes_d2_d4_bav_sav_and_shadbala_rows():
bodies = ["Ascendant", "Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn", "Rahu", "Ketu"]
chart = {body: {"sign": "Aries", "degree_in_sign": 1.0} for body in bodies}
planet = {body: {"sign": "Aries", "degree_in_sign": 1.0, "nakshatra": "Ashwini", "nakshatra_pada": 1} for body in bodies[1:]}
local = {
"ascendant": chart["Ascendant"], "planets": planet,
"varga": {"D2": chart, "D4": chart, "D9": chart, "D10": chart},
"dasha": {},
"ashtakavarga": {"bav": {name: [1] * 12 for name in ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn", "Lagna"]}, "sav": [7] * 12},
"shadbala": {name: 100.0 for name in ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"]},
}
pyjhora = {
"ascendant": chart["Ascendant"], "planets": planet,
"varga": {"D2": chart, "D4": chart, "D9": chart, "D10": chart},
"dasha": {},
"ashtakavarga": local["ashtakavarga"], "shadbala": local["shadbala"],
}
sections = {row["section"] for row in compare_one("fixture", local, pyjhora)}
assert {"D2", "D4", "Ashtakavarga_BAV", "Ashtakavarga_SAV", "Shadbala"} <= sections
+17
View File
@@ -0,0 +1,17 @@
from pathlib import Path
from scripts.pyjhora_parity_summary import summarize_matrix
def test_summary_marks_partial_verified_when_only_d1_d9_d10_dasha_are_covered(tmp_path: Path):
matrix = tmp_path / "matrix.csv"
matrix.write_text(
"section,status\nascendant,match\nD9,match\nD10,match\ndasha,match\n",
encoding="utf-8",
)
result = summarize_matrix(matrix, settings={"ayanamsa": "lahiri", "node_mode": "mean"})
assert result["status"] == "partial_verified"
assert result["full_parity_verified"] is False
assert result["missing_required_outputs"] == ["D2", "D4", "Shadbala", "Ashtakavarga"]
+14
View File
@@ -15,3 +15,17 @@ def test_railway_services_use_the_product_frontend_and_dynamic_ports() -> None:
assert "COPY SKILL.md mcp_server.py" in api
assert "--host 0.0.0.0" in api and "${PORT:-5200}" in api
assert "http.server" not in api
def test_web_image_copies_postcss_config_before_building_frontend() -> None:
web = (ROOT / "deploy" / "railway-web.Dockerfile").read_text(encoding="utf-8")
config_copy = "COPY frontend/next.config.ts frontend/postcss.config.mjs frontend/tsconfig.json ./"
assert config_copy in web
assert web.index(config_copy) < web.index("RUN npm run build")
def test_server_compose_allows_only_the_internal_api_hostname() -> None:
compose = (ROOT / "deploy" / "docker-compose.server.yml").read_text(encoding="utf-8")
assert "JYOTISH_ALLOWED_HOSTS: localhost,127.0.0.1,::1,api" in compose
+174 -7
View File
@@ -9,13 +9,50 @@ from scripts.unified_consultation_orchestrator import UnifiedConsultationOrchest
ROOT = Path(__file__).resolve().parents[1]
def test_real_case_replay_manifest_blocks_when_no_cases_are_imported() -> None:
def test_real_case_replay_manifest_contains_ten_research_grade_cases() -> None:
result = validate_manifest(ROOT / "references/real_case_calibration/replay_manifest.json")
assert result["status"] == "blocked"
assert result["case_count"] == 0
assert result["replay_ready_count"] == 0
assert result["blocked_reason"] == "no_structured_outcome_replay_cases_imported"
assert result["status"] == "pass"
assert result["case_count"] == 10
assert result["replay_ready_count"] == 10
assert result["domain_counts"] == {"career": 5, "marriage": 5}
assert result["birth_time_ratings"] == {"A": 2, "AA": 8}
def test_holdout_manifest_contains_ten_new_balanced_cases() -> None:
batch1_path = ROOT / "references/real_case_calibration/replay_manifest.json"
holdout_path = ROOT / "references/real_case_calibration/replay_manifest_holdout_v2.json"
result = validate_manifest(holdout_path)
assert result["status"] == "pass"
assert result["case_count"] == 10
assert result["domain_counts"] == {"career": 5, "marriage": 5}
assert result["birth_time_ratings"] == {"A": 5, "AA": 5}
batch1 = json.loads(batch1_path.read_text(encoding="utf-8"))
holdout = json.loads(holdout_path.read_text(encoding="utf-8"))
assert {case["subject"]["name"] for case in batch1["cases"]}.isdisjoint(
{case["subject"]["name"] for case in holdout["cases"]}
)
def test_three_case_probe_is_aa_and_disjoint_from_prior_twenty() -> None:
probe_path = ROOT / "references/real_case_calibration/replay_manifest_probe3_v2.json"
result = validate_manifest(probe_path)
assert result["status"] == "pass"
assert result["case_count"] == 3
assert result["replay_ready_count"] == 3
assert result["domain_counts"] == {"career": 2, "marriage": 1}
assert result["birth_time_ratings"] == {"AA": 3}
prior_names = set()
for path in (
ROOT / "references/real_case_calibration/replay_manifest.json",
ROOT / "references/real_case_calibration/replay_manifest_holdout_v2.json",
):
payload = json.loads(path.read_text(encoding="utf-8"))
prior_names.update(case["subject"]["name"] for case in payload["cases"])
probe = json.loads(probe_path.read_text(encoding="utf-8"))
assert prior_names.isdisjoint(case["subject"]["name"] for case in probe["cases"])
def test_real_case_replay_validator_accepts_one_structured_case(tmp_path: Path) -> None:
@@ -26,6 +63,24 @@ def test_real_case_replay_validator_accepts_one_structured_case(tmp_path: Path)
"cases": [
{
"case_id": "public_case_001",
"subject": {
"name": "Public Case",
"year": 1970,
"month": 1,
"day": 1,
"hour": 12,
"minute": 0,
"lat": 0.0,
"lon": 0.0,
"tz": 0.0,
"node_mode": "mean",
"birth_source": {
"url": "https://example.com/birth-record",
"source_grade": "primary",
"time_accuracy_rating": "AA",
"evidence_basis": "birth_record_in_hand",
},
},
"source": {
"url": "https://example.com/public-case",
"source_grade": "verified_secondary",
@@ -36,7 +91,13 @@ def test_real_case_replay_validator_accepts_one_structured_case(tmp_path: Path)
{
"event_type": "career_breakthrough",
"event_date": "2000-01",
"domain": "career",
"expected_label": "career_status",
"outcome": "public_success",
"source": {
"url": "https://example.com/event",
"source_grade": "verified_secondary",
},
}
],
"similarity": {
@@ -61,6 +122,62 @@ def test_real_case_replay_validator_accepts_one_structured_case(tmp_path: Path)
assert result["replay_ready_count"] == 1
def test_real_case_replay_validator_rejects_low_accuracy_birth_time_and_unsourced_event(tmp_path: Path) -> None:
manifest = {
"schema_version": "2.0",
"status": "ready",
"case_schema": "references/real_case_calibration/catalog.schema.json",
"cases": [
{
"case_id": "weak_case",
"subject": {
"name": "Weak Case",
"year": 1970,
"month": 1,
"day": 1,
"hour": 12,
"minute": 0,
"lat": 0.0,
"lon": 0.0,
"tz": 0.0,
"node_mode": "mean",
"birth_source": {
"url": "https://example.com/birth",
"source_grade": "unverified",
"time_accuracy_rating": "DD",
"evidence_basis": "conflicting_times",
},
},
"source": {
"url": "https://example.com/case",
"source_grade": "unverified",
"license_or_quote_boundary": "summary_only",
},
"chart_signature": {},
"event_outcomes": [
{
"event_type": "legal_marriage",
"event_date": "2000-01-01",
"domain": "marriage",
"expected_label": "legal_marriage",
"outcome": "married",
}
],
"similarity": {"score": 0.0, "matching_factors": [], "dissimilar_factors": []},
"replay": {"outcome_replay_status": "replayed", "do_not_use_for_prediction": False},
}
],
}
path = tmp_path / "replay_manifest.json"
path.write_text(json.dumps(manifest), encoding="utf-8")
result = validate_manifest(path)
assert result["status"] == "invalid"
assert {error["error"] for error in result["errors"]} >= {
"birth_time_rating_below_A",
"missing",
}
def test_orchestrator_exposes_real_case_replay_manifest_status() -> None:
orchestrator = UnifiedConsultationOrchestrator()
route = {"question_type": "career", "primary_theme": "career"}
@@ -68,6 +185,56 @@ def test_orchestrator_exposes_real_case_replay_manifest_status() -> None:
packet = orchestrator.real_case_calibration_catalog(route_packet=route, machine_evidence_packet={})
replay = packet["outcome_replay_manifest"]
assert replay["status"] == "blocked"
assert replay["case_count"] == 0
assert replay["status"] == "pass"
assert replay["case_count"] == 10
holdout = packet["holdout_replay_manifest"]
assert holdout["status"] == "pass"
assert holdout["case_count"] == 10
benchmark = packet["public_outcome_benchmark"]
assert benchmark["status"] == "used"
assert benchmark["summary"]["total_events"] == 20
assert benchmark["summary"]["positive_event_recall"] == 0.8
assert benchmark["summary"]["exact_label_rate"] == 0.4
assert benchmark["summary"]["balanced_accuracy"] is None
assert benchmark["holdout_promotion"] == {"promote": True, "reason": "holdout_metrics_improved"}
supplemental = packet["supplemental_public_probe"]
assert supplemental["status"] == "used"
assert supplemental["summary"]["total_events"] == 3
assert supplemental["summary"]["positive_event_recall"] == 1 / 3
assert supplemental["combined_observation"]["total_events"] == 23
assert supplemental["combined_observation"]["positive_event_recall"] == 17 / 23
corrected = packet["corrected_v21_observation"]
assert corrected["status"] == "used"
assert corrected["summary"]["total_events"] == 23
assert corrected["summary"]["positive_event_recall_deprecated"] is True
assert corrected["ashtakavarga_audit_status"] == "used_non_scoring"
negative = packet["negative_control_pilot"]
assert negative["status"] == "used"
assert negative["summary"]["control_date_count"] == 24
assert negative["summary"]["positive_top_1_rate"] == 0.0
assert negative["summary"]["positive_top_3_rate"] == 0.0
annual = packet["annual_control_pilot"]
assert annual["status"] == "used"
assert annual["summary"]["control_date_count"] == 12
assert annual["summary"]["positive_top_1_rate"] == 1 / 3
timing_gate = packet["timing_precision_gate"]
assert timing_gate["status"] == "blocked"
assert timing_gate["maximum_supported_precision"] == "unvalidated_broad_window"
assert timing_gate["blocked_claims"] == ["exact_day", "exact_month_from_current_replay_score"]
assert timing_gate["domain_support"] == {"career": "blocked", "marriage": "partial_candidate"}
runtime_log = orchestrator.runtime_evidence_log(
surface="api_web",
entry_mode="direct_chart",
route_packet=route,
executed_steps=["compute_chart"],
skipped_steps=[],
real_case_calibration=packet,
)
assert "timing_precision_gate_blocked" in runtime_log["quality_gate"]["blocked_items"]
timing_row = next(
row for row in runtime_log["quality_gate"]["technique_audit_table"]
if row["technique"] == "Timing Precision Gate"
)
assert timing_row["status"] == "blocked"
assert timing_row["maximum_supported_precision"] == "unvalidated_broad_window"
assert packet["required_replay_schema"] == "references/real_case_calibration/catalog.schema.json"
+10
View File
@@ -0,0 +1,10 @@
from pathlib import Path
def test_release_profile_requires_privacy_and_renderer_probes() -> None:
source = (Path(__file__).resolve().parents[1] / "scripts" / "run_quality_gate.py").read_text(encoding="utf-8")
assert '"scripts/public_release_privacy_scan.py", "--json"' in source
assert '"scripts/report_renderer_isolation_poc.py", "--strict"' in source
assert '"scripts/three_engine_parity_replay_validator.py"' in source
assert '"--require-external-parity"' in source
assert 'parity_command.append("--require-pass")' in source
@@ -0,0 +1,38 @@
from __future__ import annotations
import json
from pathlib import Path
from scripts.audit_capabilities import ALLOWED_STATUS
ROOT = Path(__file__).resolve().parents[1]
REGISTRY = ROOT / "references" / "technique_registry.json"
def test_restricted_techniques_keep_canonical_status_boundaries() -> None:
techniques = json.loads(REGISTRY.read_text(encoding="utf-8"))["techniques"]
assert techniques["prashna"]["status"] == "guarded"
assert techniques["prashna_integration"]["status"] == "guarded"
assert techniques["upagraha_gulika_maandi"]["status"] == "guarded"
assert techniques["panchavargiya_bala"]["status"] == "guarded"
assert techniques["rangacharya_jaimini_variant"]["status"] == "comparison-only"
for key in ("prashna", "prashna_integration", "upagraha_gulika_maandi", "panchavargiya_bala"):
assert techniques[key]["verification_level"]["prediction"] == "support_only"
assert techniques["rangacharya_jaimini_variant"]["verification_level"]["prediction"] == "blocked"
def test_restricted_statuses_are_accepted_by_capability_audit() -> None:
techniques = json.loads(REGISTRY.read_text(encoding="utf-8"))["techniques"]
restricted_statuses = {
techniques["prashna"]["status"],
techniques["prashna_integration"]["status"],
techniques["upagraha_gulika_maandi"]["status"],
techniques["panchavargiya_bala"]["status"],
techniques["rangacharya_jaimini_variant"]["status"],
}
assert restricted_statuses <= ALLOWED_STATUS
+14
View File
@@ -43,3 +43,17 @@ def test_mcp_docstring_marks_workbuddy_as_distribution_mirror_not_runtime_source
assert "/.workbuddy/skills/jyotish-vedic-astrology/mcp_server.py" not in text
assert "distribution mirror" in text
assert "reference only" in text
def test_engine_does_not_import_mcp_server_for_strict_evidence() -> None:
text = (ROOT / "scripts" / "jyotish_engine.py").read_text(encoding="utf-8", errors="ignore")
assert "from mcp_server import" not in text
assert "mcp_server.py" not in text
assert "strict_evidence_service" in text
def test_mcp_server_does_not_instantiate_api_handler_directly() -> None:
text = (ROOT / "mcp_server.py").read_text(encoding="utf-8", errors="ignore")
assert "from jyotish_api_server import" not in text
assert "JyotishAPIHandler" not in text
assert "consultation_workflow_service" in text
+9 -6
View File
@@ -36,13 +36,15 @@ def test_shadbala_oracle_closure_status_identifies_first_absolute_value_packet()
report = json.loads(completed.stdout)
assert report["scope"] == "shadbala_external_absolute_value_closure_status"
assert report["schema_version"] == 1
assert report["summary"]["shadbala_task_count"] == 4
assert report["summary"]["external_verified_shadbala_tasks"] == 4
assert report["summary"]["can_claim_shadbala_absolute_closure"] is True
assert report["summary"]["shadbala_task_count"] == 2
assert report["summary"]["external_verified_shadbala_tasks"] == 2
assert report["summary"]["external_packet_fields_complete"] is True
assert report["summary"]["same_chart_parity_status"] == "blocked"
assert report["summary"]["can_claim_shadbala_absolute_closure"] is False
assert report["summary"]["required_planets"] == ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"]
assert report["summary"]["required_components"] == ["sthana", "dig", "kala", "chesta", "naisargika", "drik", "total_rupa"]
assert report["first_priority"] is None
assert report["next_actions"][0] == "Shadbala external absolute-value closure is complete for the current target set."
assert report["next_actions"][0] == "Reconcile Shadbala component-level formulas against PyJHora/JHora same-chart raw values."
def test_shadbala_oracle_closure_status_markdown_can_be_written(tmp_path: Path) -> None:
@@ -53,5 +55,6 @@ def test_shadbala_oracle_closure_status_markdown_can_be_written(tmp_path: Path)
assert output.exists()
markdown = output.read_text(encoding="utf-8")
assert "# Shadbala External Absolute-Value Closure Status" in markdown
assert "can_claim_shadbala_absolute_closure: `true`" in markdown
assert "closure is complete for the current target set" in markdown
assert "same_chart_parity_status: `blocked`" in markdown
assert "can_claim_shadbala_absolute_closure: `false`" in markdown
assert "same-chart parity is still blocked" in markdown
+1 -1
View File
@@ -26,7 +26,7 @@ def test_skill_release_manifest_defines_basic_and_premium_boundaries() -> None:
def test_skill_release_manifest_contains_no_private_birth_data() -> None:
text = json.dumps(build_report(), ensure_ascii=False)
private_date = "-".join(["REDACTED_YEAR", "04", "17"])
private_date = "-".join(["1990", "04", "17"])
private_time = "14" + "" + "49"
private_place = "第四" + "人民医院"
for forbidden in (private_date, private_time, private_place):
+37 -3
View File
@@ -16,6 +16,13 @@ COORDS_MIGRATION = (
/ "migrations"
/ "20260715050000_profile_coordinates.sql"
)
CONSULTATION_MIGRATION = (
Path(__file__).resolve().parents[1]
/ "frontend"
/ "supabase"
/ "migrations"
/ "20260717000000_consultation_request_lifecycle.sql"
)
PAGE = Path(__file__).resolve().parents[1] / "frontend" / "src" / "app" / "page.tsx"
@@ -74,15 +81,42 @@ def test_chat_page_uses_authenticated_cloud_persistence() -> None:
assert '.upsert(' not in source
assert '.update(values)' in source
assert '.insert({' in source
assert source.index('await persistSession(userSession)') < source.index('setOnboardingJustCompleted(false)')
assert source.index('await persistSession(userSession)') < source.index('updateSession(sessionId, () => userSession)')
assert 'function completedOnboardingTranscript(profile: Profile): Message[]' in source
assert 'await persistSession(userSession)' not in source
assert source.index('updateSession(sessionId, () => userSession)') < source.index('await persistSession(completedSession)')
assert 'function completedOnboardingTranscript(profile: Profile, greeting: string): Message[]' in source
assert 'messages: [...preservedMessages, { role: "user", text: question }]' in source
assert 'await persistSession(completedSession)' in source
assert 'const stoppedRequestAwaitingSettlement = useRef<string | null>(null)' in source
assert 'const stoppedSessionPersistence = useRef(new Map<string, Promise<void>>())' in source
assert 'if (ownsInterface && !partialReply)' in source
assert 'await persistSession(interruptedSession)' in source
assert 'await persistence' in source
assert 'disabled={Boolean(pendingSessionId) || cancellationPending}' in source
assert "localStorage" not in source
assert "ayanam-profile" not in source
assert "ayanam-sessions" not in source
def test_consultation_credit_lifecycle_is_idempotent_and_server_only() -> None:
sql = re.sub(r"\s+", " ", CONSULTATION_MIGRATION.read_text(encoding="utf-8").lower()).strip()
assert "create table if not exists public.consultation_requests" in sql
assert "primary key (user_id, request_id)" in sql
assert "status in ('reserved', 'completed', 'cancelled')" in sql
for function_name in (
"begin_consultation_credit",
"complete_consultation_credit",
"cancel_consultation_credit",
):
assert f"create or replace function public.{function_name}" in sql
assert f"grant execute on function public.{function_name}(uuid, text) to service_role" in sql
assert f"revoke all on function public.{function_name}(uuid, text) from public, anon, authenticated" in sql
assert "pg_advisory_xact_lock" in sql
assert "if v_status = 'completed'" in sql
assert "'request_completed'::text" in sql
assert "if v_status = 'cancelled'" in sql
def test_profile_coordinates_are_persisted_with_database_bounds() -> None:
sql = re.sub(r"\s+", " ", COORDS_MIGRATION.read_text(encoding="utf-8").lower()).strip()
source = PAGE.read_text(encoding="utf-8")
+38 -21
View File
@@ -122,70 +122,70 @@ class TestTajikaStrengthLayers:
result = calc_tajika_strength_layers(planet_lons, asc_lon=15.0, year_lord='Jupiter')
assert result['status'] == 'partial'
assert result['method'] == 'Tajika Harsha/Panchavargiya Bala'
assert result['available_planets'] == 7
assert 'harsha_bala' in result
assert 'panchavargiya_bala' in result
assert 'combined_strength' in result
assert result['summary']['strongest_planets']
assert result['summary']['weakest_planets']
assert 'Panchavargiya Bala' in result['blocked_layers']
assert result['usable_layers'] == ['Harsha Bala']
assert result['summary']['next_action']
for planet in ('Sun', 'Moon', 'Mars', 'Mercury', 'Jupiter', 'Venus', 'Saturn'):
assert planet in result['harsha_bala']
assert result['harsha_bala'][planet]['status'] == 'usable'
assert planet in result['panchavargiya_bala']
assert {'score', 'max_score', 'grade', 'components'} <= set(result['combined_strength'][planet])
assert result['panchavargiya_bala'][planet]['status'] == 'blocked'
assert result['combined_strength'][planet]['status'] == 'blocked'
assert result['combined_strength'][planet]['max_score'] > 0
# ── Tajika Yogas Tests ─────────────────────────────────────────────
class TestTajikaYogas:
def test_ithasala_detected(self):
def test_legacy_adapter_blocks_without_speeds(self):
# Moon(15.0) and Mercury(14.5) in same sign, close degrees
planet_lons = {'Moon': 15.0, 'Mercury': 14.5, 'Sun': 45.0,
'Mars': 90.0, 'Jupiter': 180.0, 'Venus': 210.0, 'Saturn': 300.0}
result = calc_tajika_yogas(planet_lons)
assert result['status'] == 'blocked'
assert result['ithasala'] == []
assert len(result['ithasala']) >= 0 # May or may not detect based on rules
def test_graha_yuddha_detected(self):
def test_graha_yuddha_is_not_inferred_by_legacy_adapter(self):
# Mercury and Venus very close
planet_lons = {'Sun': 45.0, 'Moon': 120.0, 'Mars': 90.0,
'Mercury': 100.0, 'Venus': 100.5, 'Jupiter': 180.0, 'Saturn': 300.0}
result = calc_tajika_yogas(planet_lons)
assert len(result['graha_yuddha']) >= 1
assert result['graha_yuddha'] == []
def test_nakta_yoga_sun_moon_same_sign(self):
def test_nakta_is_not_inferred_from_sun_moon_co_sign(self):
planet_lons = {'Sun': 15.0, 'Moon': 18.0, 'Mars': 90.0,
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0, 'Saturn': 300.0}
result = calc_tajika_yogas(planet_lons)
assert result['nakta'] is not None
assert result['nakta'] == []
def test_summary_present(self):
planet_lons = {'Sun': 45.0, 'Moon': 120.0, 'Mars': 90.0,
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0, 'Saturn': 300.0}
result = calc_tajika_yogas(planet_lons)
assert 'summary' in result
assert 'Tajika' in result['summary']
assert 'Blocked' in result['summary']
class TestDetectTajikaYogas:
def test_10_yoga_types_detected(self):
def test_legacy_detector_is_not_a_golden_case_oracle(self):
# Use close-degree planets to force Ithasala detection
planets = {'Sun': 14.0, 'Moon': 15.0, 'Mars': 90.0,
'Mercury': 14.8, 'Jupiter': 180.0, 'Venus': 210.0, 'Saturn': 300.0}
yogas = detect_tajika_yogas(planets)
types = set(y['type'] for y in yogas)
# At least Itasala or other types should be detected
assert len(yogas) >= 0 # May be 0 if no valid pair, that's OK
assert isinstance(yogas, list)
def test_itasala_type_present(self):
def test_legacy_detector_does_not_prove_itasala(self):
# Moon(15) fast, Sun(14) slow → same sign, close
planets = {'Sun': 14.0, 'Moon': 15.0, 'Mars': 90.0,
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0, 'Saturn': 300.0}
yogas = detect_tajika_yogas(planets)
types = set(y['type'] for y in yogas)
assert 'Itasala' in types or len(yogas) >= 0
assert isinstance(types, set)
def test_kuta_yoga_three_planets_same_sign(self):
planets = {'Sun': 5.0, 'Moon': 8.0, 'Mars': 12.0,
@@ -216,6 +216,10 @@ class TestVedhaDetection:
# ── Sahams Tests ────────────────────────────────────────────────────
class TestSahams:
def test_sahams_block_without_location_context(self):
result = calc_all_sahams({'Sun': 45.0, 'Moon': 120.0}, 10.0, datetime(1990, 6, 15, 12, 0))
assert result['status'] == 'blocked'
def test_tajika_module_exposes_saham_rules_reference_path(self):
assert SAHAM_RULES_PATH.endswith('references/saham_rules.json')
assert os.path.exists(SAHAM_RULES_PATH)
@@ -226,7 +230,7 @@ class TestSahams:
'Saturn': 300.0, 'Rahu': 150.0, 'Ketu': 330.0}
asc_lon = 10.0
birth_dt = datetime(1990, 6, 15, 10, 30)
result = calc_all_sahams(planet_lons, asc_lon, birth_dt)
result = calc_all_sahams(planet_lons, asc_lon, birth_dt, lat=39.9042, lon=116.4074, tz=8)
assert 'punya_saham' in result
assert 'karya_saham' in result
assert 'vivah_saham' in result
@@ -247,7 +251,7 @@ class TestSahams:
planet_lons = {'Sun': sun, 'Moon': moon, 'Mars': 90.0,
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0,
'Saturn': 300.0, 'Rahu': 150.0, 'Ketu': 330.0}
result = calc_all_sahams(planet_lons, asc, datetime(1990, 6, 15, 12, 0))
result = calc_all_sahams(planet_lons, asc, datetime(1990, 6, 15, 12, 0), lat=39.9042, lon=116.4074, tz=8)
assert abs(result['punya_saham']['longitude'] - expected) < 0.01
def test_karma_saham_uses_reference_json_day_formula(self):
@@ -257,9 +261,22 @@ class TestSahams:
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0,
'Saturn': 300.0, 'Rahu': 150.0, 'Ketu': 330.0}
expected = (asc + (90.0 - 60.0)) % 360
result = calc_all_sahams(planet_lons, asc, datetime(1990, 6, 15, 12, 0))
result = calc_all_sahams(planet_lons, asc, datetime(1990, 6, 15, 12, 0), lat=39.9042, lon=116.4074, tz=8)
assert abs(result['karma_saham']['longitude'] - expected) < 0.01
def test_formula_saham_applies_reference_add_30_exception(self):
from tajika import _calc_formula_saham
# Asc 50 is outside the forward 100 -> 200 zodiacal arc.
result = _calc_formula_saham(
'Punya_Saham',
{'Sun': 200.0, 'Moon': 100.0},
50.0,
True,
{},
)
assert result == 340.0
def test_is_faster_moon_vs_sun(self):
assert _is_faster('Moon', 'Sun')
assert _is_faster('Mercury', 'Jupiter')
@@ -1,6 +1,10 @@
from __future__ import annotations
import hashlib
import json
import subprocess
import sys
from pathlib import Path
from pathlib import Path
from scripts.three_engine_parity_replay_validator import validate_manifest
@@ -8,22 +12,30 @@ from scripts.three_engine_parity_replay_validator import validate_manifest
ROOT = Path(__file__).resolve().parents[1]
def test_three_engine_parity_manifest_blocks_without_oracle_rows() -> None:
def test_three_engine_parity_manifest_passes_d1_with_vedastro_and_pyjhora_raw() -> None:
result = validate_manifest(ROOT / "references/oracle/three_engine_parity_replay_manifest.json")
assert result["status"] == "blocked"
assert result["comparison_row_count"] == 0
assert result["tested"] is False
assert result["blocked_reason"] == "no_same_chart_oracle_rows_imported"
assert result["status"] == "pass"
assert result["comparison_row_count"] == 15
assert result["match_count"] == 14
assert result["tested"] is True
assert result["blocked_reason"] is None
def test_three_engine_parity_validator_accepts_one_same_chart_row(tmp_path: Path) -> None:
raw = tmp_path / "vedastro.json"
raw.write_text('{"source":"official"}', encoding="utf-8")
manifest = {
"case_id": "public_same_chart_001",
"birth_data_policy": "public_case_only",
"status": "tested",
"engines": {
"VedAstro": {"status": "official_verified", "official_raw_response_path": "references/oracle/artifacts/vedastro.json"},
"VedAstro": {
"status": "official_verified",
"official_raw_response_path": "vedastro.json",
"artifact_hash": hashlib.sha256(raw.read_bytes()).hexdigest(),
"settings": {"ayanamsa": "lahiri"},
},
"PyJHora_JHora": {"status": "tested", "raw_output_path": "references/oracle/artifacts/pyjhora.txt"},
"jyotishganit": {"status": "tested", "raw_output_path": "references/oracle/artifacts/jyotishganit.json"},
},
@@ -46,3 +58,39 @@ def test_three_engine_parity_validator_accepts_one_same_chart_row(tmp_path: Path
assert result["tested"] is True
assert result["comparison_row_count"] == 1
assert result["match_count"] == 1
def test_validator_require_pass_rejects_blocked_manifest(tmp_path: Path) -> None:
root = Path(__file__).resolve().parents[1]
manifest = tmp_path / "blocked_manifest.json"
manifest.write_text(
json.dumps(
{
"case_id": "blocked_case",
"birth_data_policy": "public_case_only",
"engines": {
"VedAstro": {"status": "blocked"},
"PyJHora_JHora": {"status": "blocked"},
"jyotishganit": {"status": "blocked"},
},
"comparison_rows": [
{
"section": "D1",
"field": "Sun.longitude",
"local_value": 1.0,
"oracle_values": {},
"status": "blocked",
}
],
}
),
encoding="utf-8",
)
completed = subprocess.run(
[sys.executable, "scripts/three_engine_parity_replay_validator.py", str(manifest), "--require-pass"],
cwd=root,
capture_output=True,
text=True,
check=False,
)
assert completed.returncode == 1
@@ -198,9 +198,10 @@ def test_runtime_evidence_log_exposes_blind_packet_case_and_quality_gate_contrac
"Cross-System Arbitration",
"Evidence Packet",
"Blind Technical Mode",
"MEVG / Global Web Evidence",
"Real Case Calibration",
"Functional Benefic/Malefic",
"MEVG / Global Web Evidence",
"Real Case Calibration",
"Timing Precision Gate",
"Functional Benefic/Malefic",
]
engines = log["external_engine_cross_validation"]["engines"]
assert engines["VedAstro"]["status"] == "local_fallback"
+21
View File
@@ -44,6 +44,13 @@ def drekkana_ref(lon: float) -> int:
return (sign_index + part_index * 4) % 12
def chaturthamsa_ref(lon: float) -> int:
sign_index = int((lon % 360) / 30) % 12
degree_in_sign = (lon % 360) - sign_index * 30
part_index = int(degree_in_sign / (30 / 4))
return (sign_index + part_index * 3) % 12
@given(st.floats(min_value=0, max_value=359.999999, allow_nan=False, allow_infinity=False))
def test_navamsa_matches_bphs_reference(lon: float) -> None:
result = calc_varga(lon, 9)
@@ -66,6 +73,20 @@ def test_drekkana_uses_same_plus_four_plus_eight(lon: float) -> None:
assert result["sign_idx"] == drekkana_ref(lon)
@given(st.floats(min_value=0, max_value=359.999999, allow_nan=False, allow_infinity=False))
def test_chaturthamsa_matches_pyjhora_parashara_reference(lon: float) -> None:
result = calc_varga(lon, 4)
assert result["sign_idx"] == chaturthamsa_ref(lon)
assert result["sign"] == SIGNS[chaturthamsa_ref(lon)]
assert 0 <= result["degree_in_sign"] < 30
def test_chaturthamsa_reference_boundary_examples() -> None:
assert [varga_map(0, part, 4) for part in range(4)] == [0, 3, 6, 9]
assert [varga_map(8, part, 4) for part in range(4)] == [8, 11, 2, 5]
assert [varga_map(11, part, 4) for part in range(4)] == [11, 2, 5, 8]
def test_varga_map_boundary_examples() -> None:
assert varga_map(0, 0, 9) == 0 # Aries Navamsa starts Aries
assert varga_map(1, 0, 9) == 9 # Taurus Navamsa starts Capricorn (9th from sign)
+13
View File
@@ -1,5 +1,7 @@
from __future__ import annotations
import json
def test_gateway_status_defaults_to_local_first_cn_safe(monkeypatch):
from scripts import vedastro_gateway
@@ -58,6 +60,17 @@ def test_gateway_status_exposes_official_readiness_gate(monkeypatch):
assert status["official_readiness"]["free_tier_possible_with_cache_queue"] is True
def test_gateway_status_never_exposes_vedastro_secret(monkeypatch):
from scripts import vedastro_gateway
monkeypatch.setenv("JYOTISH_SKIP_LOCAL_ENV", "1")
monkeypatch.setenv("VEDASTRO_API_KEY", "sk_live_test_secret")
status = vedastro_gateway.gateway_status()
text = json.dumps(status, sort_keys=True)
assert "sk_live_test_secret" not in text
assert status["credential_configured"] is True
def test_gateway_run_packet_uses_user_entrypoint_and_marks_not_all_641(monkeypatch):
from scripts import vedastro_gateway
@@ -0,0 +1,26 @@
import json
from pathlib import Path
def test_official_full_snapshot_artifact_manifest_lists_raw_response(tmp_path, monkeypatch):
from scripts import vedastro_service_adapter as adapter
monkeypatch.setattr(adapter, "ARTIFACT_DIR", tmp_path)
artifact = tmp_path / "official_full_snapshot-abc-def.json"
artifact.write_text(
json.dumps(
{
"status": "ok",
"operation": "official_full_snapshot",
"raw_response": {"source": "vedastro_official_full_snapshot", "sections": {"ok": True}},
"request_manifest": {"case_id": "synthetic"},
"snapshot_sections": {"chart_core": {"Status": "Pass"}},
}
),
encoding="utf-8",
)
manifest = adapter.list_official_full_snapshot_artifacts()
assert manifest["artifact_count"] == 1
assert manifest["artifacts"][0]["official_raw_response_available"] is True
assert manifest["artifacts"][0]["path"] == str(artifact)
+2 -2
View File
@@ -158,7 +158,7 @@ def test_vedastro_official_mcp_bridge_can_call_tool_against_mock_server() -> Non
"--tool",
"get_dasa_at_time",
"--arguments-json",
'{"birth_date":"17/04/REDACTED_YEAR","check_date":"04/07/2026"}',
'{"birth_date":"17/04/1990","check_date":"04/07/2026"}',
],
cwd=ROOT,
text=True,
@@ -175,4 +175,4 @@ def test_vedastro_official_mcp_bridge_can_call_tool_against_mock_server() -> Non
assert report["operation"] == "call_tool"
assert report["tool_name"] == "get_dasa_at_time"
assert report["result"]["content"][0]["text"] == "Saturn/Venus"
assert seen_arguments["birth_date"] == "17/04/REDACTED_YEAR"
assert seen_arguments["birth_date"] == "17/04/1990"
@@ -67,7 +67,7 @@ def test_vedastro_official_subprocesses_use_adapter_timeout(monkeypatch) -> None
monkeypatch.setattr(adapter.subprocess, "run", fake_run)
case = {
"year": REDACTED_YEAR,
"year": 1990,
"month": 4,
"day": 17,
"hour": 14,
@@ -97,7 +97,7 @@ def test_vedastro_official_subprocess_timeouts_are_controlled(monkeypatch) -> No
monkeypatch.setattr(adapter.subprocess, "run", fake_timeout)
case = {
"year": REDACTED_YEAR,
"year": 1990,
"month": 4,
"day": 17,
"hour": 14,
@@ -151,7 +151,7 @@ def test_vedastro_official_snapshot_stops_when_foreground_budget_is_exhausted(mo
ticks = iter([100.0, 104.1])
monkeypatch.setattr(adapter.time, "monotonic", lambda: next(ticks))
result = adapter._run_official_full_snapshot_case({
"year": REDACTED_YEAR,
"year": 1990,
"month": 4,
"day": 17,
"hour": 14,
@@ -213,7 +213,7 @@ def test_vedastro_official_snapshot_skips_bridge_after_runner_consumes_budget(mo
ticks = iter([100.0, 100.1, 104.2])
monkeypatch.setattr(adapter.time, "monotonic", lambda: next(ticks))
result = adapter._run_official_full_snapshot_case({
"year": REDACTED_YEAR,
"year": 1990,
"month": 4,
"day": 17,
"hour": 14,
@@ -275,7 +275,7 @@ def test_vedastro_official_snapshot_budget_does_not_mask_mock_rest_endpoint(monk
monkeypatch.setattr(adapter.time, "monotonic", lambda: next(ticks))
result = adapter._run_official_full_snapshot_case({
"year": REDACTED_YEAR,
"year": 1990,
"month": 4,
"day": 17,
"hour": 14,
@@ -549,7 +549,8 @@ def test_vedastro_service_adapter_posts_official_search_events_contract() -> Non
assert report["source_metadata"]["endpoint"].endswith("/api")
assert report["source_metadata"]["official_endpoint_path"] == "/Calculate/SearchEvents"
assert report["source_metadata"]["official_request_profile"]["method"] == "POST"
assert report["source_metadata"]["official_request_profile"]["headers"]["x-api-key"] == "[redacted]"
metadata_headers = report["source_metadata"]["official_request_profile"]["headers"]
assert metadata_headers == {"Content-Type": "application/json"}
assert report["source_metadata"]["official_request_profile_hash"]
assert report["source_metadata"]["request_hash"] != report["source_metadata"]["official_request_profile_hash"]
@@ -0,0 +1,38 @@
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SCRIPTS = ROOT / "scripts"
if str(SCRIPTS) not in sys.path:
sys.path.insert(0, str(SCRIPTS))
import vedastro_strength_oracle_packet # noqa: E402
def test_strength_packet_declares_shadbala_and_ashtakavarga_as_secondary_evidence() -> None:
packet = vedastro_strength_oracle_packet.build_strength_oracle_packet("career")
assert packet["scope"] == "vedastro_strength_oracle_packet"
assert packet["domain"] == "career"
assert packet["adjudicator_policy"]["can_change_score"] is False
assert packet["adjudicator_policy"]["can_set_dominant_label"] is False
assert packet["adjudicator_policy"]["can_set_payout_label"] is False
assert [item["method"] for item in packet["requests"]] == ["CalculateShadbala", "CalculateAshtakavarga"]
assert all(item["role"] == "external_technique_evidence" for item in packet["requests"])
assert packet["technique_audit_rows"] == [
{
"technique": "VedAstro Shadbala Oracle",
"status": "preview",
"role": "external_strength_evidence",
"effect": "secondary_context_only_no_score_or_label_lift",
},
{
"technique": "VedAstro Ashtakavarga Oracle",
"status": "preview",
"role": "external_strength_evidence",
"effect": "secondary_context_only_no_score_or_label_lift",
},
]
+7 -5
View File
@@ -1,12 +1,14 @@
"""
PyJHora 风格硬编码 Yoga True/False 测试
"""
import sys, os
SKILL_DIR = '<home>/.workbuddy/skills/jyotish-vedic-astrology'
sys.path.insert(0, os.path.join(SKILL_DIR, 'scripts'))
RULES_PATH = os.path.join(SKILL_DIR, 'references', 'yoga_rules.json')
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / 'scripts'))
RULES_PATH = ROOT / 'references' / 'yoga_rules.json'
from yoga_engine import YogaEngine
engine = YogaEngine(RULES_PATH)
engine = YogaEngine(str(RULES_PATH))
def detect(rule_id, planets, ascendant, context=None):
results = engine.detect(planets, ascendant, context=context)
+3 -3
View File
@@ -642,13 +642,13 @@ CELEBRITY_CASES = [
'marriages':[
{'spouse':'Lisa Marie Presley','date':(1994,5,26),'divorce':(1996,1,18)},
{'spouse':'Debbie Rowe','date':(1996,11,14),'divorce':(1999,10,1)}],
'events':[('Jackson 5 debut',1969,8,1),('Thriller',1982,11,30),('Grammy 8',1984,1,27),('Allegations',REDACTED_YEAR,8,24),('Death',2009,6,25)]},
'events':[('Jackson 5 debut',1969,8,1),('Thriller',1982,11,30),('Grammy 8',1984,1,27),('Allegations',1993,8,24),('Death',2009,6,25)]},
{'name':'Nelson Mandela','birth':(1918,7,18,0.9,-31.9,27.0),'gender':'M','rating':'A','expected_asc':'Taurus',
'marriages':[
{'spouse':'Evelyn Mase','date':(1944,10,5),'divorce':(1958,1,1)},
{'spouse':'Winnie Madikizela','date':(1958,6,14),'divorce':(1996,3,19)},
{'spouse':'Graca Machel','date':(1998,7,18)}],
'events':[('Join ANC',1944,1,1),('Rivonia trial',1964,6,12),('Released',1990,2,11),('Nobel',REDACTED_YEAR,12,10),('President',1994,5,10),('Death',2013,12,5)]},
'events':[('Join ANC',1944,1,1),('Rivonia trial',1964,6,12),('Released',1990,2,11),('Nobel',1993,12,10),('President',1994,5,10),('Death',2013,12,5)]},
{'name':'Tom Cruise','birth':(1962,7,3,19.25,43.05,-76.15),'gender':'M','rating':'AA','expected_asc':'Libra',
'marriages':[
{'spouse':'Mimi Rogers','date':(1987,5,9),'divorce':(1990,2,4)},
@@ -667,7 +667,7 @@ CELEBRITY_CASES = [
'marriages':[{'spouse':'Meghan Markle','date':(2018,5,19),'ongoing':True}],
'events':[('Military',2005,5,1),('Invictus Games',2014,9,10),('Royal exit',2020,1,8)]},
{'name':'Jeff Bezos','birth':(1964,1,12,9.63,25.78,-80.19),'gender':'M','rating':'A','expected_asc':'Scorpio',
'marriages':[{'spouse':'MacKenzie Scott','date':(REDACTED_YEAR,1,1),'divorce':(2019,7,5)}],
'marriages':[{'spouse':'MacKenzie Scott','date':(1993,1,1),'divorce':(2019,7,5)}],
'events':[('Found Amazon',1994,7,5),('IPO',1997,5,15),('Blue Origin',2021,7,20)]},
{'name':'Priyanka Chopra','birth':(1982,7,18,10.5,23.57,87.19),'gender':'F','rating':'A','expected_asc':'Scorpio',
'marriages':[{'spouse':'Nick Jonas','date':(2018,12,1),'ongoing':True}],
+1 -1
View File
@@ -27,7 +27,7 @@ CASES = [
{'name':'Prince Harry','birth':(1984,9,15,15.33,51.5,-0.17),'gender':'M',
'marriage1':(2018,5,19)},
{'name':'Jeff Bezos','birth':(1964,1,12,9.63,25.78,-80.19),'gender':'M',
'marriage1':(REDACTED_YEAR,1,1)},
'marriage1':(1993,1,1)},
{'name':'Priyanka Chopra','birth':(1982,7,18,10.5,23.57,87.19),'gender':'F',
'marriage1':(2018,12,1)},
{'name':'Shah Rukh Khan','birth':(1965,11,1,21.25,28.61,77.21),'gender':'M',