"""Run only after final review; build local payload without upload or deployment.""" from pathlib import Path import hashlib, json, shutil, tarfile folder=Path(__file__).resolve().parent plan=json.loads((folder/'patient-release-plan.json').read_text(encoding='utf-8-sig')) assert plan.get('finalized') is True, 'Root must finalize patient-release-plan.json first' assert plan['version']=='1.4.25' and plan.get('schemaMigration') is False allowed={'zyt_patient_client.py','archive_api.py','archive_store.py','admin_api.py'} assert set(plan['backendFiles'])==allowed source=Path(plan['candidateRoot']).resolve() base=json.loads((folder/'server-baseline-patient.json').read_text()) # Each patch must start from the exact live-server baseline, not the older Windows checkout. for name in allowed: before=folder/'before-backend'/name assert before.is_file(), 'Missing backend agent before-file: '+name assert hashlib.sha256(before.read_bytes()).hexdigest()==base['expected'][name], 'Server baseline differs: '+name assert hashlib.sha256((source/'admin_backend.py').read_bytes()).hexdigest()==base['expected']['admin_backend.py'], 'Unexpected Database module change' bundle=folder/'server-bundle' assert not bundle.exists(), 'Refusing to overwrite previous payload' bundle.mkdir() manifest=[] for name in sorted(allowed): data=(source/name).read_bytes(); compile(data,str(source/name),'exec') destination=bundle/'payload/wechat_rpa'/name;destination.parent.mkdir(parents=True,exist_ok=True);destination.write_bytes(data) manifest.append({'path':'wechat_rpa/'+name,'sha256':hashlib.sha256(data).hexdigest(),'bytes':len(data)}) for name in [m+'.py' for m in plan['serverTestModules']]+plan['testSupportFiles']: assert Path(name).name==name and name.endswith('.py'), name data=(source/name).read_bytes();compile(data,str(source/name),'exec') target=bundle/'tests'/name;target.parent.mkdir(exist_ok=True);target.write_bytes(data) manifest.append({'path':'tests/'+name,'sha256':hashlib.sha256(data).hexdigest(),'bytes':len(data)}) (bundle/'patient-manifest.json').write_text(json.dumps(manifest,indent=2),encoding='utf-8') for name in ['server-baseline-patient.json','patient-release-plan.json','Dockerfile.patient-overlay','patient_server_guard.py', '01-patient-preflight.sh','02-patient-backup-build.sh','03-patient-deploy.sh','04-patient-verify.sh','rollback-patient.sh']: shutil.copyfile(folder/name,bundle/name) archive=folder/'patient-server-bundle.tar.gz' assert not archive.exists() with tarfile.open(archive,'x:gz') as tf: for p in sorted(bundle.rglob('*')): if p.is_file():tf.add(p,arcname=p.relative_to(bundle).as_posix(),recursive=False) print(json.dumps({'archive':str(archive),'sha256':hashlib.sha256(archive.read_bytes()).hexdigest(),'overlayFiles':len(allowed),'uploaded':False}))