#!/usr/bin/env python3 """Import one real model run into the evidence packet without altering source files.""" import argparse, hashlib, json, re, shutil, tempfile from datetime import datetime from pathlib import Path SAFE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{1,79}$") def sha256(data: bytes) -> str: return hashlib.sha256(data).hexdigest() def iso8601(value: str) -> str: datetime.fromisoformat(value.replace("Z", "+00:00")) return value def import_run(root, family, run_id, prompt_path, response_path, provider, model_identifier, collected_at, interface, sampling, adaptation): root=Path(root).resolve(); prompt_path=Path(prompt_path); response_path=Path(response_path) for label,value in (("family",family),("run_id",run_id)): if not SAFE.fullmatch(value): raise ValueError(f"unsafe {label}") canonical=(root/"canonical-prompt.txt").read_bytes() prompt=prompt_path.read_bytes(); response=response_path.read_bytes() if not response.strip(): raise ValueError("response is empty") canonical_hash=sha256(canonical); prompt_hash=sha256(prompt); response_hash=sha256(response) if prompt_hash == canonical_hash and adaptation is not None: raise ValueError("adaptation must be omitted for a byte-identical canonical prompt") if prompt_hash != canonical_hash and not adaptation: raise ValueError("changed prompt requires a non-empty adaptation note") iso8601(collected_at) try: sampling_obj=json.loads(sampling) except json.JSONDecodeError as e: raise ValueError(f"sampling must be JSON: {e}") from e if not isinstance(sampling_obj,dict): raise ValueError("sampling must be a JSON object") destination=root/"raw"/family/run_id if destination.exists(): raise FileExistsError(f"run already exists: {destination}") destination.parent.mkdir(parents=True,exist_ok=True) metadata={ "run_id":run_id,"provider":provider,"model_family":family, "model_identifier":model_identifier,"collected_at":collected_at, "interface":interface,"canonical_prompt_sha256":canonical_hash, "adaptation":adaptation,"sampling_parameters":sampling_obj, "response_sha256":response_hash } tmp=Path(tempfile.mkdtemp(prefix=f".{run_id}-",dir=destination.parent)) try: (tmp/"prompt.txt").write_bytes(prompt) (tmp/"response.md").write_bytes(response) (tmp/"metadata.json").write_text(json.dumps(metadata,ensure_ascii=False,indent=2)+"\n",encoding="utf-8") (tmp/"sha256.txt").write_text(f"{prompt_hash} prompt.txt\n{response_hash} response.md\n",encoding="utf-8") tmp.rename(destination) except Exception: shutil.rmtree(tmp,ignore_errors=True); raise return destination def main(): p=argparse.ArgumentParser(description=__doc__) p.add_argument("root"); p.add_argument("--family",required=True); p.add_argument("--run-id",required=True) p.add_argument("--prompt",required=True); p.add_argument("--response",required=True) p.add_argument("--provider",required=True); p.add_argument("--model-identifier",required=True) p.add_argument("--collected-at",required=True); p.add_argument("--interface",required=True) p.add_argument("--sampling",default="{}"); p.add_argument("--adaptation") a=p.parse_args() print(import_run(a.root,a.family,a.run_id,a.prompt,a.response,a.provider,a.model_identifier,a.collected_at,a.interface,a.sampling,a.adaptation)) if __name__=="__main__": main()