"""Dormant one-hold prison policy; no OS, input backend or native action calls. perform_held_action accepts only explicit adapters: * guard.check(): original private window/focus/process/display ownership check. * require_idle(): native all-key/button idle check, used before pressing only. * key.down_f(guard, *, deadline, not_after) -> exactly {key:'F', down_monotonic:actual_request_time}. The adapter must freshly prove the SAME owner/connection and idle state immediately before the request, and refuse after not_after (which includes six-second admission and pose freshness). * key.up_f(guard, *, deadline, cleanup=False) -> exactly {key:'F', up_monotonic:actual_request_time, released:True}. The adapter freshly proves the same owner before key-up and confirms native keymap idle afterward. cleanup=True may release an uncertain F after expiry ONLY through the same freshly proven connection; it cannot renew the lease or qualify a late result. No adapter exposes another key, wheel, mouse, action invocation or pose setter. * notify('held-key-pending', key='F', deadline_monotonic=...) MUST establish an independent hard supervisor before any uncertain down. Its maximum lease is five seconds from that attempt, further shortened by the frozen observation deadline. 'held-key-release-confirmed' clears only that lease. The wrapper owns failure containment; this pure module cannot guarantee release after lost ownership and retains uncertainty rather than redirecting input. * observe(): all new consecutive native INPUT/LOOK/GATE/CHOICE joined snapshots, or an unchanged latest sample. Begin with the committed selection final sample. Keep original receipts; reject missing BASIS, nonce/world/body/life/account/ camera/gate/action/context identity changes, menus or observer cancellation. Before phase2 snapshot fields match the selection adapter, plus turn=[x,y,z]. After phase2 original observer object pins remain mandatory, but live door, context, gate and forward geometry may move; selected/permission/progress may disappear. Never substitute another native identity based on similar geometry. * calibration: nonce, observer_start_real_ms (QUEUED), ready_real_ms, ready_monotonic, optional observer_deadline_monotonic <= original bound. * selection_evidence is independently revalidated raw one-wheel evidence: verified, last_sample, selected_action_id, wheel_button=5. report must retain action_selection_proof and its full in-memory native samples/immutable refs. Only six seconds of genuinely remaining ORIGINAL45s time admits a press. The previous facing/selection8s lease is closed, never renewed or borrowed. One F attempt only, <=5s hard lease, .75s reserved for guarded release, two advancing bound native progress samples, monotonic phase1->2, separate original-door control/physical motion, and native released-input observation are required. No exact4.0 progress sample is required: native completion can reset in one frame. Results distinguish refused-no-input, failed-after-input, unlock-observed-motion- unverified, and verified. Even verified means this local action/door observation only, not passage through the gate, a full escape, multiplayer or FPS evidence. Importing this file does nothing; no production/helper/runner activates it. """ import copy import math from prison_approach_proof import number, vector, length, yaw, delta, inside, target_for from prison_action_selection_proof import choices_for class Refused(ValueError): pass def need(value, message): if not value: raise Refused(message) def perform_held_action(guard, require_idle, key, observe, geometry, calibration, selection_evidence, report, *, clock, sleep, notify): need('held_action_proof' not in report, 'Held action attempt already exists') state = {'requested':True,'completed':False,'status':'refused-no-input', 'input_attempted':False,'unlock_observed':False,'gate_motion_observed':False, 'release_confirmed':False,'unconfirmed_held_key':None,'paired_release_errors':[], 'notification_errors':[],'events':[],'samples':[],'progress_samples':[],'transition_sample':None, 'control_sample':None,'motion_sample':None,'released_sample':None, 'initial_sample':None,'final_sample':None,'started_monotonic':clock(), 'finished_monotonic':None,'press_attempted_monotonic':None, 'down_monotonic':None,'up_monotonic':None,'press_sample':None, 'original_deadline_monotonic':None,'held_deadline_monotonic':None} report['held_action_proof'] = state held = False; down = None; previous = None; phase = 1; progress = 0.; pressed_ack = None deadline = None; lease = None; release_due = None; release_attempts = 0; release_barrier = None def release(cleanup=False): nonlocal held, release_attempts if not held: return need(release_attempts < 2, 'Bounded F release attempts exhausted') release_attempts += 1 event = {'key':'F','down':False,'attempted_monotonic':clock(),'cleanup':cleanup,'confirmed':False} state['events'].append(event) guard.check() # Expiry never excuses original ownership, even in cleanup. result = key.up_f(guard, deadline=lease, cleanup=cleanup) need(type(result) is dict and set(result)=={'key','up_monotonic','released'} and result['key']=='F' and result['released'] is True, 'Native F release is unconfirmed') up = number(result['up_monotonic']); returned = clock() need(event['attempted_monotonic'] <= up <= returned, 'Native F release timestamps invalid') event.update(monotonic=up, confirmed=True) state['up_monotonic']=up; state['release_confirmed']=True state['unconfirmed_held_key']=None; held=False notify({'kind':'held-key-release-confirmed','key':'F'}) if not cleanup: need(returned < lease and returned < deadline, 'F release exceeded immutable lease') try: pinned = copy.deepcopy(geometry); _, prison = target_for(pinned) state['nonce']=pinned['nonce']; state['geometry']=pinned selected = report.get('action_selection_proof', {}) need(type(selection_evidence) is dict and selection_evidence.get('verified') is True and selection_evidence.get('wheel_button')==5 and selected.get('completed') is True and selected.get('nonce')==pinned['nonce'] and selected.get('geometry')==pinned and selection_evidence.get('last_sample')==selected.get('final_sample'), 'Independently accepted same-run one-wheel selection required') prior = selected.get('samples', []) need(type(prior) is list and len(prior)>=2 and prior[-1]['sample']==selected['final_sample'], 'Original full selection samples unavailable') anchor = copy.deepcopy(prior[-1]); body=vector(anchor['origin']); view=yaw(anchor['direction']) actions = choices_for(anchor,pinned,selected_lock=True) need(selected.get('actions')==actions and type(selection_evidence.get('selected_action_id')) is int and selection_evidence['selected_action_id']==actions[1]['id'], 'Original selected lock identity mismatch') need(selected.get('selection_samples')==[prior[-2]['sample'],anchor['sample']] and anchor['sample']==prior[-2]['sample']+1 and 100<=anchor['real_ms']-prior[-2]['real_ms']<=500, 'Committed native selection pair missing') choices_for(prior[-2],pinned,selected_lock=True) queued=number(calibration['observer_start_real_ms']); ready=number(calibration['ready_real_ms']) ready_at=number(calibration['ready_monotonic']); started=state['started_monotonic'] need(calibration.get('nonce')==pinned['nonce'] and 0<=queued and 2000<=ready-queued<45000 and 0<=ready_at<=started, 'Original QUEUED/READY binding invalid') original=ready_at+(45000-(ready-queued))/1000-.5 supplied=number(calibration.get('observer_deadline_monotonic',original)) need(supplied<=original, 'Supplied observation deadline renews original lifetime') deadline=min(original,supplied,number(anchor['received_monotonic'])+(queued+45000-number(anchor['real_ms']))/1000-.5) state['original_deadline_monotonic']=deadline;state['actions']=actions state['selection_final_sample']=anchor['sample'] need(started=previous['sample'] and real>=previous['real_ms'] and receipt>=previous['received_monotonic'], 'Held native samples or receipts reversed') if index==previous['sample']: need(s==previous, 'Repeated held sample changed') return s need(index==previous['sample']+1 and 0=phase, 'Held phase reversed or left PRISON/RADIO_SEARCH') for flag in ('selected','context_selected','cached_performable','progress_bound','performing'): need(type(s[flag]) is bool, 'Malformed held action flag') value=number(s['progress']);pressed=number(s['pressed']);door=number(s['door_state']);control=number(s['door_control']) need(0<=value<=4 and 0<=pressed<=1 and number(s['duration'])==4 and -1<=door<=1 and -1<=control<=1, 'Invalid native action/door observation') geo=s['geometry'];need(type(geo) is dict and set(geo)==set(pinned) and geo['nonce']==pinned['nonce'] and geo['basis']==pinned['basis'] and math.dist(vector(geo['prison']),prison)<=.01, 'Original native gate geometry binding changed') for name in ('gate','gate_forward','context'):vector(geo[name]) need(.5<=length(geo['gate_forward'])<=2 and 0=down, 'Action sample predates actual F request') if pressed>0: pressed_ack=index if value>0: need(s['performing'] and pressed>0 and pressed_ack is not None, 'Progress lacks bound native input/performing proof') need(value>=progress, 'Native action progress decreased before transition') if value>progress: state['progress_samples'].append(index) progress=value elif progress>0: raise Refused('Native action progress reset before transition') if progress>0:need(s['performing'] and pressed>0,'Native action interrupted before transition') else: need(down is not None and index>state['press_sample'] and receipt>=down and pressed_ack is not None and len(state['progress_samples'])>=2, 'Phase transition lacks advancing bound progress from this F hold') if phase==1: state['transition_sample']=index;state['unlock_observed']=True state['status']='unlock-observed-motion-unverified' if abs(control)>.001 and state['control_sample'] is None:state['control_sample']=index if abs(door)>.001 and state['motion_sample'] is None:state['motion_sample']=index state['gate_motion_observed']=state['control_sample'] is not None and state['motion_sample'] is not None # After the full post-keyup drain, every subsequent native sample # is evidence. A neutral observation cannot be reused after renewed # action input, even if the reversal shares one buffered batch. if state['released_sample'] is not None: need(pressed==0 and value==0 and not s['performing'], 'Native action input renewed after release acknowledgement') if (release_barrier is not None and index>release_barrier and receipt>=state['up_monotonic'] and pressed==0 and value==0 and not s['performing']): state['released_sample']=index phase=s['phase'];previous=s state['samples'].append(copy.deepcopy(s));state['final_sample']=index if state['initial_sample'] is None:state['initial_sample']=index return s def read(idle=False): need(clock()=2 and samples[-1]['sample']==samples[-2]['sample']+1 and 100<=samples[-1]['real_ms']-samples[-2]['real_ms']<=500: break need(clock()+6<=deadline,'held-action-not-started: insufficient-original-budget') sleep(.025);current=read(idle=True) guard.check();require_idle() attempted=clock() not_after=min(deadline-6,current['received_monotonic']+.5) need(attempted<=not_after,'held-action-not-started: insufficient-original-budget-or-stale-pose') lease=min(deadline,attempted+5);release_due=lease-.75 state.update(press_attempted_monotonic=attempted,held_deadline_monotonic=lease,press_sample=current['sample'], input_attempted=True,status='failed-after-input',unconfirmed_held_key='F') held=True event={'key':'F','down':True,'attempted_monotonic':attempted,'confirmed':False} state['events'].append(event) notify({'kind':'held-key-pending','key':'F','deadline_monotonic':lease}) result=key.down_f(guard,deadline=lease,not_after=not_after) need(type(result) is dict and set(result)=={'key','down_monotonic'} and result['key']=='F','Unexpected held key adapter result') down=number(result['down_monotonic']) need(attempted<=down<=clock() and down<=not_after and clock()=release_due: raise Refused('Completion not observed before guarded F release reserve') current=read() if state['release_confirmed']: # Drain the entire first post-keyup batch before accepting a # newer native input acknowledgement. Never credit buffered # completion/reset samples merely received after our release. if release_barrier is None: release_barrier=current['sample'];state['release_barrier_sample']=release_barrier elif current['sample']>release_barrier and current['received_monotonic']>=state['up_monotonic'] and current['pressed']==0 and not current['performing'] and current['progress']==0: state['released_sample']=current['sample'] if state['unlock_observed'] and held:release() if (state['unlock_observed'] and state['gate_motion_observed'] and state['release_confirmed'] and state['released_sample']==current['sample'] and current['pressed']==0 and current['progress']==0 and not current['performing']): state['completed']=True;state['status']='verified' return state sleep(min(.025,max(0,deadline-clock()))) except Exception as error: state['error']=str(error) raise finally: if held: try:release(cleanup=True) except Exception as error:state['paired_release_errors'].append(str(error)) if state['unlock_observed'] and state['gate_motion_observed'] and not state['completed']: state['status']='failed-after-input' state['finished_monotonic']=clock() try: notify({'kind':'held-action-finished','successful':state['completed']}) except Exception as error: state['notification_errors'].append(str(error)) if 'error' not in state: state['completed']=False;state['status']='failed-after-input' if state['input_attempted'] else 'refused-no-input' state['error']=str(error) raise