54 lines
2.5 KiB
Python
54 lines
2.5 KiB
Python
"""Build the report-facing projection of birth-time sensitivity evidence."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from copy import deepcopy
|
|
from hashlib import sha256
|
|
import json
|
|
from typing import Any, Mapping
|
|
|
|
try:
|
|
from flexible_birth_time_profile import _candidate_window_authority_violation
|
|
except ImportError: # pragma: no cover - package import
|
|
from scripts.flexible_birth_time_profile import _candidate_window_authority_violation
|
|
|
|
SCHEMA_VERSION = "jyotish.flexible_birth_time_full_report_projection.v1"
|
|
SUPPORT_SCHEMA_VERSION = "jyotish.flexible_birth_time_report_support.v1"
|
|
|
|
|
|
class FlexibleBirthTimeFullReportProjectionError(ValueError):
|
|
"""Raised when report support cannot be projected safely."""
|
|
|
|
|
|
def build_flexible_birth_time_full_report_projection(support: Mapping[str, Any]) -> dict[str, Any]:
|
|
packet = _validate_support(support)
|
|
window = deepcopy(dict(packet.get("birth_time_window") or {}))
|
|
return {
|
|
"schema_version": SCHEMA_VERSION,
|
|
"projection_id": _digest_id(str(packet.get("support_id")), json.dumps(window, sort_keys=True, separators=(",", ":"))),
|
|
"report_section_type": "birth_time_sensitivity",
|
|
"window": window,
|
|
"stable_structure_section": deepcopy(dict(packet.get("stable_report_evidence") or {})),
|
|
"minute_sensitive_section": deepcopy(dict(packet.get("sensitive_report_evidence") or {})),
|
|
"theme_sensitivity": deepcopy(dict(packet.get("theme_sensitivity") or {})),
|
|
"trace": deepcopy(list(packet.get("trace") or [])),
|
|
"status": "candidate_window_only",
|
|
"claim_boundary": str(packet.get("claim_boundary") or "Sensitivity remains conditional."),
|
|
}
|
|
|
|
|
|
def _validate_support(value: Mapping[str, Any]) -> dict[str, Any]:
|
|
violation = _candidate_window_authority_violation(value)
|
|
if violation:
|
|
raise FlexibleBirthTimeFullReportProjectionError(f"candidate_window_authority_forbidden:{violation}")
|
|
if not isinstance(value, Mapping) or value.get("schema_version") != SUPPORT_SCHEMA_VERSION:
|
|
raise FlexibleBirthTimeFullReportProjectionError("flexible_birth_time_report_support_schema_invalid")
|
|
if value.get("status") != "candidate_window_only":
|
|
raise FlexibleBirthTimeFullReportProjectionError("support_must_remain_candidate_window_only")
|
|
return dict(value)
|
|
|
|
|
|
def _digest_id(*parts: str) -> str:
|
|
payload = json.dumps(parts, ensure_ascii=True, separators=(",", ":"))
|
|
return f"flex-report-projection://{sha256(payload.encode('utf-8')).hexdigest()[:24]}"
|