"""Run one frozen neural outer split so long training is restart-safe.""" from __future__ import annotations import argparse import json import sys from pathlib import Path import numpy as np import pandas as pd PROJECT_ROOT = Path(__file__).resolve().parents[2] if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) from revision.scripts.reanalysis_neural import run_neural_stack from revision.scripts.reanalysis_pipeline import ( _extract_features, _write_sha256_manifest, validate_config, ) from revision.scripts.run_revision_reanalysis import configure_utf8_console def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser( description="Train GAT, GCN, FPNN, and the fixed stack for one frozen outer split." ) parser.add_argument( "--config", default=str(PROJECT_ROOT / "revision" / "config" / "reanalysis.json"), ) parser.add_argument( "--artifacts-root", default=str(PROJECT_ROOT / "revision" / "artifacts" / "reviewer_requested_reanalysis_v4"), ) parser.add_argument("--strategy", required=True) parser.add_argument("--seed", required=True, type=int) return parser.parse_args() def main() -> int: configure_utf8_console() args = parse_args() config = validate_config( json.loads(Path(args.config).resolve().read_text(encoding="utf-8")), PROJECT_ROOT, ) if args.strategy not in config["split_strategies"]: raise ValueError(f"Unknown strategy: {args.strategy}") if args.seed not in config["outer_seeds"]: raise ValueError(f"Seed was not predeclared: {args.seed}") artifacts_root = Path(args.artifacts_root).resolve() expected_root = Path(config["output_root"]).resolve() if artifacts_root != expected_root: raise ValueError( f"Artifacts root must match the frozen config: {expected_root}" ) if not (artifacts_root / "SHA256SUMS.txt").is_file(): raise FileNotFoundError("Completed classical artifacts and SHA256SUMS.txt are required first.") annotated = pd.read_csv(artifacts_root / "record_identity_manifest.csv") descriptor_matrix, fingerprint_matrix = _extract_features( annotated, config["descriptor_features"], config["fingerprint"], ) split_dir = artifacts_root / args.strategy / f"seed_{args.seed}" split_data = np.load(split_dir / "split_indices.npz", allow_pickle=True) development = np.asarray(split_data["development_indices"], dtype=int) test = np.asarray(split_data["test_indices"], dtype=int) inner_train = split_data["inner_train_indices"] inner_validation = split_data["inner_validation_indices"] inner_folds = [ (np.asarray(train, dtype=int), np.asarray(validation, dtype=int)) for train, validation in zip(inner_train, inner_validation) ] output = run_neural_stack( config, annotated=annotated, descriptor_matrix=descriptor_matrix, fingerprint_matrix=fingerprint_matrix, train_indices=development, test_indices=test, inner_folds=inner_folds, output_dir=split_dir / "neural_stack", seed=args.seed, smoke_only=False, ) _write_sha256_manifest(artifacts_root) print(f"Completed frozen neural split: {output}") return 0 if __name__ == "__main__": raise SystemExit(main())