from ops import *
import csv
import re

plan=json.loads((R/'plan.json').read_text());trial=json.loads((R/'trial.json').read_text());assert trial['stage']=='PASS'
assert base.inventory()==plan['others']
assert base.inspect('contextra-redis-1')['Id']==plan['redis']['Id']
assert prior.prev.sender()['executionId']==plan['sender']['executionId']
for name in ['users.acl','compose.yaml','redis.conf']:assert base.g.sha(C/name)==plan['config_hashes'][name]
assert base.g.sha(Path('/data/contextra/runtime-state/streams_runtime.yaml'))==plan['registry_hash']
subprocess.run([sys.executable,str(C/'firewall.py'),'check'],check=True,capture_output=True,timeout=15)
p=subprocess.run(CLI+['status',str(PRESET)],cwd=REPO,capture_output=True,text=True,timeout=15);assert p.returncode==0
status=json.loads(p.stdout);assert status['state']=='running' and status['settings']['intrusion']['enabled']
save('final-cli-status.json',status)
container=base.inspect('contextra-analytics-1');pid=container['State']['Pid']
cg=Path('/proc/'+str(pid)+'/cgroup').read_text().strip().split('::')[1];folder=Path('/sys/fs/cgroup'+cg)
memory={k:int((folder/k).read_text()) for k in ['memory.current','memory.peak']};assert memory['memory.peak']<plan['caps']['memory_peak_bytes']
gpu=prior.prev.gpu();assert all(x[0]<plan['caps']['gpu_mib'] for x in gpu)
assert prior.prev.mem()>plan['caps']['min_available_ram_bytes']
for name in ['minimal','detailed']:
    proc=subprocess.run(CLI+['validate',str(REPO/'tools/examples'/('test-run-'+name+'.yaml'))],cwd=REPO,capture_output=True,text=True,timeout=10);assert proc.returncode==0
guide=REPO/'tools/TEST_RUN_GUIDE.ko.md'
for target in re.findall(r'\]\(([^)]+)\)',guide.read_text()):assert (guide.parent/target).exists()
subprocess.run(['git','diff','--check'],cwd=REPO,check=True)
summary=dict(cli='READY',tests=19,live_stop=1,live_start=1,live_restart=0,normal_cleanup_seconds=trial['final']['last_cleanup']['elapsed_s'],result_fps=trial['result_fps'],redis_fps=trial['redis_fps'],queue_range=trial['queue_range'],queue_drop=trial['queue_drop'],reader_added='192.168.50.19/32',firewall='actual/persistent ordered allow before DROP; second apply no-op',acl_unchanged=True,redis_restart=0,sender_control=0,sender_execution_preserved=True,other_containers_preserved=True,settings_unchanged=True,ai_state=status['state'],intrusion=True,capture=False,metrics=False,private_preset=str(PRESET),cgroup_memory=memory,gpu=gpu,windows='User playback success; no new investigation',external_reader='Connection from added host pending',new_registration_runtime='Unit tested API sequencing; live test reused existing channel',sdk_error_cleanup='Deferred; normal stop passed',capacity_errors=0)
save('summary.json',summary)
with (R/'summary.csv').open('w') as f:
    w=csv.writer(f);w.writerow(['item','result','scope']);w.writerows([['CLI','PASS','19 tests; existing channel Stop/Start'],['result FPS',summary['result_fps'],'15-second bounded observation'],['Redis FPS',summary['redis_fps'],'entries-added delta'],['cleanup seconds',summary['normal_cleanup_seconds'],'normal stop only'],['firewall','PASS','one exact host; actual/persistent; no-op'],['running','RETAIN','INTRUSION;store/AL/capture Off']])
save('report-receipt.json',dict(schema_version='ltb1021.codex_hub.report_receipt.v1',receipt_id='contextra-test-run-20260915-124300',timestamp='2026-09-15T12:43:00+09:00',session_alias='work-session',task='Contextra 시험 실행 CLI와 Redis reader host 추가',results=['safe YAML·read-only 등록 대조·기존 API 기반 시험 CLI 구현','Start/Stop/Restart 상태 대기·CAS·중복 제어 차단·private bounded 기록','기존 허용 범위를 보존한 reader host1개 추가 및 DROP 이전 순서 교정','최소/상세 예제와 한글 가이드 제공;Windows 사용자 재생 확인 기록'],verify=['19 표적 tests PASS; 예제2개 parser PASS','실제 도구 Stop1/Start1·정상 cleanup0.085초·결과와 Redis9.96FPS·queue0~1/drop0','방화벽 actual/persistent 순서·두 번째 apply no-op PASS','sender/모델/image/Redis 재시작 없음;기존 카메라 설정 보존;AI running 유지'],commits=[],remaining=['추가 host의 실제 접속과 사용자 수동 CLI 확인','오류 상황의 SDK Stop 지연은 별도 후속','공통 Event/Artifact 및 추가 시나리오 구현']))
for path in R.iterdir():
    if path.is_file():path.chmod(0o600)
print(json.dumps({k:summary[k] for k in ['cli','tests','normal_cleanup_seconds','result_fps','redis_fps','ai_state','sender_control','redis_restart']},ensure_ascii=False))
