"""Freeze exact input bytes, export the C++ trace, and bind both to a receipt.""" import hashlib import json import subprocess from pathlib import Path ROOT=Path(__file__).resolve().parents[1] def sha(data):return hashlib.sha256(data).hexdigest() def canonical(value):return json.dumps(value,sort_keys=True,separators=(',',':'),ensure_ascii=False).encode('utf-8') if __name__=='__main__': inputs=ROOT/'Tools/output/skill_slice_inputs';inputs.mkdir(parents=True,exist_ok=True) rows=[] for source,field in [('Config/Gameplay/greenfield.json','frozenGameplay'),('Config/Combat/skill_system_v1.proposal.json','skillDefinitions'),('Config/Combat/skill_slice.json','scenario')]: data=(ROOT/source).read_bytes();target=inputs/Path(source).name;target.write_bytes(data) rows.append(dict(source=source,snapshot=str(target.relative_to(ROOT)).replace('\\','/'),field=field,sourceSha256=sha(data),payloadSha256=sha(canonical(json.loads(data))))) target=ROOT/'AIClient/Assets/Bundles/Combat/SkillSlice/trace.json';target.parent.mkdir(parents=True,exist_ok=True) subprocess.run([str(ROOT/'AIServer/build-g1/Release/combat_slice_tests.exe'),*[str(ROOT/r['snapshot']) for r in rows],str(target)],cwd=ROOT,check=True) folder=ROOT/'Doc/Design/Combat/SkillSlice';folder.mkdir(parents=True,exist_ok=True) (folder/'export.json').write_text(json.dumps(dict(status='exported',inputs=rows,traceSha256=sha(target.read_bytes())),indent=2),encoding='utf-8')