import importlib.util
import json
import os
from pathlib import Path
import time

os.umask(0o077)
R=Path(__file__).parent
spec=importlib.util.spec_from_file_location('observe',R/'observe.py')
o=importlib.util.module_from_spec(spec);spec.loader.exec_module(o);p=o.p
plan=p.read('plan.json'); final=p.read('final.json')
assert all(final['settings_equal'].values()) and final['registry_equal'] and final['config_equal'] and final['sender_execution_equal']
channels={s:sid for s,sid in plan['channels'].items() if s!=p.SOURCES[2]}
a=p.snapshot(channels);time.sleep(5);b=p.snapshot(channels)
p.save('final-recovery.json',dict(before=a,after=b))
current=p.ops.base.inspect('contextra-analytics-1')
assert current['State']['Health']['Status']=='healthy'
assert current['Image']=='sha256:cb9999cdec2f819eb6514d470a95eda2ac176159560b9959c1ad0fa09ab23bf7'
assert p.ops.base.inventory()==plan['inventory']
result={}
for s,sid in plan['channels'].items():
    q=p.state(sid)
    if s in channels:
        assert q['run_id']==plan['states'][s]['run_id'] and q['state']=='running'
        assert q['metadata_path']['performance']['detail'] is False and q['metadata_path']['visual'] is None
        x,y=a['channels'][s],b['channels'][s];dt=y['at']-x['at']
        rate=(y['state']['metadata_path']['processed']-x['state']['metadata_path']['processed'])/dt
        delta=y['state']['metadata_path'].get('stale',0)-x['state']['metadata_path'].get('stale',0)
        result[s]=dict(state=q['state'],run_preserved=True,final_short_fps=rate,stale_delta=delta,queue=q['metadata_path']['queued'])
    else:
        assert q['state']=='stopped' and not q['cleanup_pending'] and q['last_cleanup']['completed']
        result[s]=dict(state=q['state'],cleanup=q['last_cleanup'])
    assert q.get('last_error') is None and q.get('cleanup_error') is None
p.save('close-state.json',dict(channels=result,settings_preserved=True,registry_preserved=True,config_preserved=True,sender_preserved=True,inventory_preserved=True,image=current['Image'],restart=current['HostConfig']['RestartPolicy'],helper_failures=['Gate helper RLIMIT_AS inherited by Docker Go CLI; removed virtual-address limit, replaced with512MiB RSS check. No mutation before failure.','Final display assumed stopped Metadata had performance; saved preservation result valid, standalone finalizer now checks stopped state explicitly.'],production_changes=False))
print(json.dumps(result))
