"""Check the C++ slice trace, immutable inputs, and TangoFlux audio provenance.""" import hashlib import json from pathlib import Path import numpy as np from scipy.io import wavfile from export_skill_slice import canonical ROOT=Path(__file__).resolve().parents[1] DESIGN=ROOT/'Doc/Design/Combat/SkillSlice' def main(): DESIGN.mkdir(parents=True,exist_ok=True) trace_path=ROOT/'AIClient/Assets/Bundles/Combat/SkillSlice/trace.json' trace=json.loads(trace_path.read_text(encoding='utf-8')) exported=json.loads((DESIGN/'export.json').read_text(encoding='utf-8')) assert hashlib.sha256(trace_path.read_bytes()).hexdigest()==exported['traceSha256'] for row in exported['inputs']: snapshot=(ROOT/row['snapshot']).read_bytes() assert hashlib.sha256(snapshot).hexdigest()==row['sourceSha256'] assert trace[row['field']]==json.loads(snapshot) assert hashlib.sha256(canonical(trace[row['field']])).hexdigest()==row['payloadSha256'] casts={};shots={};hits=set();deaths=set();last=-1 for seq,e in enumerate(trace['events']): assert e['seq']==seq and e['tick']>=last last=e['tick'];kind=e['kind'];cast=e.get('cast') if kind=='cast_start': assert cast not in casts casts[cast]=e elif kind=='release': assert e['tick']==casts[cast]['release'] elif kind=='projectile': key=(cast,e['target']);assert key not in shots shots[key]=e assert e['arrival']>e['tick'] elif kind=='hit': key=(cast,e['target']);assert key not in hits hits.add(key) if e['source']==1: assert e['tick']==shots[key]['arrival'] else: assert e['tick']==casts[cast]['release'] elif kind=='death': assert e['target'] not in deaths deaths.add(e['target']) assert trace['events'][-1]['kind']=='battle_end' and trace['won'] audio=json.loads((ROOT/'Doc/Design/Sound/BattleSkills/Slice/generation.json').read_text(encoding='utf-8')) rows=[] for item in audio['items']: source=ROOT/item['source'];target=ROOT/item['output'] assert hashlib.sha256(source.read_bytes()).hexdigest()==item['sourceSha256'] assert hashlib.sha256(target.read_bytes()).hexdigest()==item['outputSha256'] assert hashlib.sha256(json.dumps(item['request'],sort_keys=True).encode()).hexdigest()==item['requestHash'] assert item['job']['status']=='succeeded' rate,samples=wavfile.read(target);x=samples.astype(float)/32768 assert rate==44100 and samples.dtype==np.int16 and x.shape[1]==2 assert .1.05 assert np.max(np.abs(x[-10:]))<.003 rms=float(20*np.log10(np.sqrt(np.mean(x*x))));assert rms>-36 rows.append(dict(id=item['id'],seconds=len(x)/rate,rmsDb=rms,clippedSamples=int(np.sum(np.abs(x)>=.999)))) assert len(rows)==5 report=dict(status='pass',events=len(trace['events']),casts=len(casts),projectiles=len(shots),hits=len(hits),deaths=len(deaths),traceSha256=hashlib.sha256(trace_path.read_bytes()).hexdigest(),frozenInputs={r['source']:r['sourceSha256'] for r in exported['inputs']},currentSourceChanged=[r['source'] for r in exported['inputs'] if hashlib.sha256((ROOT/r['source']).read_bytes()).hexdigest()!=r['sourceSha256']],audio=rows,subjectiveListening='not_asserted',productionIntegrated=False) (DESIGN/'validation.json').write_text(json.dumps(report,indent=2),encoding='utf-8') print(f"PASS trace: {len(casts)} casts, {len(shots)} projectiles, {len(hits)} unique hits; five audio clips and frozen source hashes") if __name__=='__main__':main()