"""Stage a verified public release using an explicit allowlist, without credentials.""" from __future__ import annotations import argparse import hashlib import json import re import shutil import xml.etree.ElementTree as ET from datetime import datetime, timezone from pathlib import Path from codelock_affect.vectors import VectorBank ROOT_FILES = ( "README.md", "LICENSE", "NOTICE", "pyproject.toml", "requirements.txt", "Makefile", "MANIFEST.in", ".gitignore", ".gitattributes", "adapter-release.json", "adapter_config.json", "adapter_model.safetensors", "added_tokens.json", "chat_template.jinja", "merges.txt", "special_tokens_map.json", "tokenizer.json", "tokenizer_config.json", "vocab.json", ) PUBLIC_DIRS = ( "codelock_affect", "scripts", "tests", "configs", "data", "docs", "vectors", "results", ) SUFFIXES = {".py", ".json", ".jsonl", ".md", ".txt", ".sh", ".safetensors", ".xml"} def release_files(root): paths = [root / name for name in ROOT_FILES if (root / name).is_file()] for directory in PUBLIC_DIRS: paths.extend( path for path in (root / directory).rglob("*") if path.is_file() and path.suffix in SUFFIXES and not any( part.startswith(".") or part == "__pycache__" for part in path.relative_to(root).parts ) ) return sorted(paths, key=lambda path: path.relative_to(root).as_posix()) def build_release(root, output=None): root = Path(root).resolve() bank = VectorBank.load(root / "vectors/multichannel") if set(bank.vectors) != {"pain", "fear", "anxiety", "relief"}: raise ValueError("The v0.2 release requires all four channels") data_hash = hashlib.sha256( (root / "data/affect_pairs.jsonl").read_bytes() ).hexdigest() if any( vector.meta.get("dataset_file_sha256") != data_hash for vector in bank.vectors.values() ): raise ValueError("Calibration vectors do not match the current dataset") suites = ET.parse(root / "results/v2/tests.xml").getroot().iter("testsuite") counts = [dict(suite.attrib) for suite in suites] if not counts or any( int(suite.get("failures", 0)) or int(suite.get("errors", 0)) for suite in counts ): raise ValueError("A passing test report is required") replay = json.loads((root / "results/v2/replay.json").read_text(encoding="utf-8")) if not replay.get("complete") or any( "generation_context" not in row for row in replay.get("steps", []) ): raise ValueError("The event-grounded replay is incomplete") evaluation = json.loads( (root / "results/v2/evaluation.json").read_text(encoding="utf-8") ) if not evaluation.get("complete"): raise ValueError("Calibration evaluation must be complete") for seed in (7, 23, 41): result = json.loads( (root / f"results/v2/recommended-seed{seed}.json").read_text( encoding="utf-8" ) ) if not result.get("complete"): raise ValueError(f"Recommended evaluation seed {seed} is incomplete") stamp = datetime.now(timezone.utc).strftime("%Y%m%d-%H%M%S") output = ( Path(output).resolve() if output else root / ".local" / "release-staging" / stamp ) if output.exists() and any(output.iterdir()): raise ValueError( "Release output must be empty; an earlier bundle will not be overwritten" ) # Keep generated files outside the public allowlist to avoid recursive staging. if output.is_relative_to(root) and output.relative_to(root).parts[0] in PUBLIC_DIRS: raise ValueError("Release staging cannot be inside a public source directory") output.mkdir(parents=True, exist_ok=True) manifest = { "version": "0.2.0", "created_utc": datetime.now(timezone.utc).isoformat(), "base_model": "Qwen/Qwen3-8B", "contains_base_weights": False, "files": {}, } token_pattern = re.compile( r"(?:hf_[A-Za-z0-9]{20,}|tsk_[A-Za-z0-9_-]{20,}|-----BEGIN (?:OPENSSH |RSA |EC )?PRIVATE KEY-----)" ) for path in release_files(root): if path.is_symlink() or not path.resolve().is_relative_to(root): raise ValueError( f"Public file must remain inside the source directory: {path.name}" ) payload = path.read_bytes() if path.suffix != ".safetensors" and token_pattern.search( payload.decode("utf-8", errors="replace") ): raise ValueError( f"Credential-like content found in {path.relative_to(root)}; refusing publication" ) relative = path.relative_to(root) target = output / relative target.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(path, target) manifest["files"][relative.as_posix()] = { "sha256": hashlib.sha256(payload).hexdigest(), "bytes": len(payload), } (output / "release-manifest.json").write_bytes( (json.dumps(manifest, indent=2) + "\n").encode("utf-8") ) return output, manifest def main(): p = argparse.ArgumentParser(description=__doc__) p.add_argument("--output") args = p.parse_args() root = Path(__file__).resolve().parents[1] output, manifest = build_release(root, args.output) print( json.dumps( { "staging": str(output), "files": len(manifest["files"]), "bytes": sum(row["bytes"] for row in manifest["files"].values()), }, indent=2, ) ) if __name__ == "__main__": main()