"""Build the governed reference object for a PL9-grade full personal report. The authority is intentionally a compact, read-only reference envelope. It does not duplicate raw worksheets, render Markdown, alter quality-gate results, or publish a report. Consumers use its stable identity and references to locate the already assembled PL9 export packet through an approved transport layer. """ from __future__ import annotations import hashlib import json from typing import Any AUTHORITY_SCHEMA_VERSION = "jyotish.shared_full_report_authority.v1" REPORT_SCHEMA_VERSION = "expert_report_output.v2" DEFAULT_REPORT_VERSION = "pl9_personal_long_report.v2" PL9_EXPORT_SCHEMA = "pl9_style_professional_export_v1" QUALITY_GATE_SCHEMA = "jyotish.full_report_quality_gate.v1" def build_shared_full_report_authority( packet: dict[str, Any], *, expert_judgment_output: dict[str, Any] | None = None, ) -> dict[str, Any]: """Create a compact authority envelope without mutating an export packet. A quality-gate result is mandatory, but it is not a publication approval. Every non-blocked authority remains ``review_required`` until a future governed review/promotion flow authorizes a consumer surface. """ source = _require_mapping(packet, "packet") _require_value(source.get("schema"), "packet.schema") if source.get("schema") != PL9_EXPORT_SCHEMA: raise ValueError(f"packet.schema must be {PL9_EXPORT_SCHEMA}") profile = _require_mapping(source.get("calculation_profile"), "calculation_profile") profile_id = _require_value( source.get("calculation_profile_id") or profile.get("profile_id"), "calculation_profile_id", ) result_hash = _require_value(source.get("result_hash"), "result_hash") full_report_pack = _require_mapping(source.get("full_report_pack"), "full_report_pack") full_report_pack_schema = _require_value(full_report_pack.get("schema"), "full_report_pack.schema") quality_gate = _require_mapping(source.get("report_quality_gate"), "report_quality_gate") if quality_gate.get("schema_version") != QUALITY_GATE_SCHEMA: raise ValueError(f"report_quality_gate.schema_version must be {QUALITY_GATE_SCHEMA}") report_version = str(source.get("report_version") or DEFAULT_REPORT_VERSION) chart_identity = _build_chart_identity(source, profile, profile_id) identity_seed = { "report_schema_version": REPORT_SCHEMA_VERSION, "report_version": report_version, "calculation_profile_id": profile_id, "result_hash": result_hash, "full_report_pack_schema": full_report_pack_schema, # The same calculation payload can be reached from different chart # identity states. Keep those authorities distinct rather than letting # an unreviewed and an approved chart share one report reference. "chart_profile_id": chart_identity["chart_profile_id"], "rectification_status": chart_identity["rectification_status"], "approval_status": chart_identity["approval_status"], } identity_digest = _digest(identity_seed) report_id = f"full-report://{profile_id}/{identity_digest[:24]}" quality_gate_reference = _build_quality_gate_reference(quality_gate) status, publication_status = _derive_status(quality_gate_reference["status"]) sections = _require_mapping(full_report_pack.get("sections"), "full_report_pack.sections") report_pack_manifest = _as_mapping(source.get("report_pack_manifest")) pack_ids = [ str(pack.get("id")) for pack in report_pack_manifest.get("packs", []) if isinstance(pack, dict) and pack.get("id") ] judgment_lineage = _build_judgment_lineage(expert_judgment_output) limitations = _build_limitations(source, quality_gate_reference, chart_identity, judgment_lineage) return { "schema_version": AUTHORITY_SCHEMA_VERSION, "authority_id": f"shared-full-report://{identity_digest[:24]}", "report_id": report_id, "report_version": report_version, "report_contract_version": REPORT_SCHEMA_VERSION, "status": status, "publication_status": publication_status, "read_only": True, "report_metadata": { "generated_at": source.get("generated_at"), "generated_at_status": "recorded" if source.get("generated_at") else "not_recorded", }, "chart_identity": chart_identity, "lineage": { "source_schema": source.get("schema"), "calculation_profile_id": profile_id, "result_hash": result_hash, "full_report_pack_schema": full_report_pack_schema, "report_pack_ids": pack_ids, "source_reference": "pl9_export_packet", }, "quality_gate_reference": quality_gate_reference, "content_reference": { "full_report_pack_schema": full_report_pack_schema, "section_keys": list(sections.keys()), "professional_support_reference": _build_professional_support_reference( sections.get("professional_support") ), "professional_coverage_reference": _build_professional_coverage_reference( quality_gate.get("professional_coverage_manifest") ), "full_report_body_authority": _build_full_report_body_authority( sections=sections, professional_support=sections.get("professional_support"), professional_coverage_manifest=quality_gate.get("professional_coverage_manifest"), ), "available_render_formats": ["markdown", "reader-markdown", "pdf"], "contains_raw_calculation": False, "contains_shadow_artifact": False, }, "surface_slices": _build_surface_slices(report_id), "limitations": limitations, "judgment_lineage": judgment_lineage, "publication_boundary": ( "This reference does not publish, promote, render, or replace any " "existing report consumer. It remains review-only until a governed " "promotion path explicitly authorizes a surface." ), } def _require_mapping(value: Any, name: str) -> dict[str, Any]: if not isinstance(value, dict) or not value: raise ValueError(f"{name} is required") return value def _as_mapping(value: Any) -> dict[str, Any]: return value if isinstance(value, dict) else {} def _require_value(value: Any, name: str) -> str: if value in (None, ""): raise ValueError(f"{name} is required") return str(value) def _digest(value: dict[str, Any]) -> str: encoded = json.dumps(value, ensure_ascii=True, sort_keys=True, separators=(",", ":"), default=str) return hashlib.sha256(encoded.encode("utf-8")).hexdigest() def _build_quality_gate_reference(quality_gate: dict[str, Any]) -> dict[str, Any]: status = str(quality_gate.get("status") or "review_required") reference_payload = { "schema_version": quality_gate.get("schema_version"), "status": status, "blocking_reasons": list(quality_gate.get("blocking_reasons") or []), "review_reasons": list(quality_gate.get("review_reasons") or []), "warning_reasons": list(quality_gate.get("warning_reasons") or []), "audit_reference": _as_mapping(quality_gate.get("audit_reference")), } return { **reference_payload, "quality_gate_reference_id": f"report-quality-gate://{_digest(reference_payload)[:24]}", } def _derive_status(quality_gate_status: str) -> tuple[str, str]: if quality_gate_status == "blocked": return "blocked", "blocked" return "review_required", "pending_review" def _build_chart_identity( packet: dict[str, Any], profile: dict[str, Any], profile_id: str, ) -> dict[str, Any]: existing = _as_mapping(packet.get("chart_identity")) return { "chart_profile_id": existing.get("chart_profile_id") or profile_id, "birth_data_status": existing.get("birth_data_status") or packet.get("birth_data_status") or "user_provided", "rectification_status": existing.get("rectification_status") or packet.get("rectification_status") or "not_reviewed", "approval_status": existing.get("approval_status") or packet.get("approval_status") or "not_approved", "calculation_profile_reference": profile.get("profile_id") or profile_id, } def _build_limitations( packet: dict[str, Any], quality_gate_reference: dict[str, Any], chart_identity: dict[str, Any], judgment_lineage: dict[str, Any], ) -> list[dict[str, str]]: limitations = [ { "type": "publication_review_required", "detail": "A quality-gate result is advisory and cannot publish a report automatically.", }, ] if judgment_lineage.get("status") != "attached": limitations.append( { "type": "judgment_lineage_not_attached", "detail": "The current PL9 packet is not yet linked to a production ExpertJudgmentOutput reference.", } ) if quality_gate_reference.get("status") != "passed": limitations.append( { "type": "quality_gate_not_clean_pass", "detail": f"Quality gate status is {quality_gate_reference.get('status')}.", } ) if chart_identity.get("approval_status") != "approved": limitations.append( { "type": "chart_identity_not_approved", "detail": f"Chart approval status is {chart_identity.get('approval_status')}.", } ) if not packet.get("generated_at"): limitations.append( { "type": "generation_timestamp_not_recorded", "detail": "The source export did not supply a generated_at timestamp.", } ) return limitations def _build_judgment_lineage(expert_judgment_output: dict[str, Any] | None) -> dict[str, Any]: output = expert_judgment_output if isinstance(expert_judgment_output, dict) else {} if not output: return { "status": "not_attached", "boundary": ( "Current PL9 export is a governed report candidate. A future " "ExpertJudgmentOutput reference is required before it can claim " "judgment-backed production authority." ), } return { "status": "attached", "schema_version": output.get("schema_version"), "judgment_id": output.get("judgment_id"), "judgment_status": output.get("status"), "promotion_state": ((output.get("review_metadata") or {}).get("promotion_state") if isinstance(output.get("review_metadata"), dict) else None) or "unknown", "review_status": ((output.get("review_metadata") or {}).get("review_status") if isinstance(output.get("review_metadata"), dict) else None) or "unknown", "audit_reference": _as_mapping(output.get("audit_reference")), "boundary": ( "A governed ExpertJudgmentOutput reference is attached. Publication and promotion still require " "their own review boundary." ), } def _build_surface_slices(report_id: str) -> dict[str, dict[str, Any]]: return { "simple_view": { "authority_mode": "reference_only", "report_reference": report_id, "allowed_sections": ["Executive Summary", "Chart Identity", "Conflict and Limitation"], }, "deep_analysis_view": { "authority_mode": "reference_only", "report_reference": report_id, "allowed_sections": [ "Core Promise Analysis", "Strength Analysis", "Domain Analysis", "Varga Analysis", "Dasha Analysis", "KP and Transit Timing Layer", "Annual / Tajika / Yearly Focus", "Three-Year Ephemeris and Predictive Outlook", "Conflict and Limitation", "Evidence Summary", ], }, "expert_workspace": { "authority_mode": "reference_only", "report_reference": report_id, "allowed_sections": ["all_governed_sections", "Operator Appendix / Audit Appendix"], }, } def _build_professional_support_reference(section: Any) -> dict[str, Any]: topic_section = section if isinstance(section, dict) else {} topics = topic_section.get("topics") if isinstance(topic_section.get("topics"), dict) else {} topic_statuses = { str(key): str(value.get("status") or "blocked") for key, value in topics.items() if isinstance(value, dict) } restricted = topics.get("restricted_research_materials") if isinstance(topics.get("restricted_research_materials"), dict) else {} materials = restricted.get("materials") if isinstance(restricted.get("materials"), dict) else {} restricted_material_visibility = sorted( key for key, value in materials.items() if isinstance(value, dict) and value.get("status") not in (None, "", "not_available") ) body_authority_topics = sorted( key for key, value in topics.items() if key != "restricted_research_materials" and isinstance(value, dict) and value.get("status") not in (None, "", "blocked", "not_available") ) appendix_only_topics = sorted( key for key, value in topics.items() if isinstance(value, dict) and ( key == "restricted_research_materials" or value.get("status") in (None, "", "blocked", "not_available") ) ) return { "status": topic_section.get("status") or "blocked", "topic_statuses": topic_statuses, "body_authority_topics": body_authority_topics, "appendix_only_topics": appendix_only_topics, "restricted_material_visibility": restricted_material_visibility, } def _build_professional_coverage_reference(manifest: Any) -> list[dict[str, str]]: rows = manifest if isinstance(manifest, list) else [] normalized: list[dict[str, str]] = [] for row in rows: if not isinstance(row, dict): continue material_id = row.get("material_id") status = row.get("status") source_reference = row.get("source_reference") if material_id in (None, ""): continue normalized.append( { "material_id": str(material_id), "status": str(status or "unknown"), "source_reference": str(source_reference or ""), } ) return normalized def _build_full_report_body_authority( *, sections: dict[str, Any], professional_support: Any, professional_coverage_manifest: Any, ) -> dict[str, Any]: section_statuses = { str(key): str(value.get("status") or "blocked") for key, value in sections.items() if isinstance(value, dict) } professional_support_reference = _build_professional_support_reference(professional_support) coverage_rows = _build_professional_coverage_reference(professional_coverage_manifest) body_sections = [ key for key, status in section_statuses.items() if key not in {"audit_appendix", "professional_support"} and status not in {"blocked", "not_available"} ] restricted_topics = list(professional_support_reference.get("restricted_material_visibility") or []) body_authority_topics = list(professional_support_reference.get("body_authority_topics") or []) appendix_only_topics = list(professional_support_reference.get("appendix_only_topics") or []) topic_promotion_state = { topic: ( "body_authority" if topic in body_authority_topics else "restricted_registry" if topic in restricted_topics else "appendix_only" ) for topic in sorted(set(body_authority_topics + restricted_topics + appendix_only_topics)) } return { "status": "authority_topics_promoted" if body_sections or body_authority_topics or coverage_rows else "blocked", "body_sections": body_sections, "body_authority_topics": body_authority_topics, "restricted_professional_topics": restricted_topics, "appendix_only_topics": appendix_only_topics, "topic_promotion_state": topic_promotion_state, "coverage_manifest_material_ids": [row["material_id"] for row in coverage_rows], "coverage_manifest_authority_materials": [ { "material_id": row["material_id"], "status": row["status"], "source_reference": row["source_reference"], "promotion_state": "body_authority_reference" if row["status"] not in {"blocked", "not_available"} else "appendix_only", } for row in coverage_rows ], "boundary": ( "This layer tracks which high-value support and coverage materials have an explicit body-authority " "or restricted-professional registration inside the long-report contract. It does not auto-promote " "parameter-sensitive or blocked material into judgment authority." ), }