chore: enforce public release evidence boundaries
This commit is contained in:
@@ -62,8 +62,8 @@ FRONTS = {
|
||||
"--format",
|
||||
"json",
|
||||
],
|
||||
"operator_card": "docs/benchmark/shadbala_redacted_place_raman_first_packet_operator_card.md",
|
||||
"packet_template": "references/oracle/evidence_packet_templates/shadbala_redacted_place_raman_first_packet.json",
|
||||
"operator_card": "docs/benchmark/shadbala_synthetic_north_china_raman_first_packet_operator_card.md",
|
||||
"packet_template": "references/oracle/evidence_packet_templates/shadbala_synthetic_north_china_raman_first_packet.json",
|
||||
"oracle_file": "references/oracle/dasha_shadbala_oracle_cases.json",
|
||||
"apply_script": "scripts/oracle_collection_queue.py",
|
||||
"external_sources": [
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Scan release files for private birth-data residues."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import Iterable
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
SKIP_DIRS = {
|
||||
".git",
|
||||
"__pycache__",
|
||||
".pytest_cache",
|
||||
"node_modules",
|
||||
"scratch",
|
||||
"references/open_source_sources",
|
||||
}
|
||||
|
||||
SKIP_FILES = {
|
||||
"scripts/public_release_privacy_scan.py",
|
||||
"tests/test_public_release_privacy_scan.py",
|
||||
}
|
||||
|
||||
TEXT_SUFFIXES = {
|
||||
".cfg",
|
||||
".csv",
|
||||
".html",
|
||||
".js",
|
||||
".json",
|
||||
".md",
|
||||
".py",
|
||||
".txt",
|
||||
".yaml",
|
||||
".yml",
|
||||
}
|
||||
|
||||
DENY_PATTERNS: list[tuple[str, re.Pattern[str]]] = [
|
||||
("private_exact_iso_birth_date", re.compile(r"REDACTED_DATE")),
|
||||
("private_compact_birth_datetime", re.compile(r"REDACTED_DATE[_-]?REDACTED_TIME")),
|
||||
("private_slug_birth_date", re.compile(r"REDACTED_YEAR[_-]04[_-]17")),
|
||||
("private_birth_time_literal", re.compile(r"REDACTED_YEAR.{0,120}\bREDACTED_TIME\b|\bREDACTED_TIME\b.{0,120}REDACTED_YEAR|REDACTED_TIME")),
|
||||
("private_place_han", re.compile(r"REDACTED_PLACE|REDACTED_PLACE|REDACTED_HOSPITAL")),
|
||||
("private_case_slug", re.compile(r"user_REDACTED_YEAR|redacted_place", re.IGNORECASE)),
|
||||
(
|
||||
"private_birth_dict_tuple",
|
||||
re.compile(
|
||||
r"(?s)(?:year|--year|datetime\()\D*REDACTED_YEAR.{0,220}"
|
||||
r"(?:month|--month|,\s*)\D*4.{0,220}"
|
||||
r"(?:day|--day|,\s*)\D*17.{0,220}"
|
||||
r"(?:hour|--hour|,\s*)\D*14.{0,220}"
|
||||
r"(?:minute|--minute|,\s*)\D*49"
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def _is_skipped(path: Path) -> bool:
|
||||
rel = path.relative_to(ROOT).as_posix()
|
||||
if rel in SKIP_FILES:
|
||||
return True
|
||||
return any(rel == item or rel.startswith(f"{item}/") for item in SKIP_DIRS)
|
||||
|
||||
|
||||
def iter_release_files(root: Path = ROOT) -> Iterable[Path]:
|
||||
completed = subprocess.run(
|
||||
["git", "ls-files"],
|
||||
cwd=root,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
for line in completed.stdout.splitlines():
|
||||
path = root / line
|
||||
if not path.is_file() or _is_skipped(path):
|
||||
continue
|
||||
if path.suffix.lower() in TEXT_SUFFIXES:
|
||||
yield path
|
||||
|
||||
|
||||
def scan_text(path: Path, text: str) -> list[dict[str, object]]:
|
||||
findings: list[dict[str, object]] = []
|
||||
try:
|
||||
display_path = path.relative_to(ROOT).as_posix()
|
||||
except ValueError:
|
||||
display_path = path.as_posix()
|
||||
for rule_id, pattern in DENY_PATTERNS:
|
||||
for match in pattern.finditer(text):
|
||||
line = text.count("\n", 0, match.start()) + 1
|
||||
findings.append(
|
||||
{
|
||||
"rule_id": rule_id,
|
||||
"path": display_path,
|
||||
"line": line,
|
||||
}
|
||||
)
|
||||
return findings
|
||||
|
||||
|
||||
def build_report(root: Path = ROOT) -> dict[str, object]:
|
||||
findings: list[dict[str, object]] = []
|
||||
scanned = 0
|
||||
for path in iter_release_files(root):
|
||||
try:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
except UnicodeDecodeError:
|
||||
text = path.read_text(encoding="utf-8", errors="ignore")
|
||||
scanned += 1
|
||||
findings.extend(scan_text(path, text))
|
||||
return {
|
||||
"scope": "public_release_privacy_scan",
|
||||
"scanned_files": scanned,
|
||||
"finding_count": len(findings),
|
||||
"findings": findings,
|
||||
"status": "pass" if not findings else "fail",
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--json", action="store_true", help="Emit JSON.")
|
||||
args = parser.parse_args()
|
||||
report = build_report()
|
||||
if args.json:
|
||||
print(json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True))
|
||||
else:
|
||||
print(f"{report['status']}: {report['finding_count']} findings")
|
||||
for finding in report["findings"]:
|
||||
print(f"{finding['path']}:{finding['line']} {finding['rule_id']}")
|
||||
return 0 if report["status"] == "pass" else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -13,8 +13,8 @@ from typing import Any
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
PYTHON = sys.executable
|
||||
FIRST_PRIORITY_CASE_ID = "template_redacted_place_shadbala_raman"
|
||||
FIRST_PRIORITY_TEMPLATE_PATH = "references/oracle/evidence_packet_templates/shadbala_redacted_place_raman_first_packet.json"
|
||||
FIRST_PRIORITY_CASE_ID = "template_synthetic_north_china_shadbala_raman"
|
||||
FIRST_PRIORITY_TEMPLATE_PATH = "references/oracle/evidence_packet_templates/shadbala_synthetic_north_china_raman_first_packet.json"
|
||||
SHADBALA_TARGET_FIELD = "target.shadbala_components"
|
||||
SUPPORTING_TARGET_FIELDS = ["target.moon_sidereal_longitude_deg"]
|
||||
REQUIRED_PLANETS = ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"]
|
||||
|
||||
@@ -15,7 +15,7 @@ PACKET_RE = re.compile(r"\.v(\d+)\.json$")
|
||||
|
||||
def latest_packet() -> tuple[int, Path]:
|
||||
packets: list[tuple[int, Path]] = []
|
||||
for path in WORK_DIR.glob("jhora_master_evidence_packet_REDACTED_DATE_REDACTED_TIME.v*.json"):
|
||||
for path in WORK_DIR.glob("jhora_master_evidence_packet_public_sample_19550224_1915.v*.json"):
|
||||
match = PACKET_RE.search(path.name)
|
||||
if match:
|
||||
packets.append((int(match.group(1)), path))
|
||||
@@ -45,11 +45,11 @@ def main() -> int:
|
||||
if changed:
|
||||
path.write_text(json.dumps(packet, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
ledger = WORK_DIR / "evidence_packet_status_ledger_REDACTED_DATE_REDACTED_TIME.md"
|
||||
ledger = WORK_DIR / "evidence_packet_status_ledger_public_sample_19550224_1915.md"
|
||||
if ledger.exists():
|
||||
text = ledger.read_text(encoding="utf-8")
|
||||
line_re = re.compile(
|
||||
r"\| Master evidence packet \| `jhora_master_evidence_packet_REDACTED_DATE_REDACTED_TIME\.v\d+\.json` \| active \| Current canonical structured packet\. \|"
|
||||
r"\| Master evidence packet \| `jhora_master_evidence_packet_public_sample_19550224_1915\.v\d+\.json` \| active \| Current canonical structured packet\. \|"
|
||||
)
|
||||
wanted_line = f"| Master evidence packet | `{path.name}` | active | Current canonical structured packet. |"
|
||||
new_text = line_re.sub(wanted_line, text, count=1)
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Audit the route-level VedAstro official evidence contract.
|
||||
|
||||
This is a provenance/contract gate, not a live VedAstro oracle. It protects
|
||||
the user-facing reading layer from claiming official evidence when the official
|
||||
raw response is blocked, partial, or only represented by local fallback data.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from copy import deepcopy
|
||||
from typing import Any
|
||||
|
||||
|
||||
REQUIRED_CONTRACT_FIELDS = [
|
||||
"source_priority_mode",
|
||||
"official_primary_evidence",
|
||||
"local_supplemental_evidence",
|
||||
"fallback_used",
|
||||
"blocked_items",
|
||||
"conflicts",
|
||||
"confidence_cap",
|
||||
]
|
||||
|
||||
VALID_CONFIDENCE_CAPS = {"high", "medium", "low", "blocked"}
|
||||
|
||||
|
||||
ROUTE_FIXTURES: list[dict[str, Any]] = [
|
||||
{
|
||||
"route": "relationship",
|
||||
"contract": {
|
||||
"source_priority_mode": "local_fallback_official_blocked",
|
||||
"official_primary_evidence": {
|
||||
"status": "blocked",
|
||||
"required": True,
|
||||
"raw_response_available": False,
|
||||
"reason": "official_snapshot_budget_exhausted",
|
||||
},
|
||||
"local_supplemental_evidence": {
|
||||
"status": "available",
|
||||
"sections": ["D1", "D9", "UL", "Vimshottari", "Narayana"],
|
||||
},
|
||||
"fallback_used": ["local_jyotish_core"],
|
||||
"blocked_items": ["vedastro_official_full_snapshot"],
|
||||
"conflicts": [],
|
||||
"confidence_cap": "low",
|
||||
},
|
||||
},
|
||||
{
|
||||
"route": "career",
|
||||
"contract": {
|
||||
"source_priority_mode": "vedastro_official_primary",
|
||||
"official_primary_evidence": {
|
||||
"status": "official_verified",
|
||||
"required": True,
|
||||
"raw_response_available": True,
|
||||
"sections": ["chart_core", "dasha", "strength"],
|
||||
},
|
||||
"local_supplemental_evidence": {
|
||||
"status": "available",
|
||||
"sections": ["D10", "A10", "Shadbala", "Ashtakavarga"],
|
||||
},
|
||||
"fallback_used": [],
|
||||
"blocked_items": [],
|
||||
"conflicts": [],
|
||||
"confidence_cap": "high",
|
||||
},
|
||||
},
|
||||
{
|
||||
"route": "wealth",
|
||||
"contract": {
|
||||
"source_priority_mode": "vedastro_official_primary_partial",
|
||||
"official_primary_evidence": {
|
||||
"status": "partial",
|
||||
"required": True,
|
||||
"raw_response_available": True,
|
||||
"sections": ["chart_core"],
|
||||
},
|
||||
"local_supplemental_evidence": {
|
||||
"status": "missing_required_sections",
|
||||
"missing_sections": ["D2", "D11", "AV"],
|
||||
},
|
||||
"fallback_used": ["local_chart_core"],
|
||||
"blocked_items": ["local_wealth_supplemental_bundle"],
|
||||
"conflicts": [],
|
||||
"confidence_cap": "low",
|
||||
},
|
||||
},
|
||||
{
|
||||
"route": "health",
|
||||
"contract": {
|
||||
"source_priority_mode": "local_fallback_official_blocked",
|
||||
"official_primary_evidence": {
|
||||
"status": "blocked",
|
||||
"required": True,
|
||||
"raw_response_available": False,
|
||||
"reason": "endpoint_unconfigured",
|
||||
},
|
||||
"local_supplemental_evidence": {
|
||||
"status": "missing_required_sections",
|
||||
"missing_sections": ["D30", "medical_boundary_review"],
|
||||
},
|
||||
"fallback_used": [],
|
||||
"blocked_items": ["vedastro_official_full_snapshot", "local_health_supplemental_bundle"],
|
||||
"conflicts": [],
|
||||
"confidence_cap": "blocked",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def _official_status(contract: dict[str, Any]) -> str:
|
||||
evidence = contract.get("official_primary_evidence")
|
||||
if not isinstance(evidence, dict):
|
||||
return "missing"
|
||||
return str(evidence.get("status") or "missing")
|
||||
|
||||
|
||||
def _local_status(contract: dict[str, Any]) -> str:
|
||||
evidence = contract.get("local_supplemental_evidence")
|
||||
if not isinstance(evidence, dict):
|
||||
return "missing"
|
||||
return str(evidence.get("status") or "missing")
|
||||
|
||||
|
||||
def expected_confidence_cap(contract: dict[str, Any]) -> str:
|
||||
"""Return the strictest allowed confidence cap for this evidence state."""
|
||||
|
||||
official = _official_status(contract)
|
||||
local = _local_status(contract)
|
||||
conflicts = contract.get("conflicts")
|
||||
fallback_used = contract.get("fallback_used")
|
||||
unresolved_conflicts = bool(conflicts)
|
||||
has_fallback = isinstance(fallback_used, list) and bool(fallback_used)
|
||||
|
||||
if official in {"blocked", "missing"} and local != "available" and not has_fallback:
|
||||
return "blocked"
|
||||
if unresolved_conflicts:
|
||||
return "low"
|
||||
if official in {"partial", "blocked", "missing"}:
|
||||
return "low"
|
||||
if local != "available":
|
||||
return "low"
|
||||
return "high"
|
||||
|
||||
|
||||
def validate_contract(route: str, contract: dict[str, Any]) -> dict[str, Any]:
|
||||
missing_fields = [field for field in REQUIRED_CONTRACT_FIELDS if field not in contract]
|
||||
confidence_cap = contract.get("confidence_cap")
|
||||
expected_cap = expected_confidence_cap(contract)
|
||||
errors: list[str] = []
|
||||
|
||||
if missing_fields:
|
||||
errors.append(f"missing_required_fields:{','.join(missing_fields)}")
|
||||
if confidence_cap not in VALID_CONFIDENCE_CAPS:
|
||||
errors.append(f"invalid_confidence_cap:{confidence_cap}")
|
||||
if expected_cap == "blocked" and confidence_cap != "blocked":
|
||||
errors.append("blocked_state_must_use_blocked_confidence_cap")
|
||||
if expected_cap == "low" and confidence_cap not in {"low", "blocked"}:
|
||||
errors.append("partial_or_fallback_state_must_not_exceed_low")
|
||||
if expected_cap == "high" and confidence_cap not in {"high", "medium", "low", "blocked"}:
|
||||
errors.append("verified_state_has_invalid_confidence_cap")
|
||||
|
||||
return {
|
||||
"route": route,
|
||||
"valid": not errors,
|
||||
"missing_fields": missing_fields,
|
||||
"official_status": _official_status(contract),
|
||||
"local_status": _local_status(contract),
|
||||
"fallback_count": len(contract.get("fallback_used") or []),
|
||||
"blocked_count": len(contract.get("blocked_items") or []),
|
||||
"conflict_count": len(contract.get("conflicts") or []),
|
||||
"confidence_cap": confidence_cap,
|
||||
"expected_confidence_cap": expected_cap,
|
||||
"errors": errors,
|
||||
}
|
||||
|
||||
|
||||
def build_audit_report(routes: list[dict[str, Any]] | None = None) -> dict[str, Any]:
|
||||
fixtures = deepcopy(routes if routes is not None else ROUTE_FIXTURES)
|
||||
route_reports = [
|
||||
validate_contract(str(item.get("route") or "unknown"), item.get("contract") or {})
|
||||
for item in fixtures
|
||||
]
|
||||
invalid_routes = [item for item in route_reports if not item["valid"]]
|
||||
|
||||
return {
|
||||
"scope": "vedastro_official_evidence_contract_audit",
|
||||
"schema_version": 1,
|
||||
"required_fields": REQUIRED_CONTRACT_FIELDS,
|
||||
"route_count": len(route_reports),
|
||||
"routes": route_reports,
|
||||
"summary": {
|
||||
"valid_routes": len(route_reports) - len(invalid_routes),
|
||||
"invalid_routes": len(invalid_routes),
|
||||
"confidence_cap_policy": "enforced",
|
||||
},
|
||||
"boundary": (
|
||||
"Contract audit only; this does not prove VedAstro official raw "
|
||||
"response availability, endpoint health, API key validity, or quota."
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--json", action="store_true", help="Emit JSON. Kept for CLI symmetry.")
|
||||
args = parser.parse_args()
|
||||
_ = args
|
||||
print(json.dumps(build_audit_report(), ensure_ascii=False, indent=2, sort_keys=True))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -487,11 +487,11 @@ def schema() -> dict[str, Any]:
|
||||
},
|
||||
"time": {
|
||||
"__vedastro_type__": "Time",
|
||||
"year": REDACTED_YEAR,
|
||||
"month": 4,
|
||||
"day": 17,
|
||||
"hour": 14,
|
||||
"minute": 49,
|
||||
"year": 1955,
|
||||
"month": 2,
|
||||
"day": 24,
|
||||
"hour": 19,
|
||||
"minute": 15,
|
||||
"offset": 8,
|
||||
"geolocation": {
|
||||
"__vedastro_type__": "GeoLocation",
|
||||
|
||||
Reference in New Issue
Block a user