import ast,json,os,subprocess
from pathlib import Path
os.umask(0o077)
R=Path(__file__).parent
runner='/root/.local/bin/codex-git-closeout'
job='contextra-rtsp-cli-20260914-152947'
def run(args):return subprocess.check_output(args,text=True,timeout=45)
def prepare(repo,head,label,title,messages,verify,expected):
    assert run(['git','-C',repo,'rev-parse','HEAD']).strip()==head
    assert not run(['git','-C',repo,'diff','--cached','--name-only']).strip()
    paths=sorted(set(run(['git','-C',repo,'diff','--name-only']).splitlines()+run(['git','-C',repo,'ls-files','--others','--exclude-standard']).splitlines()))
    assert set(paths)==set(expected),(paths,expected)
    run(['git','-C',repo,'diff','--check'])
    for p in paths:
        if p.endswith('.py'):ast.parse((Path(repo)/p).read_text())
    args=[runner,'prepare','--repository',repo,'--output',str(R/(label+'-manifest.json')),'--job-id',job if label=='contextra' else job+'-'+label,
          '--profile','ltb1021','--session-alias','work-session','--title',title,'--verify',verify]
    for m in messages:args+=['--message',m]
    for p in paths:args+=['--path',p]
    return json.loads(run(args))
ref='docs/profiles/ltb1021/topics/runtime-lifecycle/runs/20260914T152947+0900-run-rtsp-test-cli.md'
source_paths=['tools/rtsp_test.py','tools/rtsp_test_manager.py','tools/rtsp_test_worker.py','tools/RTSP_TEST_GUIDE.ko.md','tests/test_rtsp_test_manager.py',ref,
 'docs/profiles/ltb1021/topics/runtime-lifecycle/decision/20260914T152947+0900-decision-rtsp-test-event-artifact.md',
 'docs/profiles/ltb1021/topics/runtime-lifecycle/README.ko.md']
source=prepare('/workspace/contextra-analytics-runtime-lifecycle-refactor','fae05fabf1669a6f8ef34a592b9422ba9628cd3f','contextra',
 'feat(rtsp-test): 독립 반복 송출 CLI와 수명 및 시간축 검증 추가',[
 'Why=승인 영상을 사용자가 직접 반복 시험하면서 운영 AI와 기존 송출 서비스를 보존할 수 있는 최소 도구가 필요하다.',
 'What=기존 FFmpeg/GstRtspServer의 stream-copy 경로, 영상 매핑과 owned container 수명, continuous/once, 한글 경로 및4개 상한을 구현했다.',
 'Impact=운영 변경과 GPU추론 없이 localhost 시험만 제공한다. 기본 sample01 등록/송출0이며 Event/Artifact 승인값은 기록만 했다.',
 'Verify=표적11 tests PASS. once30Frame/정상 EOF, 실제2개 동시 수신과 독립 Stop, 반복 경계 RTP90000/9000 및 역행0. 기존16개 container 불변과 cleanup 확인. 실제4개/AI/Web 동기화는 미검증.',
 'Rollback=동일 registry stop-all 후 CLI 사용을 중단하고 이번 source만 되돌린다. 운영 image와 모델 및 원본은 변경하지 않았다.'
 ],'11 unit tests PASS; MPEG4 once30frames EOS; two concurrent RTP receivers; loop delta9000 at clock90000; no backward or observed gaps; owned cleanup PASS; existing16 containers unchanged; help/AST/diff PASS',source_paths)
prefix='servers/test/users/ltb1021/portfolio_logs/'
portfolio_paths=[prefix+'catalogs/track_index.jsonl',prefix+'entries/contextra-analytics/ops__deployment__reproducible-deployment/2026/2026-09.jsonl',prefix+'entries/contextra-analytics/ops__deployment__reproducible-deployment/track.json']
portfolio=prepare('/workspace/users/root/codex-ops-docs','9e6bddb04fe09acd118617eda892bc40ffad8208','portfolio',
 'docs(portfolio): 반복 시험 송출과 자원 소유권 검증 기록',[
 'Why=검증된 독립 시험 도구의 재현성과 안전한 자원 수명 관리 성과를 남긴다.',
 'What=RTSP CLI의 실제 단회 및 반복 동시 송수신 검증 milestone1건을 안전 append했다.',
 'Impact=Portfolio shard와 track/catalog만 갱신하며 historical evidence와 공용 지침을 보존한다.',
 'Verify=append dry-run와 content safety PASS, source8파일 및 Runtime evidence 대응 확인.',
 'Rollback=새 entry와 관련 track/catalog 갱신만 안전 절차로 보정하며 application Runtime은 변경하지 않는다.'
 ],'HIGH milestone; dry-run PASS; source8 files correspond; actual2 vs limit4 and AI/Web limits preserved',portfolio_paths)
args=[runner,'batch-prepare','--output',str(R/'git-batch.json'),'--batch-id',job,'--profile','ltb1021','--session-alias','work-session','--expected-group-count','2']
for label,p in [('contextra',source),('portfolio',portfolio)]:
    args+=['--repository-label',label,'--manifest',str(R/(label+'-manifest.json')),'--expect-plan-hash',p['plan_hash']]
print(run(args))
