"""Preserve presentation sources and bounded verification without changing old evidence."""
from datetime import datetime
import hashlib
import json
from pathlib import Path
import re
import shlex
import shutil
from zoneinfo import ZoneInfo

from content import PAGES,COMMANDS

RUN=Path(__file__).resolve().parent
OUT=Path('/workspace/architecture_docs/topics/contextra/20260930_field_operations_gamebook')
REPO=Path('/workspace/contextra-analytics-runtime-lifecycle-refactor')
verification=json.loads((RUN/'verification.json').read_text())
surface={
 'config':('field_cli.py',{'status','version','prepare','connect','retry','apply','resume','cancel','restore','note','confirm','export'}),
 'profile':('field_cli.py',{'select','edit','credentials','paths','web'}),
 'net':('field_cli.py',{'status','apply','arp'}),
 'lang':('field_ui.py',{'en'}),
 'usb':('field_usb.py',{'status','unmount'}),
 'vscode':('vscode_safety.py',{'status'}),
 'resources':('field_resources.py',{'stop'}),
 'observe':('observability.py',{'start','status','stop'}),
 'work':('ct.py',{'begin','note','end','export'}),
 'logs':('ct.py',{'analytics','ai-control-sidecar','ai-gateway'}),
}
ctsource=(REPO/'tools/icerti_offline/maintenance/ct.py').read_text()
audit=[]
for item in COMMANDS:
    args=shlex.split(item['command'])
    if not args or args[0]!='ct':continue
    assert re.search(r'\b'+re.escape(args[1])+r'\b',ctsource),args
    source='ct.py'
    if args[1] in surface:
        source, allowed=surface[args[1]]
        if len(args)>2:assert args[2] in allowed,(args,allowed)
        text=(REPO/'tools/icerti_offline/maintenance'/source).read_text()
        if len(args)>2:assert re.search(r'\b'+re.escape(args[2])+r'\b',text),args
    audit.append({'command':item['command'],'source':'tools/icerti_offline/maintenance/'+source,'executed':False})
verification['command_surface_audit']={'ct_lines':len(audit),'displayed_lines':len(COMMANDS),'all_mapped':True,'runtime_commands_executed':False}
verification['visual_review']={'full_pages':list(range(1,36)),'quick_pages':list(range(1,9)),
  'issues_remaining':0,'notes':['Long scp is explicitly one line','work export tar.gz path is separate from config ZIP','External file URI navigation removed','All page images reviewed; changed pages rechecked']}
verification['layout']=json.loads((RUN/'layout.json').read_text())
(OUT/'verification.json').write_text(json.dumps(verification,ensure_ascii=False,indent=2)+'\n')
(RUN/'command-audit.json').write_text(json.dumps(audit,ensure_ascii=False,indent=2)+'\n')
source=OUT/'source';source.mkdir(exist_ok=True)
for name in ['content.py','build.py','export_reference.py','verify.py','preserve.py']:
    shutil.copy2(RUN/name,source/name)
shutil.copy2(REPO/'docs/deployment/CT_FIELD_GAMEBOOK_GPT.ko.md',OUT/'CT_FIELD_GAMEBOOK_GPT.ko.md')
shutil.copy2(RUN/'command-audit.json',OUT/'command-audit.json')
files=[]
for path in sorted(OUT.rglob('*')):
    if path.is_file() and path.name!='manifest.json':
        files.append({'path':str(path.relative_to(OUT)),'size_bytes':path.stat().st_size,'sha256':hashlib.sha256(path.read_bytes()).hexdigest()})
manifest={'schema_version':'codex.artifact-manifest.v1','created_at':datetime.now(ZoneInfo('Asia/Seoul')).isoformat(),
 'profile':'ltb1021','lifecycle':'presentation','source_fingerprint':'e6bc1e92068961adef8a5bc58cd9d8c4fc15dc1b',
 'owner':'docs/profiles/ltb1021/topics/runtime-lifecycle/README.ko.md','cleanup_candidate_at':'manual-review',
 'files':files,'historical_artifacts_changed':False,'server_access':False}
(OUT/'manifest.json').write_text(json.dumps(manifest,ensure_ascii=False,indent=2)+'\n')
print(json.dumps({'files':len(files),'ct_commands_audited':len(audit),'manifest':str(OUT/'manifest.json')},ensure_ascii=False))
