"""Independent route qualification from raw native records; never sends input.""" import math from ordinary_gate_evidence import join_gate_snapshots, validate_gate_geometry from ordinary_look_evidence import validate_look_evidence def need(value, message): if not value: raise ValueError(message) def number(value): need(type(value) in (int, float) and math.isfinite(value), 'invalid numeric evidence') return value def horizontal(a, b): return math.hypot(a[0]-b[0], a[2]-b[2]) def norm(v): return math.sqrt(sum(x*x for x in v)) def yaw(v): return math.degrees(math.atan2(v[0], v[2])) def angle(a, b): return (a-b+180)%360-180 def neutral(s): i=s['input'] return abs(i['forward']) <= .01 and norm(i['input']) <= .01 and norm(i['velocity']) <= .05 def validate_approach_evidence(content, nonce, look_proof, proof): result={'verified':False,'errors':[], 'scope':'one private ordinary-input approach to the interior prison gate waypoint; no unlock, escape, visual, multiplayer or FPS qualification', 'held_action_verified':False,'escape_verified':False} try: need(type(proof) is dict and proof.get('requested') is True and proof.get('completed') is True and proof.get('nonce')==nonce, 'approach did not complete under this nonce') need(not proof.get('error') and proof.get('paired_release_errors')==[] and proof.get('unconfirmed_held_key') is None, 'approach input did not end cleanly') profile=proof.get('profile','standard') need(type(profile) is str and profile in ('standard','coarse'), 'unknown approach profile') max_pixels,max_angle,max_pulses=(384,35,16) if profile=='coarse' else (128,15,12) result['profile']=profile start=number(proof['started_monotonic']); finish=number(proof['finished_monotonic']); deadline=number(proof['deadline_monotonic']) need(0 <= start < finish <= deadline and deadline-start <= 35, 'approach helper deadline invalid') events=proof['events']; stops=proof['stops']; motions=proof['motions']; references=proof['samples'] need(type(events) is list and 2 <= len(events) <= 2*max_pulses and len(events)%2==0, 'expected bounded W key pairs') need(type(stops) is list and len(stops)*2==len(events), 'each W pair needs a native full-stop interval') need(type(motions) is list and len(motions)<=16 and type(references) is list and 2 <= len(references) <= 450, 'route reference bounds invalid') ids=[r['sample'] for r in references] need(all(type(i) is int for i in ids) and ids==sorted(set(ids)), 'route sample references repeated or reversed') data=join_gate_snapshots(content,nonce); samples=data['snapshots']; first,last=ids[0],ids[-1] need(type(proof.get('final_sample')) is int and proof['final_sample']==last, 'final native reference differs from last sample') need(first >= look_proof['return_sample'] and first in samples and last in samples, 'route is not after native look calibration') receipts={}; previous_receipt=start-.5 for reference in references: i=reference['sample']; need(i in samples and type(reference['real_ms']) is int and reference['real_ms']==samples[i]['real_ms'], 'helper sample clock differs from native source') received=number(reference['received_monotonic']) need(previous_receipt<=received<=finish, 'native receipt timestamps reversed or outside route') receipts[i]=received; previous_receipt=received geometry=validate_gate_geometry(content,nonce,first,last) need(geometry['verified'], 'native route geometry rejected: '+str(geometry['errors'])) look=validate_look_evidence(content,nonce,look_proof,events[:2]) need(look['verified'], 'native calibration rejected: '+str(look['errors'])) need(start >= look_proof['finished_monotonic'], 'route started before calibration finished') origin=samples[first]['geometry']; center=origin['prison']; hinge=origin['gate']; handle=origin['context'] dx,dz=center[0]-hinge[0],center[2]-hinge[2]; separation=math.hypot(dx,dz) need(5.75 <= separation <= 6.25 and min(abs(dx),abs(dz)) <= .1, 'unsupported native prison geometry') inward=(dx/separation,dz/separation) need(abs(origin['gate_forward'][0]*inward[0]+origin['gate_forward'][2]*inward[1])>=.99 and horizontal(handle,hinge)<=4.5,'native gate orientation or handle invalid') target=(handle[0]+1.5*inward[0],center[1],handle[2]+1.5*inward[1]) def inside(v): return abs(v[0]-center[0])<=5.25 and abs(v[2]-center[2])<=5.25 and abs(v[1]-center[1])<=3 need(inside(target), 'interior waypoint outside authored bounds') ready=data['ready']; need(samples[last]['real_ms']-ready['real_ms']<35000,'native approach exceeded original READY bound') path=0.; previous=None for i in range(first,last+1): need(i in samples,'missing raw route sample') s=samples[i]; p=s['input']['origin']; g=s['geometry']; a=s['action'] need(inside(p) and norm(s['input']['velocity'])<=5,'body left interior motion envelope') move=s['input']['input'];need(abs(move[0])<=.01 and abs(move[1])<=.01 and -.01<=move[2]<=1.01 and -.01<=s['input']['forward']<=1.01, 'unexpected native movement input') need(g['door_state']==0 and g['door_control']==0 and a['pressed']==0 and not a['performing'] and a['progress']==0,'gate action or door was operated during approach') if previous: dt=s['real_ms']-previous['real_ms']; step=horizontal(p,previous['input']['origin']) need(0