from ops import *
import datetime,re
job='20260926-contextra-pose-reference-r01'
assert cmd(['git','-C',str(REPO),'rev-parse','HEAD']).strip()=='3c29d98100ace7100a710c05f0699a6dcd62eee1'
assert not cmd(['git','-C',str(REPO),'diff','--cached','--name-only']).strip()
paths=sorted(set(cmd(['git','-C',str(REPO),'diff','--name-only']).splitlines()+cmd(['git','-C',str(REPO),'ls-files','--others','--exclude-standard']).splitlines()))
assert len(paths)==12
cmd(['git','-C',str(REPO),'diff','--check'])
for p in paths:
    if not p.endswith('.md'):continue
    for target in re.findall(r'\]\(([^)]+)\)',(REPO/p).read_text()):
        if '://' not in target and not target.startswith('#'):assert ((REPO/p).parent/target.split('#')[0]).exists(),target
image=json.loads((HERE/'image-334fde3791.json').read_text())
for p,h in image['hashes'].items():assert hashlib.sha256((REPO/p).read_bytes()).hexdigest()==h
final=json.loads((HERE/'final-state.json').read_text())
assert final['stopped']==36 and not final['provider_pids'] and final['wss']
trial=json.loads((HERE/'pose'/'trial-result.json').read_text())
assert not trial['errors'] and trial['cleanup']['reaped']
assert [s['level'] for s in trial['stages'] if s['status']=='PASS']==[1,2,4,8,16,17]
for stage in trial['stages']:
    assert len(stage['frames']['providers'])==stage['level']
    assert all(p['required']==['pose'] and p['reordered']==0 for p in stage['frames']['providers'].values())
for lane in json.loads((HERE/'lanes-v2.json').read_text()):
    assert lane['completed']==lane['accepted'] and lane['late']==0
    for d in lane['durations'].values():assert d['count']==sum(d['histogram']) and min(d['histogram'])>=0
for row in json.loads((HERE/'summary-v2.json').read_text()):
    assert row['expected_children']==row['observed_children'] and not row['metric_errors']
    assert all(v['inferences']==0 for m,v in row['models'].items() if m!='RFDETRKeypointPreview')
rows=api('/api/v1/streams')['streams']
current=dict(stopped=sum(r['state']=='stopped' for r in rows),children=sum(bool(r.get('child_pid')) for r in rows))
save('verification.json',dict(final_targeted_tests=28,python='3.12',earlier_tests='47 plus one terminal fixture; overlap, not added',
    first_canary='failed; early EOS, worker_join, SIGKILL; preserved',
    final_canary='14.90 seconds, exit0, unforced',completed=[1,2,4,8,16,17],
    final=final,current_status=current,files=paths,portfolio='MEDIUM; mixed-load stall and browser acceptance pending',
    bounds=dict(root_free_gib=shutil.disk_usage('/').free/1024**3),
    limitations=['No historical image rerun','No GPU profiler','No natural Event in scenario-off baseline','Sender detailed timing not collected']))
receipt=dict(schema_version='ltb1021.codex_hub.report_receipt.v1',receipt_id=job,
 timestamp=datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9))).isoformat(),
 session_alias='work-session',task='Contextra 기동 중 Stop 회수 보완과 Pose 단독17채널 기준선',
 results=['첫 canary의 premature EOS 회수 실패 뒤 기존 deadline 내 source-ready 순서로 수정;최종14.90초 exit0/unforced',
 '최종 Python3.12 표적28PASS;Pose-only Off 1/2/4/8/16/17 각각30초 완료 및 전체정상회수',
 '평균수락9.87/9.83/9.64/9.29/5.96/5.64FPS;16→17합계95.37→95.93FPS;응답폐기0',
 '모델/instance/batch 불변,Event/renderer0;과거16채널과 입력/구조 차이로 회귀원인 미확정'],
 verify=['image/source hash, counters/histogram, docs link/diff checks',
 '36stopped/child0/4modelsREADY/WSS connected/Artifact HTTP On;settings restored/freshnessOn/non-target preserved'],
 commits=[],remaining=['복합 부하 stall 근본원인과 Artifact 병렬실패','Pose bulk 변환 후보의 효과 검증 및 실제 Web 수용'])
save('report-receipt.json',receipt)
print(cmd(['codex-report-receipt','--profile','ltb1021','--session-alias','work-session','--receipt',str(HERE/'report-receipt.json')]))
out=Path('/tmp/codex/ltb1021/git-closeout')/job;out.mkdir(mode=0o700);mf=out/'manifest.json'
args=['codex-git-closeout','prepare','--repository',str(REPO),'--output',str(mf),'--job-id',job,
 '--profile','ltb1021','--session-alias','work-session',
 '--title','fix(runtime): 기동 중 Stop 순서 보완과 Pose 기준선 기록',
 '--message','Why=기동 중 EOS가 첫 입력보다 앞서 회수에 실패하고 혼합 부하만으로는 단일 모델 처리량을 판단할 수 없었다.',
 '--message','What=미시작 graph Stop 제외,기존 cleanup deadline 안의 source-ready EOS,실제 출력 진행 기반 stall 판단,terminal 회수 재확인과 회귀 fixture를 추가했다.',
 '--message','Impact=provider-process/Frame/Event/Settings 보호와모델/instance/batch/queue/FPS/decoder를보존한다.시험 freshnessOff는종료했고운영On/100ms/startup10/steady2/JPEGOff이다.',
 '--message','Verify=최종Python3.12표적28PASS.첫canary실패후수정한기동Stop14.90초/exit0/unforced.Pose-only1/2/4/8/16/17각30초,모든child정상회수.평균수락9.87/9.83/9.64/9.29/5.96/5.64FPS,응답폐기0.과거대비회귀원인/복합stall/브라우저수용은미확정.',
 '--message','Rollback=이전image/config/실패evidence보존,자동rollback없음.최종pose-reference-334fde3791/36stopped/WSS연결/모델READY/ArtifactHTTPOn.원래설정CAS복귀,helper와시험image유지.',
 '--verify','28 targeted PASS; startup Stop canary; Pose-only six scale stages and unforced cleanup; source/image/diff/link/histogram checks',
 '--verify','36 stopped; Gateway/WSS recovered; freshness On; settings and non-target preserved; Web and mixed-load acceptance pending',
 '--expires-in-seconds','86400']
for p in paths:args+=['--path',p]
print(cmd(args));batch=out/'batch.json'
print(cmd(['codex-git-closeout','batch-prepare','--output',str(batch),'--batch-id',job,'--profile','ltb1021','--session-alias','work-session','--expected-group-count','1','--repository-label','contextra-analytics','--manifest',str(mf),'--expect-plan-hash',json.loads(mf.read_text())['plan_hash'],'--expires-in-seconds','86400']))
h=json.loads(batch.read_text())['plan_hash']
print(cmd(['codex-git-closeout','batch-plan','--batch-manifest',str(batch),'--expect-batch-plan-hash',h]))
print(cmd(['codex-git-closeout','batch-present','--batch-manifest',str(batch),'--expect-batch-plan-hash',h]))
