Harden Shadbala oracle and VedAstro range evidence
This commit is contained in:
@@ -34,6 +34,8 @@ This file is the small index for the current engineering fronts that still drive
|
||||
- `/Users/wuyongnaren/Documents/印度占星/docs/research/oracle_benchmark_inventory_latest.json`
|
||||
- `/Users/wuyongnaren/Documents/印度占星/docs/research/oracle_closure_master_dashboard_latest.md`
|
||||
- `/Users/wuyongnaren/Documents/印度占星/docs/research/public_benchmark_dashboard_latest.md`
|
||||
- `/Users/wuyongnaren/Documents/印度占星/docs/research/shadbala_absolute_oracle_comparison_audit_2026_06_28.md`
|
||||
- `/Users/wuyongnaren/Documents/印度占星/scripts/shadbala_oracle_comparison.py`
|
||||
- `/Users/wuyongnaren/Documents/印度占星/references/oracle/`
|
||||
- Before changing oracle-dependent adjudicator or benchmark claims, run:
|
||||
- `python3 scripts/oracle_benchmark_inventory.py --format json`
|
||||
@@ -43,6 +45,7 @@ This file is the small index for the current engineering fronts that still drive
|
||||
- `/Users/wuyongnaren/Documents/印度占星/docs/research/vedastro_parity_matrix_latest.md`
|
||||
- `/Users/wuyongnaren/Documents/印度占星/docs/research/vedastro_parity_matrix_latest.json`
|
||||
- `/Users/wuyongnaren/Documents/印度占星/docs/research/life_event_graph_v1_audit_2026_06_28.md`
|
||||
- `/Users/wuyongnaren/Documents/印度占星/docs/research/vedastro_range_scan_allowlist_audit_2026_06_28.md`
|
||||
- `/Users/wuyongnaren/Documents/印度占星/scripts/vedastro_service_adapter.py`
|
||||
- follow only after the Jaimini marriage bridge v1 regression loop is closed
|
||||
- Use the parity matrix before adding or claiming VedAstro-equivalent capability.
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Shadbala Absolute Oracle Comparison Audit - 2026-06-28
|
||||
|
||||
## Scope
|
||||
|
||||
This pass promotes the local Shadbala absolute-value comparison helper from an untracked fragment into a formal oracle-closure asset.
|
||||
|
||||
## New Entrypoint
|
||||
|
||||
- `/Users/wuyongnaren/Documents/印度占星/scripts/shadbala_oracle_comparison.py`
|
||||
- Primary function: `compare_case(oracle_file, case_id)`
|
||||
- CLI example:
|
||||
|
||||
```bash
|
||||
python3 scripts/shadbala_oracle_comparison.py \
|
||||
--oracle-file references/oracle/dasha_shadbala_oracle_cases.json \
|
||||
--case-id template_steve_jobs_dasha_lahiri \
|
||||
--format json
|
||||
```
|
||||
|
||||
## Output Contract
|
||||
|
||||
The report exposes:
|
||||
|
||||
- `scope = shadbala_absolute_oracle_comparison`
|
||||
- `case_id`
|
||||
- external oracle `status`
|
||||
- birth and settings metadata
|
||||
- per-planet `oracle_total_rupa`, `local_total_rupa`, and `diff_total_rupa`
|
||||
- per-component Rupa deltas
|
||||
- `global_scaling_check`
|
||||
- tolerance metadata
|
||||
|
||||
## Boundary
|
||||
|
||||
- This is diagnostic oracle evidence.
|
||||
- It does not authorize global Shadbala scaling.
|
||||
- It does not tune constants from a single case.
|
||||
- It preserves component-level deltas so future fixes can target the actual failing sub-strength instead of hiding mismatch inside a total score.
|
||||
|
||||
## Current External-Verified Case Snapshot
|
||||
|
||||
For `template_steve_jobs_dasha_lahiri`:
|
||||
|
||||
- `planet_count = 7`
|
||||
- `planets_within_total_tolerance = 5`
|
||||
- `max_abs_total_delta_rupa = 2.085`
|
||||
|
||||
This is useful enough to keep in the main repo, but not sufficient to claim Shadbala oracle closure.
|
||||
|
||||
## Regression Coverage
|
||||
|
||||
- `/Users/wuyongnaren/Documents/印度占星/tests/test_shadbala_oracle_comparison.py`
|
||||
@@ -0,0 +1,48 @@
|
||||
# VedAstro Range Scan Allowlist Audit - 2026-06-28
|
||||
|
||||
## Scope
|
||||
|
||||
This pass hardens the VedAstro range-scan adapter so external `EventsAtRange`-style responses do not enter the local evidence ledger unfiltered.
|
||||
|
||||
## Behavior
|
||||
|
||||
`scripts/vedastro_service_adapter.py` now filters range-scan events through a per-domain allowlist before writing `evidence_ledger`.
|
||||
|
||||
Supported domains:
|
||||
|
||||
- `marriage`
|
||||
- `wealth`
|
||||
- `career`
|
||||
|
||||
Each domain can accept an event by either:
|
||||
|
||||
- known event id, or
|
||||
- at least one relevant tag.
|
||||
|
||||
## Boundary
|
||||
|
||||
- The allowlist only filters external candidate evidence.
|
||||
- It does not promote VedAstro events into final conclusions.
|
||||
- It does not change local Dasha, Narayana, Jaimini, Varga, Shadbala, Ashtakavarga, or strict workflow scoring.
|
||||
- External range evidence remains secondary/oracle evidence until a domain adjudicator explicitly promotes it through tests.
|
||||
|
||||
## Contract Exposure
|
||||
|
||||
`--print-schema` now exposes:
|
||||
|
||||
```json
|
||||
{
|
||||
"range_scan_event_allowlist": {
|
||||
"marriage": {
|
||||
"event_ids": [],
|
||||
"tags": []
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This prevents future agents from treating the filtering layer as hidden behavior.
|
||||
|
||||
## Regression Coverage
|
||||
|
||||
- `/Users/wuyongnaren/Documents/印度占星/tests/test_vedastro_service_adapter_executor.py`
|
||||
@@ -8,7 +8,10 @@ import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import oracle_boundary_audit
|
||||
try:
|
||||
from scripts import oracle_boundary_audit
|
||||
except ImportError: # pragma: no cover - supports direct script execution.
|
||||
import oracle_boundary_audit
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
@@ -60,6 +60,36 @@ PARITY_CASES = {
|
||||
}
|
||||
|
||||
SUPPORTED_RANGE_SCAN_DOMAINS = {"marriage", "wealth", "career"}
|
||||
RANGE_SCAN_EVENT_ALLOWLIST = {
|
||||
"marriage": {
|
||||
"event_ids": {
|
||||
"GocharJupiterIn7th",
|
||||
"GocharJupiterAspect7th",
|
||||
"GocharSaturnAspect7th",
|
||||
"JupiterSupportsMarriageAxis",
|
||||
},
|
||||
"tags": {"marriage", "relationship", "spouse", "transit"},
|
||||
},
|
||||
"wealth": {
|
||||
"event_ids": {
|
||||
"GocharJupiterIn2nd",
|
||||
"GocharJupiterIn11th",
|
||||
"GocharJupiterAspect2nd",
|
||||
"GocharJupiterAspect11th",
|
||||
"WealthExpansionWindow",
|
||||
},
|
||||
"tags": {"wealth", "finance", "income", "gains", "transit"},
|
||||
},
|
||||
"career": {
|
||||
"event_ids": {
|
||||
"GocharJupiterIn10th",
|
||||
"GocharSaturnIn10th",
|
||||
"GocharJupiterAspect10th",
|
||||
"CareerExpansionWindow",
|
||||
},
|
||||
"tags": {"career", "profession", "work", "transit"},
|
||||
},
|
||||
}
|
||||
DEFAULT_TIMEOUT_SECONDS = 8
|
||||
TIMEOUT_ENV = "VEDASTRO_TIMEOUT_SECONDS"
|
||||
RETRY_POLICY = {
|
||||
@@ -85,6 +115,13 @@ def schema() -> dict[str, Any]:
|
||||
**PARITY_CASES["beijing_first_use_demo"],
|
||||
"body_list": ["Sun", "Moon", "Ascendant", "Rahu", "Ketu"],
|
||||
}
|
||||
range_scan_allowlist = {
|
||||
domain: {
|
||||
"event_ids": sorted(values["event_ids"]),
|
||||
"tags": sorted(values["tags"]),
|
||||
}
|
||||
for domain, values in sorted(RANGE_SCAN_EVENT_ALLOWLIST.items())
|
||||
}
|
||||
return {
|
||||
"adapter": "vedastro_service_adapter",
|
||||
"backend": "vedastro_service_adapter_candidate",
|
||||
@@ -144,6 +181,7 @@ def schema() -> dict[str, Any]:
|
||||
"evidence_ledger",
|
||||
"source_metadata",
|
||||
],
|
||||
"range_scan_event_allowlist": range_scan_allowlist,
|
||||
"request_example": request_example,
|
||||
"provenance_contract": {
|
||||
"external_service": True,
|
||||
@@ -222,20 +260,32 @@ def _normalize_range_scan_success(
|
||||
if not isinstance(events, list):
|
||||
events = []
|
||||
|
||||
domain = request_preview["domain"]
|
||||
allowlist = RANGE_SCAN_EVENT_ALLOWLIST.get(domain, {})
|
||||
allowed_ids = allowlist.get("event_ids", set())
|
||||
allowed_tags = allowlist.get("tags", set())
|
||||
|
||||
evidence_ledger = []
|
||||
for index, event in enumerate(events, start=1):
|
||||
if not isinstance(event, dict):
|
||||
continue
|
||||
event_id = event.get("id") or event.get("name") or f"event_{index}"
|
||||
tags = event.get("tags") or []
|
||||
if not isinstance(tags, list):
|
||||
tags = []
|
||||
tag_set = {str(tag) for tag in tags}
|
||||
if event_id not in allowed_ids and tag_set.isdisjoint(allowed_tags):
|
||||
continue
|
||||
evidence_ledger.append(
|
||||
{
|
||||
"source": "vedastro_service_adapter_candidate",
|
||||
"operation": "range_scan",
|
||||
"domain": request_preview["domain"],
|
||||
"event_id": event.get("id") or event.get("name") or f"event_{index}",
|
||||
"domain": domain,
|
||||
"event_id": event_id,
|
||||
"start": event.get("start") or event.get("start_time") or event.get("start_date"),
|
||||
"end": event.get("end") or event.get("end_time") or event.get("end_date"),
|
||||
"score": event.get("score") if event.get("score") is not None else event.get("strength"),
|
||||
"tags": event.get("tags") or [],
|
||||
"tags": tags,
|
||||
"raw": event,
|
||||
}
|
||||
)
|
||||
@@ -259,7 +309,7 @@ def _normalize_range_scan_success(
|
||||
"available": True,
|
||||
"status": "ok",
|
||||
"operation": "range_scan",
|
||||
"domain": request_preview["domain"],
|
||||
"domain": domain,
|
||||
"request_preview": request_preview,
|
||||
"event_count": len(evidence_ledger),
|
||||
"top_event": top_event,
|
||||
|
||||
@@ -41,6 +41,8 @@ def test_vedastro_service_adapter_executor_schema_is_declared() -> None:
|
||||
assert "start_date" in report["range_scan_request_contract"]
|
||||
assert "range_scan_response_contract" in report
|
||||
assert "evidence_ledger" in report["range_scan_response_contract"]
|
||||
assert report["range_scan_event_allowlist"]["marriage"]["event_ids"]
|
||||
assert "marriage" in report["range_scan_event_allowlist"]["marriage"]["tags"]
|
||||
|
||||
|
||||
def test_vedastro_service_adapter_returns_controlled_unconfigured_status() -> None:
|
||||
@@ -295,6 +297,78 @@ def test_vedastro_service_adapter_can_normalize_mock_range_scan_response() -> No
|
||||
assert report["source_metadata"]["endpoint"].startswith("http://127.0.0.1:")
|
||||
|
||||
|
||||
def test_vedastro_service_adapter_applies_domain_allowlist_to_range_scan_noise() -> None:
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
def do_POST(self) -> None: # noqa: N802
|
||||
response = {
|
||||
"events": [
|
||||
{
|
||||
"id": "GocharJupiterIn7th",
|
||||
"name": "Jupiter enters 7th house",
|
||||
"start": "2026-05-01",
|
||||
"end": "2026-06-01",
|
||||
"score": 72,
|
||||
"tags": ["marriage", "transit"],
|
||||
},
|
||||
{
|
||||
"id": "RandomMoonMoodShift",
|
||||
"name": "Random moon mood shift",
|
||||
"start": "2026-05-08",
|
||||
"end": "2026-05-09",
|
||||
"score": 91,
|
||||
"tags": ["emotion", "noise"],
|
||||
},
|
||||
]
|
||||
}
|
||||
body = json.dumps(response).encode("utf-8")
|
||||
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",
|
||||
"--range-scan",
|
||||
"--domain",
|
||||
"marriage",
|
||||
"--case",
|
||||
"beijing_first_use_demo",
|
||||
"--start-date",
|
||||
"2026-01-01",
|
||||
"--end-date",
|
||||
"2031-01-01",
|
||||
],
|
||||
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["event_count"] == 1
|
||||
assert report["top_event"]["event_id"] == "GocharJupiterIn7th"
|
||||
assert report["evidence_ledger"][0]["event_id"] == "GocharJupiterIn7th"
|
||||
|
||||
|
||||
def test_vedastro_service_adapter_classifies_http_error() -> None:
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
def do_POST(self) -> None: # noqa: N802
|
||||
|
||||
Reference in New Issue
Block a user