"""Validate native stamps using Hertz's frozen split-timing parser; no field verdict."""
import importlib.util
import json
from pathlib import Path
import sys
ROOT=Path(__file__).resolve().parents[4]
AMENDMENT=ROOT/'.spt/preserved/302/raw-copy-resume-v1'
sys.path.insert(0,str(AMENDMENT))
spec=importlib.util.spec_from_file_location('step1_analyzer',AMENDMENT/'step1-analyze.py')
a=importlib.util.module_from_spec(spec);spec.loader.exec_module(a)
folder=Path(sys.argv[1])
epochs=a.parse_stamps((folder/'native.stderr').read_text().splitlines())
assert len(epochs)==1, list(epochs)
epoch=next(iter(epochs.values()))
result={'epoch_issues':epoch['issues'],'stamp_count':len(epoch['records']),'boundary_count':len(epoch['spans']),'worker_tids':epoch['worker_tids'],'snapshot_count':len(epoch['stacks']),'local_only':True}
# Open spans remain honest evidence at forced process exit; all other schema failures reject.
unexpected=[i for i in epoch['issues'] if not i.startswith('open_boundary_')]
result['unexpected_issues']=unexpected
accepted=[]
for r in epoch['stacks']:
    workers=r['workers']
    processing_begin=r.get('processing_begin_mono_ms')
    processing_end=r.get('processing_end_mono_ms')
    processing_duration=r.get('processing_duration_ms')
    split_valid=(r.get('capture_timing')=='raw-copy-resume-v1'
        and all(isinstance(v,int) for v in (processing_begin,processing_end,processing_duration))
        and r['capture_end_mono_ms']<=processing_begin<=processing_end
        and processing_duration==processing_end-processing_begin)
    if (split_valid and sorted(w['tid'] for w in workers)==sorted(epoch['worker_tids']) and len(workers)==2
        and r['capture_end_mono_ms']-r['capture_begin_mono_ms']<=100 and r['trigger_canary_age_ms']>=1000
        and all(w['frames'] and not w['error'] for w in workers)):
        accepted.append(r)
result['complete_bounded_pairs']=len(accepted)
separated_pairs=[
    [first['capture_id'],second['capture_id']]
    for first in accepted for second in accepted
    if second['capture_begin_mono_ms']-first['capture_begin_mono_ms']>=250
]
result['separated_pair_ids']=separated_pairs
result['paired_capture_ids']=[r['capture_id'] for r in accepted]
result['capture_spans_ms']=[r['capture_end_mono_ms']-r['capture_begin_mono_ms'] for r in epoch['stacks']]
result['processing_spans_ms']=[r.get('processing_duration_ms') for r in epoch['stacks']]
result['capture_timing']=[r.get('capture_timing') for r in epoch['stacks']]
result['serialized_captures']=all(
    a.get('processing_end_mono_ms',float('inf'))<=b['capture_begin_mono_ms']
    for a,b in zip(epoch['stacks'],epoch['stacks'][1:])
)
(folder/'local-evidence.json').write_text(json.dumps(result,indent=2)+'\n')
print(json.dumps(result,indent=2))
assert not unexpected, unexpected
assert result['serialized_captures'], 'new raw capture overlaps prior processing'
if folder.name.startswith('forced'):
    assert separated_pairs, 'need two complete bounded both-worker captures at least 250ms apart'
