"""Exercise setup capture and drift refusal; never start model training.""" import argparse import copy import json from pathlib import Path import shutil import tempfile from unittest.mock import patch from capture_job import HERE, FILES, capture, verify, identity def record(): baseline = capture() matched = verify(baseline, identity(baseline)) probes = [] for name in ('configuration', 'dataset', 'trainer'): with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) for file in FILES: target = root / file target.parent.mkdir(parents=True, exist_ok=True) shutil.copyfile(HERE / file, target) if name == 'configuration': path = root / 'job-config.json' config = json.loads(path.read_text()); config['epochs'] = 201 path.write_text(json.dumps(config) + '\n') else: path = root / ('trainer/rice.csv' if name == 'dataset' else 'trainer/baseline.py') path.write_bytes(path.read_bytes() + b'\n') try: verify(baseline, identity(baseline), root) except ValueError as error: probes.append({'changed': name, 'refused': True, 'reason': str(error)}) else: raise AssertionError('changed setup was accepted') # An explicitly simulated runtime metadata difference exercises the verifier. # This does not claim that a second Python interpreter was installed or used. changed = dict(baseline['runtime'], python_version='simulated-other-version') with patch('capture_job.describe_runtime', return_value=changed): try: verify(baseline, identity(baseline)) except ValueError as error: probes.append({'changed': 'simulated runtime metadata', 'refused': True, 'reason': str(error)}) else: raise AssertionError('runtime metadata difference was accepted') return {'mode': 'local setup inspection; no training, metric computation or model calls', 'snapshot': baseline, 'verified': matched, 'probes': probes} def portable_checks(result): """Check portable behavior; runtime enforcement is tested by verify(), not waived.""" stable = copy.deepcopy(result) stable['snapshot'].pop('runtime') stable['verified'].pop('recipe_id') # Derived from the runtime as well as the files. return stable def main(): parser = argparse.ArgumentParser() parser.add_argument('--check', action='store_true') parser.add_argument('--save', type=Path) args = parser.parse_args(); result = record() if args.check and portable_checks(result) != portable_checks(json.loads((HERE / 'result.json').read_text())): raise SystemExit('portable setup checks differ from the recorded result') if args.save: args.save.write_text(json.dumps(result, indent=2) + '\n') snapshot = result['snapshot'] print('Setup capture only: training_started=False; no new metrics') print('Trainer imports:', ', '.join(snapshot['dependencies']['trainer_direct_imports'])) print('Third-party packages:', len(snapshot['dependencies']['third_party'])) config = snapshot['effective_config'] print(f"Effective settings: epochs={config['epochs']}; learning_rate={config['learning_rate']}; mode={config['mode']}") print('Current captured setup verifies:', result['verified']['setup_matches']) for row in result['probes']: print(row['changed'] + ': refused=' + str(row['refused'])) print('Runtime is recorded in result.json; --check compares portable checks only.') print('Use capture_job.py verify to enforce your own captured runtime and input identity.') if __name__ == '__main__': main()