#!/usr/bin/env python3
from pathlib import Path
import datetime, hashlib, json, subprocess, time
ROOT=Path('/data/video-pipeline/HaTramAudio/project/017-Tam-Ve-Khong-Ghi-Diem-Den')
RUN='run-20260721T030911Z-51bf7fe4';OWNER='Levy'
WORK=ROOT/'work/story'/RUN
FILES=[ROOT/'script/creative-options.json',ROOT/'script/story-brief.json',ROOT/'script/outline.json',ROOT/'script/ledger.json',WORK/'candidate.txt']
LEASE='/home/hermes/.hermes/skills/audio-production/ha-tram-audio/scripts/gate_lease.py'
COMMIT='/home/hermes/.hermes/skills/audio-production/ha-tram-audio/scripts/commit_gate.py'
QA=WORK/'qa_and_promote.py'
def guard():
 d=json.loads((ROOT/'.ownership-lock.json').read_text(encoding='utf-8'))
 if any(d.get(k)!=v for k,v in {'project_id':ROOT.name,'run_id':RUN,'owner':OWNER}.items()):raise RuntimeError('ownership mismatch')
def fp():
 if not all(p.is_file() and p.stat().st_size>0 for p in FILES):return None
 return tuple((str(p),p.stat().st_size,p.stat().st_mtime_ns) for p in FILES)
def heartbeat():
 subprocess.check_call(['python3',LEASE,'heartbeat','--project-root',str(ROOT),'--gate','story','--run-id',RUN,'--owner',OWNER,'--ttl-seconds','3600'],stdout=subprocess.DEVNULL)
def main():
 guard();started=time.monotonic();last=None;stable_since=None;last_beat=0.0
 while time.monotonic()-started<7200:
  guard();now=time.monotonic()
  if now-last_beat>=300:heartbeat();last_beat=now
  current=fp()
  if current is not None and current==last:
   if stable_since is None:stable_since=now
   if now-stable_since>=30:break
  else:last=current;stable_since=now if current is not None else None
  time.sleep(5)
 else:raise RuntimeError('timed out waiting for stable story artifacts')
 for p in FILES[:-1]:
  d=json.loads(p.read_text(encoding='utf-8'))
  if d.get('project_id',ROOT.name)!=ROOT.name or d.get('run_id',RUN)!=RUN:raise RuntimeError('story architecture identity mismatch: '+str(p))
 subprocess.check_call(['python3',str(QA)],cwd=ROOT)
 receipt=ROOT/'log/story.json';d=json.loads(receipt.read_text(encoding='utf-8'))
 if d.get('status')!='completed' or d.get('verified') is not True:raise RuntimeError('Story QA did not produce terminal verified receipt')
 subprocess.check_call(['python3',COMMIT,'--project-root',str(ROOT),'--gate','story','--receipt',str(receipt),'--run-id',RUN])
 manifest=json.loads((ROOT/'script/project-manifest.json').read_text(encoding='utf-8'))
 event=manifest.get('gate_events',{}).get('story',{})
 if manifest.get('steps',{}).get('story')!='completed' or event.get('verified') is not True:raise RuntimeError('Story Gate commit verification failed')
 print(json.dumps({'status':'completed','verified':True,'gate':'story','canon_sha256':manifest['canon_sha256'],'word_count':manifest['story_word_count']},ensure_ascii=False))
if __name__=='__main__':main()
