from common import *
import csv
import re
plan=json.loads((R/'plan.json').read_text());result=json.loads((R/'acl-result.json').read_text())
now=query('admin','ACL','GETUSER','contextra_reader')
assert set(now['commands'].split())-set(plan['reader']['commands'].split())=={'+scan','+hscan','+xinfo|stream'}
assert now['passwords']==plan['reader']['passwords'] and now['keys']==plan['reader']['keys']
assert g.sha(C/'users.acl')==result['persistent_hash']
for name,path in [('access',C/'access.json'),('firewall',C/'firewall.py'),('active',C/'compose.yaml'),('redis_config',C/'redis.conf')]:
    assert g.sha(path)==plan[name+'_hash']
assert g.sha(g.ENV)==json.loads((R/'persistent-bounds.json').read_text())['env_hash']
current=json.loads(g.sh(['docker','inspect','contextra-redis-1']))[0]
assert current['Id']==plan['redis']['Id'] and current['RestartCount']==plan['redis']['RestartCount']
assert g.inspect()['Id']==plan['analytics']['Id'] and g.others()==plan['other_containers']
clients=query('admin','CLIENT','LIST')
rows=[dict(f.split('=',1) for f in l.split() if '=' in f) for l in clients.splitlines()]
before_ids={x['id'] for x in plan['clients'] if x['user']=='contextra_reader'}
after_ids={x['id'] for x in rows if x['user']=='contextra_reader'}
paths=['docs/integration/metadata-web-review.ko.md',
 'docs/profiles/ltb1021/topics/runtime-lifecycle/decision/20260915T102820+0900-decision-reader-guide-bounds.md',
 'docs/profiles/ltb1021/topics/runtime-lifecycle/runs/20260915T102820+0900-run-redis-reader-guide.md',
 'docs/profiles/ltb1021/topics/runtime-lifecycle/README.ko.md']
links=0
for path in paths:
    file=REPO/path;content=file.read_text()
    if path.endswith('README.ko.md'):content=content.split('## H.264')[0]
    for target in re.findall(r'\]\(([^)]+)\)',content):
        if target.startswith(('http:','https:','#')):continue
        assert (file.parent/target.split('#',1)[0]).resolve().exists(),target
        links+=1
example=json.loads((REPO/'docs/integration/metadata-example.json').read_text())
assert example['sourceId']=='camera-demo-01'
t=example['frameTime'];assert t['detectedAtWallMs']==t['startWallTimeMs']+t['rtpTimestamp']*1000//t['rtpClockRate']
assert all(e['runId']==example['runId'] and e['frameSeq']==example['frameSeq'] for e in example.get('events',[]))
subprocess.run(['git','diff','--check'],cwd=REPO,check=True)
summary=dict(acl='PASS',added_commands=['SCAN','HSCAN','XINFO STREAM'],dryrun_cases=len(result['dryrun']),
 actual_read=['SCAN','HSCAN'],writes_tested='ACL DRYRUN only',authentication_and_key_scope_preserved=True,
 previous_reader_connections_retained=len(before_ids&after_ids),previous_reader_connections=len(before_ids),
 redis_recreate=0,redis_restart=0,ai_start=0,container_identity_preserved=True,
 redis_live=query('admin','CONFIG','GET','maxmemory','maxmemory-policy'),
 existing_container_restart='2gb; reconciliation deferred while readers connected',
 persistent_recreate='8gb',source_defaults=dict(message_bytes=10485760,queue_bytes=268435456,redis='8gb'),
 data='No data write/delete/restore; existing TTL and publisher heartbeat continue',
 guide='Markdown review only; HTML not created',example_tests=4,local_links=links,
 capacity_errors=0,publisher=api('/api/v1/metadata/status'))
save('summary.json',summary)
with (R/'summary.csv').open('w') as f:
    w=csv.writer(f);w.writerow(['item','result','scope'])
    w.writerows([['reader ACL','PASS','3 additions;16 dryrun checks'],['Redis recreate','DEFERRED','Existing reader connections preserved'],
       ['capacity','PARTIAL','Live/persistent8GiB; existing container restart2GiB'],['guide','REVIEW','7 sections;JSON and Python examples;4 tests'],
       ['data','PRESERVED','No restart or data mutation;TTL continues']])
for p in R.iterdir():
    if p.is_file():p.chmod(0o600)
print(json.dumps(summary))
