#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ collatz_iterate_palier_protocol.py Deterministic "next palier" protocol generator for the hybrid chain C1→C2→C3. It does NOT run expensive computations. It inspects existing versioned artefacts and writes a checklist (JSON + MD) describing: - current certified palier for C3 (from verification JSON) - current max C2 completion transition (from verification JSON) - availability of local H6 directories at a chosen target palier - commands to generate / verify / report the next iteration (2^m → 2^(m+1)) Outputs are intended to be versioned under `docs/artefacts/`. """ from __future__ import annotations import argparse import json from dataclasses import dataclass from pathlib import Path def _read_json(path: Path) -> object: return json.loads(path.read_text(encoding="utf-8", errors="strict")) def _req_int(d: dict[str, object], key: str) -> int: v = d.get(key) if not isinstance(v, int): raise ValueError(f"Expected int for {key}") return v def _write_json(path: Path, obj: object) -> None: path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(obj, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") def _write_md(path: Path, lines: list[str]) -> None: path.parent.mkdir(parents=True, exist_ok=True) path.write_text("\n".join(lines) + "\n", encoding="utf-8") def _discover_local_h6_state_dirs(root: Path, palier: int) -> list[Path]: return sorted([p for p in root.glob(f"local_E*_palier2p{palier}") if p.is_dir()]) @dataclass(frozen=True) class ProtocolState: c3_palier: int c2_max_child_palier: int target_palier: int local_h6_states_found: int local_h6_missing_state_ids: list[int] def _load_c3_palier(c3_verification_json: Path) -> int: obj = _read_json(c3_verification_json) if not isinstance(obj, dict): raise ValueError("Invalid C3 verification JSON: expected object") domain = obj.get("domain") if not isinstance(domain, dict): raise ValueError("Invalid C3 verification JSON: missing domain") return _req_int(domain, "palier") def _load_c2_max_child_palier(c2_verification_json: Path) -> int: obj = _read_json(c2_verification_json) if not isinstance(obj, dict): raise ValueError("Invalid C2 verification JSON: expected object") transitions = obj.get("transitions") if not isinstance(transitions, list) or not all(isinstance(x, dict) for x in transitions): raise ValueError("Invalid C2 verification JSON: missing transitions") child_paliers = [_req_int(t, "palier_child") for t in transitions] if not child_paliers: raise ValueError("Invalid C2 verification JSON: empty transitions") return max(child_paliers) def _infer_state_id_from_dirname(dirname: str) -> int: # expected: local_E{sid}_palier2p{m} parts = dirname.split("_") for p in parts: if p.startswith("E") and p[1:].isdigit(): return int(p[1:]) raise ValueError(f"Cannot infer state id from {dirname}") def run( *, local_h6_root: Path, c2_verification_json: Path, c3_verification_json: Path, output_dir: Path, target_palier: int | None, ) -> None: c3_palier = _load_c3_palier(c3_verification_json) c2_max_child = _load_c2_max_child_palier(c2_verification_json) tgt = (c3_palier + 1) if target_palier is None else int(target_palier) if tgt < 13: raise ValueError("target_palier must be >= 13") found_dirs = _discover_local_h6_state_dirs(local_h6_root, tgt) found_ids = sorted({_infer_state_id_from_dirname(p.name) for p in found_dirs}) missing_ids = [sid for sid in range(1, 61) if sid not in found_ids] state = ProtocolState( c3_palier=c3_palier, c2_max_child_palier=c2_max_child, target_palier=tgt, local_h6_states_found=len(found_ids), local_h6_missing_state_ids=missing_ids, ) commands = { "C1_local_H6_generate": ( "python3 applications/collatz/collatz_k_scripts/collatz_generate_local_h6_artefacts.py " f"--docs-dir docs --output-root docs/artefacts/collatz --state-ids all " f"--palier-start {tgt} --palier-max {tgt} " "--t-min 9 --t-max 120 --write-index --index-path docs/artefacts/collatz/local_H6_index.md" ), "C3_verify_local_descent": ( "python3 applications/collatz/collatz_k_scripts/collatz_verify_c3_local_descent.py " "--local-h6-root docs/artefacts/collatz " "--output-dir docs/artefacts/collatz/c3_local_descent " f"--palier {tgt}" ), "Universal_clauses_extract": ( "python3 applications/collatz/collatz_k_scripts/collatz_extract_universal_clauses.py " f"--verification-json docs/artefacts/collatz/c3_local_descent/verification_c3_local_descent_palier2p{tgt}.json " "--output-dir docs/artefacts/collatz/universal_clauses" ), "Universal_clauses_verify": ( "python3 applications/collatz/collatz_k_scripts/collatz_verify_universal_clauses.py " f"--verification-json docs/artefacts/collatz/c3_local_descent/verification_c3_local_descent_palier2p{tgt}.json " "--clauses-json docs/artefacts/collatz/universal_clauses/clauses_universelles.json " "--output-dir docs/artefacts/collatz/universal_clauses" ), "C2_verify_projective": ( "python3 applications/collatz/collatz_k_scripts/collatz_verify_c2_projective.py " "--repo-root /home/ncantu/code/algo --output-dir docs/artefacts/collatz/c2_projective" ), } out_obj = { "inputs": { "local_h6_root": str(local_h6_root), "c2_verification_json": str(c2_verification_json), "c3_verification_json": str(c3_verification_json), }, "state": { "c3_palier": state.c3_palier, "c2_max_child_palier": state.c2_max_child_palier, "target_palier": state.target_palier, "local_h6_states_found": state.local_h6_states_found, "local_h6_missing_state_ids": state.local_h6_missing_state_ids, }, "commands": commands, } output_dir.mkdir(parents=True, exist_ok=True) out_json = output_dir / "iteration_protocol.json" out_md = output_dir / "iteration_protocol.md" _write_json(out_json, out_obj) md: list[str] = [] md.append("**Auteur** : Équipe 4NK") md.append("") md.append("# Protocole déterministe — itération de palier (C1→C2→C3)") md.append("") md.append("## État courant (artefacts)") md.append("") md.append(f"- C3 palier certifié : 2^{state.c3_palier} (d’après `{c3_verification_json}`)") md.append(f"- C2 transition max auditée : palier enfant 2^{state.c2_max_child_palier} (d’après `{c2_verification_json}`)") md.append("") md.append("## Palier cible") md.append("") md.append(f"- palier cible : 2^{state.target_palier}") md.append(f"- H6 locale présente (états) : {state.local_h6_states_found}/60") if state.local_h6_missing_state_ids: md.append(f"- états manquants : {state.local_h6_missing_state_ids}") md.append("") md.append("## Étapes (commandes reproductibles)") md.append("") for k, cmd in commands.items(): md.append(f"- **{k}** :") md.append("") md.append("```bash") md.append(cmd) md.append("```") md.append("") md.append("## Notes") md.append("") md.append("- Pour `C3_verify_local_descent` : si `palier != 13`, les sorties attendues sont suffixées `..._palier2p.{json,md}`.") md.append("- La génération de run reports (sha256 + compteurs) pour des paliers `m != 13` peut nécessiter l’extension du profil `c3_local_descent` du générateur de rapports.") _write_md(out_md, md) def main() -> None: ap = argparse.ArgumentParser(description="Generate a deterministic next-palier protocol for C1→C2→C3") ap.add_argument("--local-h6-root", default="docs/artefacts/collatz", help="Root containing local_E*_palier2p/ dirs") ap.add_argument("--c2-verification-json", default="docs/artefacts/collatz/c2_projective/verification_c2_projective.json") ap.add_argument("--c3-verification-json", default="docs/artefacts/collatz/c3_local_descent/verification_c3_local_descent.json") ap.add_argument("--output-dir", default="docs/artefacts/collatz/iteration_protocol") ap.add_argument("--target-palier", default="", help="Override target palier m (defaults to c3_palier+1)") args = ap.parse_args() tgt = int(args.target_palier) if args.target_palier.strip() else None run( local_h6_root=Path(args.local_h6_root).resolve(), c2_verification_json=Path(args.c2_verification_json).resolve(), c3_verification_json=Path(args.c3_verification_json).resolve(), output_dir=Path(args.output_dir).resolve(), target_palier=tgt, ) if __name__ == "__main__": main()