from __future__ import annotations import hashlib import json import os from pathlib import Path from typing import Any BEHAVIOR_PATHS = ( "answering.py", "engine.py", "clause_retrieval.py", "normative_runtime.py", "normative_status.py", "release_identity.py", "source_router.py", "proof_bundle.py", "hybrid_retrieval.py", "query_understanding.py", "clarification.py", "conversation_intent.py", "sources.py", "llm.py", "decision_runtime.py", "normative_metadata.py", "prompts.py", "config.py", "ui_gradio.py", "institution_onboarding.py", "normative_contract.py", "ontology.py", "rdfox_pilot.py", "requirements.txt", "data/registry/document_semantic_profiles.json", "data/registry/normative_decision_contracts.json", "data/registry/normative_relations.json", "data/registry/legal_documents.json", "data/mckf/mckf_shapes.ttl", ) def compute_release_manifest(root: Path, corpus_build_id: str) -> dict[str, Any]: artifacts: dict[str, dict[str, Any]] = {} for relative in BEHAVIOR_PATHS: path = root / relative if not path.exists(): continue payload = path.read_bytes() artifacts[relative] = { "sha256": hashlib.sha256(payload).hexdigest(), "bytes": len(payload), } models = { "provider": os.getenv("LLM_PROVIDER", "auto"), "hf": os.getenv("HF_MODEL") or os.getenv("GEN_MODEL", "Qwen/Qwen2.5-7B-Instruct"), "groq": os.getenv("GROQ_MODEL", "openai/gpt-oss-120b"), "openai": os.getenv("OPENAI_MODEL", "gpt-4o-mini"), } material = json.dumps( {"corpus_build_id": corpus_build_id, "artifacts": artifacts, "models": models}, ensure_ascii=False, sort_keys=True, separators=(",", ":"), ) release_id = "mitranlil-" + hashlib.sha256(material.encode("utf-8")).hexdigest()[:20] return { "schema": "MCKF-RuntimeRelease-v1.0", "release_id": release_id, "corpus_build_id": corpus_build_id, "behavior_artifacts": artifacts, "configured_models": models, }