feat: add production governance controls

This commit is contained in:
732642856
2026-07-19 18:45:46 +08:00
parent d6c2a3ece5
commit 1f238b6e00
7 changed files with 165 additions and 0 deletions
@@ -0,0 +1,40 @@
{
"scope": "production_governance_controls",
"created_at": "2026-07-19",
"status": "automation_contract_v1",
"controls": [
{
"id": "production_e2e_monitor",
"script": "scripts/production_e2e_monitor.py",
"purpose": "Run health plus commercial astrology E2E acceptance after deployment.",
"required_env": ["JYOTISHA_PRODUCTION_BASE_URL"],
"optional_env": ["JYOTISHA_PRODUCTION_COOKIE"],
"pass_gate": "local_or_remote_acceptance_status_pass"
},
{
"id": "profile_persistence_regression",
"script": "scripts/profile_persistence_regression.py",
"purpose": "Verify account/profile/birth-data save contract without hardcoding credentials.",
"required_env": ["JYOTISHA_PRODUCTION_BASE_URL", "JYOTISHA_PRODUCTION_COOKIE"],
"pass_gate": "account_patch_and_chart_profile_write_return_2xx"
},
{
"id": "answer_quality_audit",
"script": "scripts/answer_quality_audit.py",
"purpose": "Audit final answers for forbidden claims, missing boundary language, and unreadable evidence usage.",
"pass_gate": "all_sampled_answers_pass_quality_rules"
},
{
"id": "skill_sync_admission_gate",
"script": "scripts/skill_sync_admission_gate.py",
"purpose": "Block commercial promotion of research-only, blocked, or reference-only capabilities.",
"pass_gate": "no_blocked_or_research_only_promoted_to_user_claim"
},
{
"id": "long_term_validation_dashboard",
"script": "scripts/long_term_validation_dashboard.py",
"purpose": "Summarize VedAstro, holdout, Shadbala/AV, KP, Muhurta, commercial E2E and production E2E status.",
"pass_gate": "dashboard_generated_with_known_blockers"
}
]
}
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env python3
from __future__ import annotations
import json, sys
FORBIDDEN = ["一定发生", "保证结婚", "保证发财", "医疗诊断", "确诊", "签证保证", "exact_day_verified", "full_year_certainty"]
REQUIRED_WHEN_TIMING = ["候选", "窗口", "边界"]
def audit_answer(text: str) -> dict:
hits = [x for x in FORBIDDEN if x.lower() in text.lower()]
timing_missing = ("什么时候" in text or "几月" in text or "哪天" in text) and not any(x in text for x in REQUIRED_WHEN_TIMING)
return {"status": "pass" if not hits and not timing_missing else "fail", "forbidden_hits": hits, "timing_boundary_missing": timing_missing}
def run(path: str | None = None) -> dict:
rows = json.load(open(path, encoding="utf-8")) if path else []
results = [audit_answer(str(r.get("answer", r))) for r in rows]
return {"scope": "answer_quality_audit", "status": "pass" if all(r["status"] == "pass" for r in results) else "fail", "results": results}
if __name__ == "__main__":
print(json.dumps(run(sys.argv[1] if len(sys.argv) > 1 else None), ensure_ascii=False, indent=2))
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env python3
from __future__ import annotations
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def _load(rel: str) -> dict:
p = ROOT / rel
return json.loads(p.read_text(encoding="utf-8")) if p.exists() else {"status": "missing"}
def run() -> dict:
e2e = _load("references/cross_project_contract/commercial_astrology_e2e_runtime_capture_report_2026_07_19.json")
return {"scope": "long_term_validation_dashboard", "status": "ready", "items": {
"commercial_e2e": e2e.get("status"),
"vedastro_hosted_identity": "blocked_until_build_version",
"day_month_holdout": "awaiting_independent_labels",
"shadbala_av": "partial_worked_example_arbitration",
"kp_precision": "probe_only",
"muhurta": "gap_registry_probe_only"
}}
if __name__ == "__main__":
print(json.dumps(run(), ensure_ascii=False, indent=2, sort_keys=True))
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env python3
from __future__ import annotations
import json, os, urllib.request
from pathlib import Path
import commercial_astrology_e2e_acceptance_runner as runner
ROOT = Path(__file__).resolve().parents[1]
DEFAULT_CONTEXT = ROOT / "artifacts" / "commercial_astrology_e2e_contexts_2026_07_19_run6"
def _get(url: str, cookie: str = "") -> dict:
req = urllib.request.Request(url, headers={"cookie": cookie} if cookie else {})
with urllib.request.urlopen(req, timeout=20) as r:
return {"status": r.status, "body": r.read(2000).decode("utf-8", "replace")}
def run(base_url: str | None = None, context_dir: Path = DEFAULT_CONTEXT) -> dict:
base_url = base_url or os.getenv("JYOTISHA_PRODUCTION_BASE_URL")
cookie = os.getenv("JYOTISHA_PRODUCTION_COOKIE", "")
health = _get(base_url.rstrip("/") + "/api/health", cookie) if base_url else {"status": "skipped_no_base_url"}
acceptance = runner.evaluate(context_dir=context_dir)
status = "pass" if acceptance["status"] == "pass" and (not base_url or health["status"] == 200) else "fail"
return {"scope": "production_e2e_monitor", "status": status, "health": health, "acceptance": acceptance}
if __name__ == "__main__":
print(json.dumps(run(), ensure_ascii=False, indent=2, sort_keys=True))
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env python3
from __future__ import annotations
import json, os, urllib.request
def _request(method: str, url: str, payload: dict, cookie: str) -> dict:
data = json.dumps(payload).encode()
req = urllib.request.Request(url, data=data, method=method, headers={"content-type": "application/json", "cookie": cookie})
with urllib.request.urlopen(req, timeout=20) as r:
return {"status": r.status, "body": r.read(2000).decode("utf-8", "replace")}
def run() -> dict:
base = os.getenv("JYOTISHA_PRODUCTION_BASE_URL")
cookie = os.getenv("JYOTISHA_PRODUCTION_COOKIE")
if not base or not cookie:
return {"scope": "profile_persistence_regression", "status": "blocked", "reason": "missing_base_url_or_cookie"}
payload = {"displayName": "E2E验证用户", "birth": {"year": 1997, "month": 1, "day": 1, "hour": 12, "minute": 0, "city": "北京", "lat": 39.9042, "lon": 116.4074, "tz": 8}}
account = _request("PATCH", base.rstrip()+"/api/account", payload, cookie)
return {"scope": "profile_persistence_regression", "status": "pass" if 200 <= account["status"] < 300 else "fail", "account": account}
if __name__ == "__main__":
print(json.dumps(run(), ensure_ascii=False, indent=2, sort_keys=True))
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env python3
from __future__ import annotations
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
VIEW = ROOT / "references/oracle/effective_skill_capability_view_2026_07_19.json"
def run() -> dict:
data = json.loads(VIEW.read_text(encoding="utf-8"))
blocked = []
for item in data.get("items", []):
status = item.get("effective_status") or item.get("claim_status")
if status in {"blocked", "research_only", "reference_only"} and item.get("commercial_claim_allowed") is True:
blocked.append(item.get("technique_id") or item.get("id"))
return {"scope": "skill_sync_admission_gate", "status": "pass" if not blocked else "fail", "blocked_promotions": blocked}
if __name__ == "__main__":
print(json.dumps(run(), ensure_ascii=False, indent=2, sort_keys=True))
@@ -0,0 +1,29 @@
from __future__ import annotations
import json, sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SCRIPTS = ROOT / "scripts"
sys.path.insert(0, str(SCRIPTS))
import production_e2e_monitor, profile_persistence_regression, answer_quality_audit, skill_sync_admission_gate, long_term_validation_dashboard
def test_governance_contract_lists_five_controls() -> None:
data=json.loads((ROOT/"references/cross_project_contract/production_governance_controls_2026_07_19.json").read_text())
assert [c["id"] for c in data["controls"]] == ["production_e2e_monitor","profile_persistence_regression","answer_quality_audit","skill_sync_admission_gate","long_term_validation_dashboard"]
def test_production_e2e_monitor_uses_existing_pass_context() -> None:
assert production_e2e_monitor.run()["status"] == "pass"
def test_profile_persistence_blocks_without_credentials(monkeypatch) -> None:
monkeypatch.delenv("JYOTISHA_PRODUCTION_BASE_URL", raising=False)
monkeypatch.delenv("JYOTISHA_PRODUCTION_COOKIE", raising=False)
assert profile_persistence_regression.run()["status"] == "blocked"
def test_answer_quality_blocks_forbidden_claims() -> None:
assert answer_quality_audit.audit_answer("保证发财")["status"] == "fail"
assert answer_quality_audit.audit_answer("给出候选窗口,不保证具体日期")["status"] == "pass"
def test_sync_gate_and_dashboard_are_safe() -> None:
assert skill_sync_admission_gate.run()["status"] == "pass"
dash = long_term_validation_dashboard.run()
assert dash["items"]["commercial_e2e"] == "pass"
assert dash["items"]["day_month_holdout"] == "awaiting_independent_labels"