import ast
import datetime
import json
import os
from pathlib import Path
import re
import subprocess

os.umask(0o077)
HERE=Path(__file__).parent
REPO=Path('/workspace/contextra-analytics-runtime-lifecycle-refactor')
JOB='20260918-contextra-secure-wss-r01'
ROOT=Path('/tmp/codex/ltb1021/git-closeout')/JOB
ROOT.mkdir(parents=True,mode=0o700,exist_ok=False)
def cmd(args):
    p=subprocess.run(args,text=True,capture_output=True,timeout=90)
    if p.returncode: raise RuntimeError(p.stdout+p.stderr)
    return p.stdout
def save(path,data):
    with path.open('x') as f:json.dump(data,f,indent=2,ensure_ascii=False)
    path.chmod(0o600)
assert not cmd(['git','-C',str(REPO),'diff','--cached','--name-only']).strip()
paths=cmd(['git','-C',str(REPO),'diff','--name-only']).splitlines()
paths+=cmd(['git','-C',str(REPO),'ls-files','--others','--exclude-standard']).splitlines()
assert len(paths)==22,(len(paths),paths)
cmd(['git','-C',str(REPO),'diff','--check'])
count=0
for name in paths:
    f=REPO/name
    if f.suffix=='.py':ast.parse(f.read_text())
    if f.suffix=='.md':
        for target in re.findall(r'\]\(([^)]+)\)',f.read_text()):
            if '://' in target or target.startswith('#'):continue
            target=target.split('#',1)[0]
            assert (f.parent/target).exists(),(name,target)
            count+=1
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 ARP 한정 우회 및 인증서 bootstrap/최소 WSS 구현 준비',
    results=['단일 neighbor 임시 고정 후 SSH 지문과 승인 CA 지문 및 관제 HTTPS 검증을 확인했다.',
             '로그인/발급 CLI와 최소 WSS, 인증 session 인계 및 backoff/상한을 구현하고 후보image를 준비했다.',
             '첫 로그인의 관제 NULL boolean 매핑 오류를 확인해 반복 없이 실제 반영 전 재개점에서 중단했다.'],
    verify=['초기32/수정22/최종image5 표적검증 PASS(중복 포함), Compose 및 image-owned source 확인.',
            '기존 두 채널 running/Artifact Off 및 persistent baseline 유지, 신규 bridge 미기동.'],
    commits=[],remaining=['관제 로그인 오류 수정 뒤 CSR 발급·실제 WSS/REST·두 채널 최소 수용 재개.'])
save(HERE/'report-receipt.json',receipt)
print(cmd(['codex-report-receipt','--profile','ltb1021','--session-alias','work-session','--receipt',str(HERE/'report-receipt.json')]))
print(cmd(['python3','/workspace/users/root/codex-ops-docs/servers/test/users/ltb1021/portfolio_logs/scripts/create_portfolio_candidate.py',
    '--run-dir',str(HERE),'--confidence','MEDIUM','--repo','contextra-analytics',
    '--track-key','contextra-analytics:ops:deployment:reproducible-deployment','--closeout-job',JOB,
    '--evidence-state','implemented','--confidentiality','internal',
    '--reason','인증 bootstrap 및 최소 WSS 후보 구현과 보호 검증 완료; 외부 로그인 오류로 실제 연동 대기',
    '--verify','Targeted fixture PASS; candidate images ready; external login blocked; original runtime unchanged']))
mf=ROOT/'manifest.json'
args=['codex-git-closeout','prepare','--repository',str(REPO),'--output',str(mf),'--job-id',JOB,
      '--profile','ltb1021','--session-alias','work-session',
      '--title','feat(secure-bridge): 인증 bootstrap과 최소 WSS 후보 준비',
      '--message','Why=실제 관제 계약과 초기 인증 순서를 맞추고 네트워크 장애와 인증 및 Runtime 수용을 분리한다.',
      '--message','What=최신 로그인 body와 CSR CLI, bounded WSS/heartbeat, 부모 상태 조회, session 인계와 transient backoff 및 Gateway 경로를 연결했다.',
      '--message','Impact=source와 후보 이미지만 준비했다. 단일 neighbor 임시 우회 외 기존 Runtime과 모델 및 원격 관제 설정은 변경하지 않았다.',
      '--message','Verify=초기32/영향22/최종image5 표적검증 PASS(중복 포함). Compose/source hash 및 SSH/CA/HTTPS 확인. 실제 로그인은 관제 NULL boolean 매핑 오류로 중단했고 CSR/WSS/REST 실제 수용은 대기다.',
      '--message','Rollback=코드/image 자동 rollback 없음. 기존 두 채널/Artifact Off를 유지했고 임시 neighbor 제거값과 재개 원장을 private에 남겼다.',
      '--verify','Targeted 32 + impact22 + image5 PASS; overlapping tests not summed',
      '--verify','Compose config/source hash/AST/local links/diff check PASS; original two streams unchanged',
      '--verify','Manager login blocked; no CSR POST, deployment or runtime restart',
      '--expires-in-seconds','86400']
for path in sorted(paths):args+=['--path',path]
print(cmd(args))
plan=json.loads(mf.read_text())['plan_hash']
batch=ROOT/'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',plan,
    '--expires-in-seconds','86400']))
print('LINKS',count)
print('BATCH_HASH',json.loads(batch.read_text())['plan_hash'])
