#!/usr/bin/env python3
from pathlib import Path
import datetime as dt,hashlib,json,os
ROOT=Path('/data/video-pipeline/HaTramAudio/project/016-Nguoi-Giu-Am-Thanh-Cuoi-Cung');RUN='run-20260720T233725Z-24504f17';CANON='fae6fce617a14dc4f8b3bd52968cc688a456c45a60bc2ed7701ccd8164875e02';OUT=ROOT/'log/publish-ready.json'
def sha(p):
 h=hashlib.sha256()
 with p.open('rb') as f:
  while b:=f.read(8*1024*1024):h.update(b)
 return h.hexdigest()
def load(rel):return json.loads((ROOT/rel).read_text())
def main():
 lock=load('.ownership-lock.json');assert (lock['project_id'],lock['run_id'],lock['owner'],lock['status'])==(ROOT.name,RUN,'zoro','main_session_pipeline')
 assert sha(ROOT/'story/story-canon.txt')==sha(ROOT/'story/spoken-narration.txt')==CANON
 story=load('script/story-manifest.json');assert story['status']=='completed' and story['verified'] and story['canon_sha256']==CANON and story['spoken_narration_sha256']==CANON
 tts=load('script/tts-manifest.json');assert tts['status']=='completed' and tts['verified'] and tts['source_canon_sha256']==CANON and tts['output_sha256']==sha(ROOT/'audio/story-full.wav')
 ta=load('log/tts-independent-audit.json');assert ta['status']=='passed' and ta['verified'] and ta['output_sha256']==tts['output_sha256']
 art=load('log/artwork-qa.json');assert art['status']=='passed' and art['verified'] and art['source_canon_sha256']==CANON
 layout=load('image/layout-manifest.json');assert layout['status']=='completed' and layout['verified'] and layout['source_canon_sha256']==CANON and layout['layout']['sha256']==sha(Path(layout['layout']['path']))
 intro=load('log/intro-render.json');assert intro['status']=='completed' and intro['verified'] and intro['visual_qa']['verified'] and intro['source_canon_sha256']==CANON and intro['video_sha256']==sha(ROOT/'output/intro/intro.mp4')
 footage=load('log/footage-render.json');assert footage['status']=='completed' and footage['verified'] and footage['technical_verified'] and footage['visual_qa']['verified'] and footage['source_canon_sha256']==CANON and footage['source_audio_sha256']==tts['output_sha256'] and footage['source_layout_sha256']==layout['layout']['sha256'] and footage['output_sha256']==sha(ROOT/'output/footage/footage.mp4')
 final=load('log/final-render.json');assert final['status']=='completed' and final['verified'] and final['technical_verified'] and final['visual_qa']['verified'] and final['source_canon_sha256']==CANON and final['source_intro_sha256']==intro['video_sha256'] and final['source_footage_sha256']==footage['output_sha256'] and final['output_sha256']==sha(ROOT/'output/final.mp4')
 trans=load('log/transcode-upload.json');upload=ROOT/'output/final-upload.mp4';assert trans['status']=='completed' and trans['verified'] and trans['technical_verified'] and trans['visual_qa']['verified'] and trans['under_one_gb'] and trans['source_canon_sha256']==CANON and trans['source_final_sha256']==final['output_sha256'] and trans['output_sha256']==sha(upload) and trans['output_bytes']==upload.stat().st_size<1000000000
 meta=load('log/metadata.json');info=ROOT/'output/info.txt';assert meta['status']=='completed' and meta['verified'] and meta['source_canon_sha256']==CANON and meta['metadata_sha256']==sha(info) and meta['upload_copy_sha256']==trans['output_sha256']
 thumb=ROOT/'image/normalized/intro-poster-1920x1080.png';assert sha(thumb)==layout['normalized_assets']['intro']['sha256']
 blockers=[p.name for p in ROOT.iterdir() if p.name.startswith('DO_NOT_PUBLISH') or p.name.startswith('publish_block')];assert not blockers
 now=dt.datetime.now(dt.timezone.utc).isoformat().replace('+00:00','Z');obj={'schema_version':1,'project_id':ROOT.name,'run_id':RUN,'status':'ready','verified':True,'source_canon_sha256':CANON,'story_manifest_sha256':sha(ROOT/'script/story-manifest.json'),'tts_manifest_sha256':sha(ROOT/'script/tts-manifest.json'),'tts_output_sha256':tts['output_sha256'],'artwork_qa_sha256':sha(ROOT/'log/artwork-qa.json'),'layout_sha256':layout['layout']['sha256'],'intro_sha256':intro['video_sha256'],'footage_sha256':footage['output_sha256'],'final_sha256':final['output_sha256'],'upload_copy_path':str(upload),'upload_copy_sha256':trans['output_sha256'],'upload_copy_bytes':upload.stat().st_size,'upload_copy_under_one_gb':True,'metadata_path':str(info),'metadata_sha256':meta['metadata_sha256'],'thumbnail_path':str(thumb),'thumbnail_sha256':sha(thumb),'blockers':[],'credential':'[REDACTED]','verified_at':now};OUT.parent.mkdir(parents=True,exist_ok=True);tmp=OUT.with_suffix('.json.tmp');tmp.write_text(json.dumps(obj,ensure_ascii=False,indent=2)+'\n');os.replace(tmp,OUT);print(json.dumps({'status':'ready','verified':True,'upload_copy_bytes':obj['upload_copy_bytes']}))
if __name__=='__main__':main()
