Prepare independent successor playtest with spawn recovery and casualty feedback

This commit is contained in:
2026-09-19 22:12:52 +02:00
parent 61e165ef5b
commit 6cf989a060
266 changed files with 134064 additions and 154 deletions
+1 -1
View File
@@ -59,7 +59,7 @@ def check():
assert set(mapped)==set(inventory['script_paths']), 'Original inventory has untracked or unknown entries'
print(f'PASS: {len(mapped)} original script entries tracked across {len(feature_ids)} unfinished responsibilities')
print(f'PASS: {len(ids)} isolated addons, acyclic dependencies, {len(resources)} unique resources, exact vanilla references')
for name in ['test_aircraft_field_probe.py', 'test_aircraft_field_runner.py', 'test_aircraft_field_rules.py', 'test_aircraft_field_envelope.py', 'test_aircraft_field_flight.py', 'test_command_maintenance.py', 'test_aircraft_service.py', 'test_aircraft_service_cancel_runner.py', 'test_prison_action_selection_proof.py', 'test_prison_action_selection_evidence.py', 'test_ordinary_gate_choices.py', 'test_aircraft_control_bridge.py', 'test_prison_alignment_proof.py', 'test_prison_alignment_evidence.py', 'test_aircraft_route_demand.py', 'test_prison_approach_proof.py', 'test_prison_approach_evidence.py', 'test_ordinary_gate_evidence.py', 'test_ordinary_gate_observer.py', 'test_ordinary_look_observer.py', 'test_ordinary_look_evidence.py', 'test_relative_look_runner.py', 'test_radio_waiting_text.py', 'test_inventory_control_runner.py', 'test_inventory_layout.py', 'test_headless_input_proof.py', 'test_headless_input_exercise_runner.py', 'test_private_prefix_cleanup.py', 'test_runner_private_cleanup.py', 'test_ordinary_input_runner.py', 'test_ordinary_input_observer.py', 'test_aircraft_route_envelope.py', 'test_aircraft_route_policy.py', 'test_aircraft_route_probe.py', 'test_rough_intel_feedback.py', 'test_headless_display_probe.py', 'test_headless_display_runner.py', 'test_preparation_status.py', 'test_hint_delivery.py', 'test_native_end_lifecycle.py', 'test_native_end_runner.py', 'test_escape_result_wording.py', 'test_native_stats.py', 'test_aircraft_translation.py', 'test_spawn_retry_budget.py', 'test_action_feedback.py', 'test_native_aircraft_control.py', 'test_aircraft_flight_policy.py', 'test_aircraft_flight_envelope.py', 'test_ordinary_screenshot.py', 'test_participant_selection.py', 'test_native_shared_map_ownership.py', 'test_shared_map_ownership.py', 'test_intel_registration.py', 'test_mortar_activity_completion.py', 'test_packed_chat_game.py', 'test_native_mortar_refresh.py', 'test_archive_packed.py', 'test_mortar_refresh.py', 'test_packed_core_game.py', 'test_pak_inventory.py', 'test_native_mortar_salvo.py', 'test_spectator_guidance.py', 'test_native_package.py', 'test_item_station_teardown.py', 'test_source_bundle.py', 'test_native_flight_footprint.py', 'test_native_flight_input_diagnostics.py', 'test_mortar_logistics.py', 'test_mortar_courier_storage.py','test_powered_flight_pad.py','test_prison_escape_policy.py','test_powered_flight_policy.py','test_flight_action_runner.py','test_native_local_admission_probe.py','test_mortar_report_ledger.py','test_dedicated_native.py','test_native_mortar_transfer.py','test_mortar_aim_renewal.py','test_dedicated_preflight.py','test_mortar_transactions.py','test_native_mortar_probe.py','test_diagnostic_no_splash.py','test_casualty_incapacitation.py','test_casualty_remove_probe.py','test_extraction_placement_policy.py','test_guard_cancellation_policy.py','test_casualty_ground_policy.py','test_casualty_reservation_death.py','test_casualty_loading_policy.py','test_initial_guard_policy.py','test_headless_game_runner.py','test_vanilla_game_control.py','test_archive_game_control.py','test_site_discovery_policy.py','test_faction_catalog_scope.py','test_mission_rules.py','test_admin_setting_policy.py', 'test_player_admission_policy.py','test_progression_identity.py','test_discovery_map_position.py','test_local_admission.py','test_prison_placement_policy.py', 'test_recovery_policy.py','test_time_policy.py','test_environment_policy.py','test_environment_restart_runner.py', 'test_inventory_enumeration_policy.py','test_radio_defence_policy.py','test_radio_feedback_policy.py','test_performance_comparison.py','test_release_check.py','test_settings_migration.py','hq_network_regression.py','helicopter_availability_regression.py','mortar_salvo_regression.py']:
for name in ['test_casualty_feedback.py', 'test_initial_admission_exhaustion.py', 'test_prison_held_action_proof.py', 'test_prison_held_action_evidence.py', 'test_prison_held_input_adapter.py', 'test_prison_held_runner.py', 'test_prison_coarse_facing.py', 'test_aircraft_field_probe.py', 'test_aircraft_field_runner.py', 'test_aircraft_field_rules.py', 'test_aircraft_field_envelope.py', 'test_aircraft_field_flight.py', 'test_command_maintenance.py', 'test_aircraft_service.py', 'test_aircraft_service_cancel_runner.py', 'test_prison_action_selection_proof.py', 'test_prison_action_selection_evidence.py', 'test_ordinary_gate_choices.py', 'test_aircraft_control_bridge.py', 'test_prison_alignment_proof.py', 'test_prison_alignment_evidence.py', 'test_aircraft_route_demand.py', 'test_prison_approach_proof.py', 'test_prison_approach_evidence.py', 'test_ordinary_gate_evidence.py', 'test_ordinary_gate_observer.py', 'test_ordinary_look_observer.py', 'test_ordinary_look_evidence.py', 'test_relative_look_runner.py', 'test_radio_waiting_text.py', 'test_inventory_control_runner.py', 'test_inventory_layout.py', 'test_headless_input_proof.py', 'test_headless_input_exercise_runner.py', 'test_private_prefix_cleanup.py', 'test_runner_private_cleanup.py', 'test_ordinary_input_runner.py', 'test_ordinary_input_observer.py', 'test_aircraft_route_envelope.py', 'test_aircraft_route_policy.py', 'test_aircraft_route_probe.py', 'test_rough_intel_feedback.py', 'test_headless_display_probe.py', 'test_headless_display_runner.py', 'test_preparation_status.py', 'test_hint_delivery.py', 'test_native_end_lifecycle.py', 'test_native_end_runner.py', 'test_escape_result_wording.py', 'test_native_stats.py', 'test_aircraft_translation.py', 'test_spawn_retry_budget.py', 'test_action_feedback.py', 'test_native_aircraft_control.py', 'test_aircraft_flight_policy.py', 'test_aircraft_flight_envelope.py', 'test_ordinary_screenshot.py', 'test_participant_selection.py', 'test_native_shared_map_ownership.py', 'test_shared_map_ownership.py', 'test_intel_registration.py', 'test_mortar_activity_completion.py', 'test_packed_chat_game.py', 'test_native_mortar_refresh.py', 'test_archive_packed.py', 'test_mortar_refresh.py', 'test_packed_core_game.py', 'test_pak_inventory.py', 'test_native_mortar_salvo.py', 'test_spectator_guidance.py', 'test_native_package.py', 'test_item_station_teardown.py', 'test_source_bundle.py', 'test_native_flight_footprint.py', 'test_native_flight_input_diagnostics.py', 'test_mortar_logistics.py', 'test_mortar_courier_storage.py','test_powered_flight_pad.py','test_prison_escape_policy.py','test_powered_flight_policy.py','test_flight_action_runner.py','test_native_local_admission_probe.py','test_mortar_report_ledger.py','test_dedicated_native.py','test_native_mortar_transfer.py','test_mortar_aim_renewal.py','test_dedicated_preflight.py','test_mortar_transactions.py','test_native_mortar_probe.py','test_diagnostic_no_splash.py','test_casualty_incapacitation.py','test_casualty_remove_probe.py','test_extraction_placement_policy.py','test_guard_cancellation_policy.py','test_casualty_ground_policy.py','test_casualty_reservation_death.py','test_casualty_loading_policy.py','test_initial_guard_policy.py','test_headless_game_runner.py','test_vanilla_game_control.py','test_archive_game_control.py','test_site_discovery_policy.py','test_faction_catalog_scope.py','test_mission_rules.py','test_admin_setting_policy.py', 'test_player_admission_policy.py','test_progression_identity.py','test_discovery_map_position.py','test_local_admission.py','test_prison_placement_policy.py', 'test_recovery_policy.py','test_time_policy.py','test_environment_policy.py','test_environment_restart_runner.py', 'test_inventory_enumeration_policy.py','test_radio_defence_policy.py','test_radio_feedback_policy.py','test_performance_comparison.py','test_release_check.py','test_settings_migration.py','hq_network_regression.py','helicopter_availability_regression.py','mortar_salvo_regression.py']:
subprocess.run([sys.executable,str(ROOT/'tests'/name)],check=True)
print('All repository checks passed. Native compilation and multiplayer tests are separate requirements.')
if __name__=='__main__':check()
+88 -6
View File
@@ -637,6 +637,10 @@ def validate_input_observer(a):
def validate_input_exercise(a):
if type(getattr(a, 'exercise_prison_held_action', False)) is not bool or (getattr(a, 'exercise_prison_held_action', False) and not (getattr(a, 'exercise_prison_selection', False) and getattr(a, 'exercise_prison_coarse_facing', False))):
refuse('Prison held action requires explicit selection and coarse facing')
if type(getattr(a, 'exercise_prison_coarse_facing', False)) is not bool or (getattr(a, 'exercise_prison_coarse_facing', False) and not (getattr(a, 'exercise_prison_coarse_approach', False) and getattr(a, 'exercise_prison_selection', False))):
refuse('Coarse facing requires explicit coarse approach and selection')
if getattr(a, 'exercise_prison_selection', False) and not (getattr(a, 'exercise_prison_alignment', False) and getattr(a, 'observe_prison_choices', False)):
refuse('Prison action selection requires explicit alignment and native choices')
if getattr(a, 'observe_prison_choices', False) and getattr(a, 'exercise_player_input', False) and not getattr(a, 'exercise_prison_approach', False):
@@ -662,7 +666,7 @@ def validate_input_exercise(a):
refuse('Input exercise requires --settle >=50')
def input_observer_command(command, project, packed, nonce, look=False, gate=False, choices=False):
def input_observer_command(command, project, packed, nonce, look=False, gate=False, choices=False, held_action=False):
if project not in {'core', 'chat'} or packed is not None:
refuse('Input observation requires loose Core or Chat')
if not re.fullmatch(r'[A-Za-z0-9]{1,32}', nonce):
@@ -673,7 +677,9 @@ def input_observer_command(command, project, packed, nonce, look=False, gate=Fal
refuse('Prison choices require explicit boolean gate observation')
if type(gate) is not bool:
refuse('Prison gate observation selection must be boolean')
if any(value.startswith(('-errOrdinaryInput', '-errOrdinaryLook', '-errOrdinaryGate')) for value in command):
if type(held_action) is not bool or (held_action and not (look and gate and choices)):
refuse('Held action observation requires explicit look, gate and choices')
if any(value.startswith(('-errOrdinaryInput', '-errOrdinaryLook', '-errOrdinaryGate', '-errOrdinaryHeld')) for value in command):
refuse('Input observer command already has observer options')
options = ['-errOrdinaryInputObserve', nonce, '-errOrdinaryInputScreenshots', '1']
if look:
@@ -682,6 +688,8 @@ def input_observer_command(command, project, packed, nonce, look=False, gate=Fal
options += ['-errOrdinaryGateObserve', nonce]
if choices:
options += ['-errOrdinaryGateChoices', nonce]
if held_action:
options += ['-errOrdinaryHeldAction', nonce]
return command + options
@@ -882,7 +890,17 @@ def selection_module_hashes(root):
return hashes
def input_exercise_command(command, root, compat, profile, executable, run_id, host_display, display_context, look=False, approach=False, alignment=False, selection=False, coarse_approach=False):
def held_module_hashes(root):
hashes = {}
for name in ('prison_held_action_proof.py', 'prison_held_action_evidence.py'):
path = root/'tools'/name
if path.is_symlink() or not path.is_file():
refuse('Held action requires regular local proof modules')
hashes[name] = hashlib.sha256(path.read_bytes()).hexdigest()
return hashes
def input_exercise_command(command, root, compat, profile, executable, run_id, host_display, display_context, look=False, approach=False, alignment=False, selection=False, coarse_approach=False, coarse_facing=False, held_action=False):
"""Put the input supervisor around the display inspector, inside Gamescope."""
separator = command.index('--')
if command[:separator].count('--backend') != 1 or command[command.index('--backend')+1] != 'headless':
@@ -893,6 +911,10 @@ def input_exercise_command(command, root, compat, profile, executable, run_id, h
if (not display_context or len(child) < 3 or child[:2] != [sys.executable, str(ownership)]
or not re.fullmatch(r'[A-Za-z0-9]{1,32}', run_id)):
refuse('Input exercise requires the existing scoped display wrapper and observer nonce')
if type(held_action) is not bool or (held_action and not (selection and coarse_facing)):
refuse('Held action requires explicit selection and coarse facing')
if type(coarse_facing) is not bool or (coarse_facing and not (coarse_approach and selection)):
refuse('Coarse facing requires explicit coarse approach and selection')
if type(coarse_approach) is not bool or (coarse_approach and not approach):
refuse('Coarse approach requires explicit approach')
if type(selection) is not bool or (selection and not alignment):
@@ -901,6 +923,12 @@ def input_exercise_command(command, root, compat, profile, executable, run_id, h
refuse('Prison alignment requires explicit prior approach')
if type(approach) is not bool or (approach and not look):
refuse('Prison approach requires explicit relative look')
held_tokens = [i for i,value in enumerate(child) if value.startswith('-errOrdinaryHeld')]
if held_action:
if len(held_tokens) != 1 or child[held_tokens[0]] != '-errOrdinaryHeldAction' or child[held_tokens[0]+1:held_tokens[0]+2] != [run_id]:
refuse('Held action requires its exact native observer nonce')
elif held_tokens:
refuse('Unexpected native held-action option')
gate_tokens = [value for value in child if value.startswith('-errOrdinaryGate')]
if selection and '-errOrdinaryGateChoices' not in gate_tokens:
refuse('Action selection requires exact native choices')
@@ -939,6 +967,9 @@ def input_exercise_command(command, root, compat, profile, executable, run_id, h
context['approach_requested'] = True
context['approach_module_sha256'] = approach_module_hashes(root)
wrapper.insert(-1, '--enable-private-approach-proof')
if coarse_facing:
context['coarse_facing_requested'] = True
wrapper.insert(-1, '--enable-private-coarse-facing-proof')
if coarse_approach:
context['coarse_approach_requested'] = True
wrapper.insert(-1, '--enable-private-coarse-approach-proof')
@@ -950,6 +981,10 @@ def input_exercise_command(command, root, compat, profile, executable, run_id, h
context['selection_requested'] = True
context['selection_module_sha256'] = selection_module_hashes(root)
wrapper.insert(-1, '--enable-private-selection-proof')
if held_action:
context['held_action_requested'] = True
context['held_module_sha256'] = held_module_hashes(root)
wrapper.insert(-1, '--enable-private-held-action-proof')
return command[:separator+1] + wrapper + child, context
@@ -971,6 +1006,10 @@ def input_exercise_poll_failure(context):
for key in ('helper_sha256', 'ownership_helper_sha256', 'prefix', 'profile', 'game_executable', 'report', 'command', 'nonce'):
if report.get(key) != context[key]:
return False
if type(report.get('held_action_requested', False)) is not bool or report.get('held_action_requested', False) != context.get('held_action_requested', False):
return False
if context.get('held_action_requested') and report.get('held_module_sha256') != context.get('held_module_sha256'):
return False
if context.get('selection_requested') and report.get('selection_module_sha256') != context.get('selection_module_sha256'):
return False
if report.get('selection_requested', False) != context.get('selection_requested', False):
@@ -985,6 +1024,8 @@ def input_exercise_poll_failure(context):
return None
if type(report.get('coarse_approach_requested', False)) is not bool or report.get('coarse_approach_requested', False) != context.get('coarse_approach_requested', False):
return False
if type(report.get('coarse_facing_requested', False)) is not bool or report.get('coarse_facing_requested', False) != context.get('coarse_facing_requested', False):
return False
if report.get('look_requested', False) != context.get('look_requested', False):
return False
return bool(report.get('error') or report.get('supervision_failed') is True or (
@@ -1028,6 +1069,15 @@ def input_exercise_result(result, context, session, observation, display_result)
for key in ('helper_sha256', 'ownership_helper_sha256', 'prefix', 'profile', 'game_executable', 'report', 'command', 'nonce'):
if report.get(key) != context[key]:
refuse('Input report binding mismatch: '+key)
held_action_requested = context.get('held_action_requested', False)
if type(held_action_requested) is not bool or type(report.get('held_action_requested', False)) is not bool or report.get('held_action_requested', False) != held_action_requested:
refuse('Held action request does not match launch context')
if held_action_requested and (context.get('selection_requested') is not True or context.get('coarse_facing_requested') is not True or report.get('held_module_sha256') != context.get('held_module_sha256') or context.get('held_module_sha256') != held_module_hashes(ROOT)):
refuse('Held action requires explicit coarse selection and unchanged module sources')
if not held_action_requested and (report.get('held_action_proof') is not None or report.get('held_events')):
refuse('Unexpected held action evidence or F input')
if report.get('held_release_errors', []) != []:
refuse('Held F release is unconfirmed')
selection_requested = context.get('selection_requested', False)
if type(report.get('selection_requested', False)) is not bool or report.get('selection_requested', False) != selection_requested:
refuse('Action selection request does not match launch context')
@@ -1058,6 +1108,12 @@ def input_exercise_result(result, context, session, observation, display_result)
refuse('Coarse approach request does not match explicit launch context')
if approach_requested and report.get('approach_proof', {}).get('profile', 'standard') != ('coarse' if coarse_approach_requested else 'standard'):
refuse('Approach profile does not match explicit launch context')
coarse_facing_requested = context.get('coarse_facing_requested', False)
if type(coarse_facing_requested) is not bool or type(report.get('coarse_facing_requested', False)) is not bool or report.get('coarse_facing_requested', False) != coarse_facing_requested or (coarse_facing_requested and not (coarse_approach_requested and selection_requested)):
refuse('Coarse facing request does not match explicit launch context')
facing_profile = 'coarse' if coarse_facing_requested else 'standard'
if report.get('facing_proof', {}).get('profile', 'standard') != facing_profile:
refuse('Facing profile does not match explicit launch context')
look_requested = context.get('look_requested', False)
if type(report.get('look_requested', False)) is not bool or report.get('look_requested', False) != look_requested:
refuse('Relative look request does not match launch context')
@@ -1121,10 +1177,34 @@ def input_exercise_result(result, context, session, observation, display_result)
if (not isinstance(event,dict) or type(event.get('button')) is not int or event['button'] != 5 or event.get('down') is not down or event.get('sent') is not True or event.get('finally')
or type(event.get('monotonic')) not in (int,float) or not math.isfinite(event['monotonic']) or type(wheel.get(key)) not in (int,float) or not math.isfinite(wheel[key]) or abs(event['monotonic']-wheel[key]) > .01):
refuse('Selection wheel adapter and policy pair disagree')
proof['action_selection_proof'] = validate_selection_evidence((session/'console.log').read_text(errors='replace'),context['nonce'],report.get('look_proof'),route,report.get('facing_proof'),selected)
proof['action_selection_proof'] = validate_selection_evidence((session/'console.log').read_text(errors='replace'),context['nonce'],report.get('look_proof'),route,report.get('facing_proof'),selected,facing_profile=facing_profile)
proof['scope'] = 'ordinary private approach, stationary facing and one wheel pair with independent native original-lock selection; no F hold, unlock, exit or multiplayer qualification'
if proof['action_selection_proof'].get('verified') is not True:
refuse('Independent native action-selection evidence is incomplete')
if held_action_requested:
from prison_held_action_evidence import validate_held_action_evidence
held = report.get('held_action_proof', {})
held_events = report.get('held_events', [])
policy_events = held.get('events', [])
if (held.get('completed') is not True or held.get('status') != 'verified' or held.get('input_attempted') is not True
or held.get('release_confirmed') is not True or held.get('unconfirmed_held_key') is not None
or held.get('paired_release_errors') != [] or held.get('notification_errors') != [] or held.get('error')
or not isinstance(held_events, list) or len(held_events) != 2 or not isinstance(policy_events, list) or len(policy_events) != 2):
refuse('Held action lacks exactly one confirmed F pair')
for event, policy_event, down, field in zip(held_events,policy_events,(True,False),('down_monotonic','up_monotonic')):
stamp = event.get('monotonic') if isinstance(event,dict) else None
if (not isinstance(event,dict) or set(event) != {'key','down','monotonic','sent'} or event.get('key') != 'F' or event.get('down') is not down or event.get('sent') is not True
or type(stamp) not in (int,float) or not math.isfinite(stamp) or stamp < 0
or not isinstance(policy_event,dict) or policy_event.get('key') != 'F' or policy_event.get('down') is not down or policy_event.get('confirmed') is not True or policy_event.get('cleanup')
or type(policy_event.get('monotonic')) not in (int,float) or policy_event['monotonic'] != stamp
or type(held.get(field)) not in (int,float) or held[field] != stamp):
refuse('Held F adapter and policy pair disagree')
if not held_events[0]['monotonic'] < held_events[1]['monotonic'] or held_events[1]['monotonic']-held_events[0]['monotonic'] > 5 or held_events[0]['monotonic'] <= buttons[-1]['monotonic']:
refuse('Held F pair violates order or five-second bound')
proof['held_action_proof'] = validate_held_action_evidence((session/'console.log').read_text(errors='replace'),context['nonce'],report.get('look_proof'),route,report.get('facing_proof'),selected,held,facing_profile=facing_profile)
proof['scope'] = 'ordinary private approach, selection and one held F action with independent native unlock, original door motion and released-input evidence; no gate passage, full escape or multiplayer qualification'
if any(proof['held_action_proof'].get(key) is not True for key in ('verified','held_action_verified','unlock_observed','gate_motion_observed')):
refuse('Independent native held-action evidence is incomplete')
elif alignment_requested:
from prison_alignment_evidence import validate_alignment_evidence
proof['alignment_proof'] = validate_alignment_evidence((session/'console.log').read_text(errors='replace'), context['nonce'], report.get('look_proof'), route, report.get('alignment_proof'))
@@ -1206,13 +1286,13 @@ def run_locked(a, steam, compat, profile, packed=None):
run_id = uuid.uuid4().hex
observation_nonce = run_id if getattr(a, 'observe_player_input', False) else None
if observation_nonce:
command = input_observer_command(command, a.project, packed, observation_nonce, getattr(a, 'exercise_relative_look', False), getattr(a, 'observe_prison_gate', False), getattr(a, 'observe_prison_choices', False))
command = input_observer_command(command, a.project, packed, observation_nonce, getattr(a, 'exercise_relative_look', False), getattr(a, 'observe_prison_gate', False), getattr(a, 'observe_prison_choices', False), getattr(a, 'exercise_prison_held_action', False))
display_context = None
if getattr(a, 'inspect_headless_display', False):
command, display_context = display_probe_command(command, ROOT, compat, profile, executable, run_id, os.environ.get('DISPLAY', ''))
exercise_context = None
if getattr(a, 'exercise_player_input', False):
command, exercise_context = input_exercise_command(command, ROOT, compat, profile, executable, run_id, os.environ.get('DISPLAY', ''), display_context, getattr(a, 'exercise_relative_look', False), getattr(a, 'exercise_prison_approach', False), getattr(a, 'exercise_prison_alignment', False), getattr(a, 'exercise_prison_selection', False), getattr(a, 'exercise_prison_coarse_approach', False))
command, exercise_context = input_exercise_command(command, ROOT, compat, profile, executable, run_id, os.environ.get('DISPLAY', ''), display_context, getattr(a, 'exercise_relative_look', False), getattr(a, 'exercise_prison_approach', False), getattr(a, 'exercise_prison_alignment', False), getattr(a, 'exercise_prison_selection', False), getattr(a, 'exercise_prison_coarse_approach', False), getattr(a, 'exercise_prison_coarse_facing', False), getattr(a, 'exercise_prison_held_action', False))
silent_sink = 'erri_game_'+run_id
application_id = 'org.escapistsrereintroduced.game.'+run_id
env = os.environ.copy()
@@ -1377,8 +1457,10 @@ def main():
parser.add_argument('--capture-prison-view', action='store_true', help='Opt-in single genuine local prison screenshot; loose successor source only, no camera or input changes')
parser.add_argument('--observe-player-input', action='store_true', help='Read-only native local-input sampler; loose Core/Chat only, requires --settle >=50; sends no input')
parser.add_argument('--approach-wide-display', action='store_true', help='Use a disposable 2560x720 headless viewport for the explicit approach experiment; no physical display changes')
parser.add_argument('--exercise-prison-held-action', action='store_true', help='Explicit single held-F unlock experiment after coarse facing and selection; requires independent native progress, original door motion and release evidence')
parser.add_argument('--exercise-prison-selection', action='store_true', help='Explicit facing and single wheel selection trial; requires alignment and native choice diagnostics; no F or gate operation')
parser.add_argument('--exercise-prison-alignment', action='store_true', help='Explicit stationary yaw-only alignment to native prison lock after verified approach; no F or gate operation')
parser.add_argument('--exercise-prison-coarse-facing', action='store_true', help='Explicit coarse yaw facing; requires coarse approach and selection, unchanged total pixels and clocks')
parser.add_argument('--exercise-prison-coarse-approach', action='store_true', help='Explicit coarse stationary-heading approach profile; requires approach and retains original clocks; no F')
parser.add_argument('--exercise-prison-approach', action='store_true', help='Explicit bounded relative-mouse/W approach inside prison; requires relative look and gate observer; never operates gate')
parser.add_argument('--observe-prison-choices', action='store_true', help='Read-only native selected/ordered gate action diagnostics; requires --observe-prison-gate')
+283 -22
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
"""Opt-in bounded private XTest keyboard and optional relative-look experiment. Not a launcher or gameplay proof."""
import argparse
import copy
import ctypes as C
import hashlib
import json
@@ -46,9 +47,19 @@ def option(args, name):
def gate_options(native, args):
# Two exact read-only options; a prefix match must never admit an alias,
# duplicate, foreign nonce or extra diagnostic in keyboard-only mode.
held = getattr(args, 'enable_private_held_action_proof', False)
held_tokens = [value for value in native if value.startswith('-errOrdinaryHeld')]
if type(held) is not bool or (held and not (getattr(args, 'enable_private_coarse_facing_proof', False) and getattr(args, 'enable_private_selection_proof', False))):
raise Refused('Held action requires explicit coarse facing and selection')
if held_tokens != (['-errOrdinaryHeldAction'] if held else []):
raise Refused('Unexpected, missing or repeated native held observer option')
if held and option(native, '-errOrdinaryHeldAction') != args.nonce:
raise Refused('Native held observer nonce mismatch')
tokens = [value for value in native if value.startswith('-errOrdinaryGate')]
if any(value not in {'-errOrdinaryGateObserve', '-errOrdinaryGateChoices'} for value in tokens):
raise Refused('Unknown native gate observer option')
if getattr(args, 'enable_private_coarse_facing_proof', False) and not (getattr(args, 'enable_private_coarse_approach_proof', False) and getattr(args, 'enable_private_selection_proof', False)):
raise Refused('Coarse facing requires coarse approach and selection')
approach = getattr(args, 'enable_private_approach_proof', False)
if getattr(args, 'enable_private_coarse_approach_proof', False) and not approach:
raise Refused('Coarse approach requires explicit approach proof')
@@ -136,9 +147,14 @@ def yaw_delta(first, second):
class RelativeMouse:
def __init__(self, query, keyboard, owner, enable_approach=False, enable_alignment=False, enable_coarse_approach=False):
def __init__(self, query, keyboard, owner, enable_approach=False, enable_alignment=False, enable_coarse_approach=False, enable_coarse_facing=False, enable_selection=False):
if type(enable_coarse_approach) is not bool or (enable_coarse_approach and not enable_approach):
raise Refused("Coarse approach requires explicit approach capability")
if type(enable_coarse_facing) is not bool or (enable_coarse_facing and not (enable_coarse_approach is True and enable_alignment is True and enable_selection is True)):
raise Refused('Coarse facing requires explicit selection and coarse approach capability')
self.enable_coarse_facing = enable_coarse_facing
self.alignment_pixels = 0
self.alignment_requests = 0
self.enable_coarse_approach = enable_coarse_approach
self.query, self.keyboard, self.owner = query, keyboard, owner
self.enable_approach = enable_approach
@@ -189,13 +205,19 @@ class RelativeMouse:
def alignment_move(self, dx, dy, guard, *, deadline, clock=time.monotonic):
if (self.enable_alignment is not True or self.enable_approach is not True or type(dx) is not int
or not 1 <= abs(dx) <= 128 or type(dy) is not int or dy != 0):
or not 1 <= abs(dx) <= (384 if self.enable_coarse_facing else 128) or type(dy) is not int or dy != 0):
raise Refused('Unsupported or unenabled alignment relative step')
def within_lease():
if clock() >= deadline:
if type(deadline) not in (int, float) or not math.isfinite(deadline) or not 0 <= clock() < deadline:
raise Refused('Original alignment deadline exceeded before relative input')
within_lease()
self._move(dx, dy, guard, before_send=within_lease)
if self.alignment_requests >= 6 or self.alignment_pixels+abs(dx) > 768:
raise Refused('Alignment request or cumulative pixel budget exhausted')
def commit():
within_lease()
self.alignment_requests += 1
self.alignment_pixels += abs(dx)
self._move(dx, dy, guard, before_send=commit)
def _move(self, dx, dy, guard, before_send=None):
target = guard.check()
@@ -304,7 +326,11 @@ class Observer:
"""Only records appended after this exact owned console was opened count."""
pattern = re.compile(r'ERR INPUT OBSERVE: run=([A-Za-z0-9]{1,32}) sample=(\d+) real=(\d+) world=(\d+(?:\.\d+)?) (.+)$')
def __init__(self, path, nonce, clock=time.monotonic, enable_look=False, enable_approach=False, enable_selection=False):
def __init__(self, path, nonce, clock=time.monotonic, enable_look=False, enable_approach=False, enable_selection=False, enable_held=False):
if type(enable_held) is not bool or (enable_held and not (enable_selection and enable_approach and enable_look)):
raise Refused('Held observation requires all original observation capabilities')
self.enable_held = enable_held
self.held_previous = None; self.held_anchor = None
self.path, self.nonce, self.clock = path, nonce, clock
self.fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
info = os.fstat(self.fd)
@@ -476,8 +502,42 @@ class Observer:
def selection_snapshots(self):
return self._snapshot_batch('selection_previous')
def _snapshot_batch(self, cursor):
def begin_held(self, final_sample):
if self.enable_held is not True or self.held_anchor is not None or type(final_sample) is not int:
raise Refused('Held observation cannot be started or re-adopted')
_, data = self.approach_data()
if final_sample not in data['snapshots'] or final_sample < data['ready']['sample']:
raise Refused('Held observation lacks original selection anchor')
self.held_anchor = final_sample; self.held_previous = final_sample-1
def held_data(self):
# Native observer retains original world/player/action/door objects; the
# same acknowledged stream may show their moving geometry after phase2.
# Do not run the closed-yard geometry validator on that moving door.
from ordinary_gate_choices import join_choice_snapshots
self.fresh()
if (self.enable_held is not True or self.held_anchor is None or self.events != ['READY'] or
not self.gate_complete_end or any(r['kind'] == 'cancelled' for r in self.gate_records+self.look_records)):
raise Refused('Original held observation context ended or was not adopted')
content = '\n'.join(self.approach_lines[:self.gate_complete_end])
data = join_choice_snapshots(content, self.nonce)
latest = max(data['snapshots'])
if (latest < self.held_anchor or self.clock()-self.gate_received[latest] > .5 or
self.input_samples[-1]['real_ms']-data['snapshots'][latest]['real_ms'] > 500):
raise Refused('Original held native snapshot is stale or reversed')
phase = 1
for index in range(self.held_anchor, latest+1):
item = data['snapshots'][index]
if item['action']['phase'] < phase or item['input']['inventory']:
raise Refused('Original held phase or menu context changed')
phase = item['action']['phase']
return content, data
def held_snapshots(self):
return self._snapshot_batch('held_previous')
def _snapshot_batch(self, cursor):
_, data = self.held_data() if cursor == 'held_previous' else self.approach_data()
snapshots = data['snapshots']; latest = max(snapshots)
previous = getattr(self, cursor)
first = latest if previous is None else min(previous + 1, latest)
@@ -493,9 +553,11 @@ class Observer:
'inventory': native['inventory'], 'phase': action['phase'], 'door_state': geo['door_state'], 'door_control': geo['door_control'],
'geometry': {'nonce': self.nonce, 'basis': 'registered-prison-lock-native-interaction',
**{key: geo[key] for key in ('prison', 'gate', 'gate_forward', 'context', 'radius')}}})
if self.enable_held:
result[-1].update(world_ms=native['world_ms'], turn=pose['turn'])
if self.enable_selection:
choice = item['choices']
if cursor != 'approach_previous' and action['context_selected']:
if cursor != 'approach_previous' and action['phase'] == 1 and action['context_selected']:
from ordinary_gate_choices import exact_prison_choices
choice = exact_prison_choices(item)
result[-1]['choices'] = {key: choice[key] for key in ('nonce','sample','real_ms','selected_id','selected_class','actions')}
@@ -545,6 +607,89 @@ class Keyboard:
self.query.x.XFlush(self.query.d)
class HeldFKey:
"""One F-only attempt on the captured private connection; never creates one."""
def __init__(self, guard, keyboard, mouse, report, clock, sleep, original_deadline, *, enabled=False):
if enabled is not True or type(original_deadline) not in (int,float) or not math.isfinite(original_deadline):
raise Refused('Held F requires explicit capability and original deadline')
self.guard, self.keyboard, self.mouse = guard, keyboard, mouse
self.query, self.xt = keyboard.query, keyboard.xt
self.owner = copy.deepcopy(mouse.owner)
self.report, self.clock, self.sleep = report, clock, sleep
self.original_deadline = original_deadline
self.attempted = False; self.pending = False; self.lease = None; self.up_attempts = 0
self._context(guard)
self.code = int(self.query.x.XKeysymToKeycode(self.query.d, 0x66))
if (not 8 <= self.code <= 255 or self.query.x.XKeycodeToKeysym(self.query.d, self.code, 0) != 0x66 or
self.code in keyboard.codes.values()):
raise Refused('Default distinct unmodified F mapping unavailable')
report.setdefault('held_events', []); report.setdefault('held_release_errors', [])
def _context(self, guard):
if (guard is not self.guard or self.guard.query is not self.query or self.keyboard.query is not self.query or
self.mouse.query is not self.query or self.mouse.keyboard is not self.keyboard or
self.keyboard.xt is not self.xt or self.mouse.owner != self.owner or self.guard.owner != self.owner):
raise Refused('Captured F owner or connection changed')
def _owned(self, guard, *, idle):
self._context(guard)
target = guard.check()
if idle: self.keyboard.require_idle()
self.mouse.validate_pointer(target,0,0)
target = guard.check()
if idle: self.keyboard.require_idle()
self.mouse.validate_pointer(target,0,0)
self._context(guard)
def down_f(self, guard, *, deadline, not_after):
if (self.attempted or type(deadline) not in (int,float) or not math.isfinite(deadline) or
type(not_after) not in (int,float) or not math.isfinite(not_after) or
not 0 <= self.clock() <= not_after <= self.original_deadline-6 or
not self.clock() < deadline <= min(self.original_deadline,self.clock()+5)):
raise Refused('Repeated, expired or unqualified held F admission')
# The numeric original keycode is retained for cleanup even if its
# mapping later changes; never redirect key-up to a new F keycode.
self.attempted = True; self.pending = True; self.lease = deadline
self.report['unconfirmed_held_key'] = 'F'
self._owned(guard,idle=True)
if self.query.x.XKeycodeToKeysym(self.query.d,self.code,0) != 0x66:
raise Refused('Original F mapping changed before down')
now = self.clock()
if not 0 <= now <= not_after or now >= self.lease:
raise Refused('Six-second admission or native pose freshness expired before F')
event = {'key':'F','down':True,'monotonic':now,'sent':False}
self.report['held_events'].append(event); self.report['input_attempted'] = True
if not self.xt.XTestFakeKeyEvent(self.query.d,self.code,1,0):
raise Refused('Native held F down request uncertain')
self.query.x.XFlush(self.query.d)
event['sent'] = True; self.report['input_sent'] = True
return {'key':'F','down_monotonic':now}
def up_f(self, guard, *, deadline, cleanup=False):
try:
if (type(cleanup) is not bool or not self.attempted or not self.pending or self.up_attempts >= 2 or
type(deadline) not in (int,float) or not math.isfinite(deadline) or deadline != self.lease):
raise Refused('Unowned, repeated or renewed held F release')
self.up_attempts += 1
self._owned(guard,idle=False)
now = self.clock()
if not math.isfinite(now) or now < 0 or (not cleanup and now >= min(self.lease,self.original_deadline)):
raise Refused('Original F release deadline expired')
event = {'key':'F','down':False,'monotonic':now,'sent':False}
if cleanup: event['finally'] = True
self.report['held_events'].append(event); self.report['input_attempted'] = True
if not self.xt.XTestFakeKeyEvent(self.query.d,self.code,0,0):
raise Refused('Native held F up request uncertain')
self.query.x.XFlush(self.query.d)
event['sent'] = True; self.report['input_sent'] = True
confirm_release(guard,self.keyboard,self.report,'F',self.clock,self.sleep)
self.pending = False; self.report['unconfirmed_held_key'] = None
return {'key':'F','up_monotonic':now,'released':True}
except Exception as error:
self.report['held_release_errors'].append(str(error))
raise
class Guard:
def __init__(self, args, bound, query, owner):
self.args, self.bound, self.query, self.owner = args, bound, query, owner
@@ -595,9 +740,13 @@ def confirm_release(guard, keyboard, report, key, clock=time.monotonic, sleep=ti
observation['end'] = clock()
def sequence(guard, keyboard, observer, report, clock=time.monotonic, sleep=time.sleep, mouse=None, approach=False, alignment=False, selection=False, coarse_approach=False):
def sequence(guard, keyboard, observer, report, clock=time.monotonic, sleep=time.sleep, mouse=None, approach=False, alignment=False, selection=False, coarse_approach=False, coarse_facing=False, held_action=False):
if type(coarse_approach) is not bool or (coarse_approach and not approach) or report.get("coarse_approach_requested", False) is not coarse_approach:
raise Refused("Coarse approach requires matching explicit capability")
if type(coarse_facing) is not bool or (coarse_facing and not (selection and coarse_approach)) or report.get('coarse_facing_requested', False) is not coarse_facing:
raise Refused('Coarse facing requires matching explicit selection capability')
if type(held_action) is not bool or report.get('held_action_requested', False) is not held_action or (held_action and not (selection and coarse_facing and getattr(observer, 'enable_held', False))):
raise Refused('Held action requires matching explicit selection and observer capabilities')
deadline = clock() + 70
held = None
approach_completed = False
@@ -665,6 +814,9 @@ def sequence(guard, keyboard, observer, report, clock=time.monotonic, sleep=time
notify({'kind': 'approach-pending', 'deadline_monotonic': deadline})
if observer.events != ['READY']:
raise Refused('Inventory was already changed before input')
if held_action:
original_end = observer.ready_at + (45000-(observer.ready_real-observer.queued_real))/1000-.5
notify({'kind':'held-observer-deadline','deadline_monotonic':original_end})
if mouse is not None:
perform_look(guard, keyboard, observer, mouse, report, clock, sleep)
if not approach:
@@ -679,6 +831,8 @@ def sequence(guard, keyboard, observer, report, clock=time.monotonic, sleep=time
notify({'kind': 'approach-finished', 'successful': True})
if selection:
run_selection(guard, keyboard, observer, mouse, report, clock, sleep)
if held_action:
run_held_action(guard, keyboard, observer, mouse, report, clock, sleep)
else:
run_alignment(guard, keyboard, observer, mouse, report, clock, sleep)
report["sequence_completed"] = True
@@ -714,9 +868,9 @@ def sequence(guard, keyboard, observer, report, clock=time.monotonic, sleep=time
if approach:
route = report.get('approach_proof', {})
report['paired_release_errors'].extend(route.get('paired_release_errors', []))
report['unconfirmed_held_key'] = route.get('unconfirmed_held_key')
report['unconfirmed_held_key'] = report.get('unconfirmed_held_key') or route.get('unconfirmed_held_key')
notify({'kind': 'approach-finished', 'successful': approach_completed if alignment else report['sequence_completed']})
report['all_attempted_presses_released'] = not report.get('unconfirmed_held_key') and not report['paired_release_errors'] and not report.get('unconfirmed_held_button') and not report.get('wheel_release_errors')
report['all_attempted_presses_released'] = not report.get('unconfirmed_held_key') and not report['paired_release_errors'] and not report.get('unconfirmed_held_button') and not report.get('wheel_release_errors') and not report.get('held_release_errors')
class ApproachKeyboard:
@@ -926,6 +1080,10 @@ def run_selection(guard, keyboard, observer, mouse, report, clock, sleep):
from prison_alignment_proof import perform_facing
from prison_alignment_evidence import validate_facing_evidence
from prison_action_selection_proof import perform_selection
coarse_facing = report.get('coarse_facing_requested', False)
if type(coarse_facing) is not bool or coarse_facing is not getattr(mouse, 'enable_coarse_facing', False):
raise Refused('Facing profile differs from owned mouse capability')
facing_profile = 'coarse' if coarse_facing else 'standard'
from prison_approach_evidence import validate_approach_evidence
if observer.ready_at is None or observer.ready_real is None or observer.queued_real is None:
raise Refused('Original native alignment clocks missing')
@@ -960,13 +1118,13 @@ def run_selection(guard, keyboard, observer, mouse, report, clock, sleep):
# is handed to this stage. It may only assert that all keys are idle.
perform_facing(guard, keyboard.require_idle, AlignmentMouse(mouse, report, clock, deadline),
observer.alignment_snapshots, route['geometry'], calibration, evidence, report,
clock=clock, sleep=sleep, notify=alignment_notify)
clock=clock, sleep=sleep, notify=alignment_notify, profile=facing_profile)
facing = report.get('facing_proof', {})
if not facing.get('completed'):
raise Refused('Facing module did not complete')
deadline = min(deadline, facing['deadline_monotonic'])
content, data = observer.approach_data()
facing_evidence = validate_facing_evidence(content, observer.nonce, look, route, facing)
facing_evidence = validate_facing_evidence(content, observer.nonce, look, route, facing, profile=facing_profile)
if not facing_evidence.get('verified'):
raise Refused('Independent native facing prerequisite refused')
if clock() >= deadline:
@@ -987,12 +1145,54 @@ def run_selection(guard, keyboard, observer, mouse, report, clock, sleep):
notify({'kind': 'alignment-finished', 'successful': successful})
def run_held_action(guard, keyboard, observer, mouse, report, clock, sleep):
from prison_action_selection_evidence import validate_selection_evidence
from prison_held_action_proof import perform_held_action
from prison_held_action_evidence import validate_held_action_evidence
if (report.get('held_action_requested') is not True or report.get('coarse_facing_requested') is not True or
observer.enable_held is not True or mouse.enable_coarse_facing is not True):
raise Refused('Held action lacks explicit native/input capabilities')
content, _ = observer.approach_data()
selected = report.get('action_selection_proof')
accepted = validate_selection_evidence(content,observer.nonce,report.get('look_proof'),report.get('approach_proof'),
report.get('facing_proof'),selected,facing_profile='coarse')
if accepted.get('verified') is not True:
raise Refused('Independent native one-wheel selection prerequisite refused')
if observer.ready_at is None or observer.ready_real is None or observer.queued_real is None:
raise Refused('Original held observation clock missing')
original_end = observer.ready_at+(45000-(observer.ready_real-observer.queued_real))/1000-.5
calibration = {'nonce':observer.nonce,'ready_real_ms':observer.ready_real,'ready_monotonic':observer.ready_at,
'observer_start_real_ms':observer.queued_real,'observer_deadline_monotonic':original_end}
observer.begin_held(accepted['last_sample'])
key = HeldFKey(guard,keyboard,mouse,report,clock,sleep,original_end,enabled=True)
try:
perform_held_action(guard,keyboard.require_idle,key,observer.held_snapshots,selected['geometry'],calibration,accepted,report,
clock=clock,sleep=sleep,notify=notify)
finally:
held = report.get('held_action_proof',{})
report['paired_release_errors'].extend(held.get('paired_release_errors',[]))
if held.get('unconfirmed_held_key') is not None:
report['unconfirmed_held_key'] = held['unconfirmed_held_key']
# Live success still belongs to the independent raw parser. No action/input
# can follow this final read-only observation and full policy verification.
content, _ = observer.held_data()
verified = validate_held_action_evidence(content,observer.nonce,report.get('look_proof'),report.get('approach_proof'),
report.get('facing_proof'),selected,report.get('held_action_proof'),facing_profile='coarse')
if verified.get('verified') is not True:
raise Refused('Independent native held-action evidence refused')
guard.check(); keyboard.require_idle()
if clock() >= original_end:
raise Refused('Original held observation lifetime expired before completion')
def arguments(argv=None):
p = argparse.ArgumentParser(description=__doc__)
p.add_argument('--enable-private-keyboard-proof', action='store_true', required=True)
p.add_argument('--enable-private-held-action-proof', action='store_true', help='One bounded F hold after independently accepted selection; requires explicit coarse facing')
p.add_argument('--enable-private-selection-proof', action='store_true', help='After facing, try one button5 wheel selection; never perform the action')
p.add_argument('--enable-private-look-proof', action='store_true')
p.add_argument('--enable-private-alignment-proof', action='store_true', help='After successful approach, attempt stationary native lock selection using horizontal relative mouse only')
p.add_argument('--enable-private-coarse-facing-proof', action='store_true', help='Explicit coarse facing only; requires coarse approach and selection, no renewed clocks')
p.add_argument('--enable-private-coarse-approach-proof', action='store_true', help='Explicit larger stationary-yaw profile; requires approach, original clocks unchanged')
p.add_argument('--enable-private-approach-proof', action='store_true', help='After look calibration, replace W/Tab cycle with bounded interior approach only')
for name in ('prefix', 'game-executable', 'profile', 'report'):
@@ -1002,6 +1202,10 @@ def arguments(argv=None):
p.add_argument('--nonce', required=True)
p.add_argument('command', nargs=argparse.REMAINDER)
args = p.parse_args(argv)
if args.enable_private_held_action_proof and not (args.enable_private_selection_proof and args.enable_private_coarse_facing_proof):
p.error('Held action requires selection and coarse facing')
if args.enable_private_coarse_facing_proof and not (args.enable_private_coarse_approach_proof and args.enable_private_selection_proof):
p.error('Coarse facing requires coarse approach and selection')
if args.enable_private_coarse_approach_proof and not args.enable_private_approach_proof:
p.error('Coarse approach proof requires explicit approach proof')
if args.enable_private_selection_proof and not (args.enable_private_alignment_proof and args.enable_private_approach_proof and args.enable_private_look_proof):
@@ -1067,6 +1271,7 @@ APPROACH_MODULES = ('prison_approach_proof.py', 'ordinary_gate_evidence.py',
ALIGNMENT_MODULES = ('prison_alignment_proof.py', 'prison_alignment_evidence.py')
SELECTION_MODULES = ('ordinary_gate_choices.py', 'prison_action_selection_proof.py', 'prison_action_selection_evidence.py')
HELD_MODULES = ('prison_held_action_proof.py', 'prison_held_action_evidence.py')
def approach_module_hashes():
@@ -1088,6 +1293,8 @@ def report_for_write(report):
names.append('alignment_proof')
if report.get('selection_requested') is True:
names += ['facing_proof', 'action_selection_proof']
if report.get('held_action_requested') is True:
names.append('held_action_proof')
for name in names:
route = report.get(name)
if isinstance(route, dict):
@@ -1095,7 +1302,7 @@ def report_for_write(report):
samples = route.get('samples')
if isinstance(samples, list):
result[name]['samples'] = [
{key: sample.get(key) for key in ('sample', 'real_ms', 'received_monotonic')}
{key: sample.get(key) for key in (('sample', 'real_ms', 'world_ms', 'received_monotonic') if name == 'held_action_proof' else ('sample', 'real_ms', 'received_monotonic'))}
if isinstance(sample, dict) else {'invalid_reference': True} for sample in samples]
return result
@@ -1111,7 +1318,9 @@ def main(argv=None):
console_path(args)
bound = display.binding(args.host_display, args.prefix)
report = {'schema': 1, 'kind': 'headless-private-keyboard-experiment', 'input_sent': False,
'held_action_requested': getattr(args, 'enable_private_held_action_proof', False),
'look_requested': args.enable_private_look_proof,
'coarse_facing_requested': getattr(args, 'enable_private_coarse_facing_proof', False),
'coarse_approach_requested': getattr(args, 'enable_private_coarse_approach_proof', False),
'approach_requested': getattr(args, 'enable_private_approach_proof', False),
'alignment_requested': getattr(args, 'enable_private_alignment_proof', False),
@@ -1128,6 +1337,9 @@ def main(argv=None):
if report['selection_requested']:
report['selection_module_sha256'] = module_hashes(SELECTION_MODULES)
report.update(wheel_events=[], wheel_release_errors=[], unconfirmed_held_button=None)
if report['held_action_requested']:
report['held_module_sha256'] = module_hashes(HELD_MODULES)
report.update(held_events=[], held_release_errors=[])
fd = os.open(args.report, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600)
info = os.fstat(fd)
notify({'kind': 'report', 'path': str(args.report), 'device': info.st_dev, 'inode': info.st_ino,
@@ -1165,7 +1377,7 @@ def main(argv=None):
raise Refused('New native console deadline exceeded')
report['console'] = str(args.console)
observer = Observer(args.console, args.nonce, enable_look=args.enable_private_look_proof,
enable_approach=getattr(args, "enable_private_approach_proof", False), enable_selection=getattr(args, "enable_private_selection_proof", False))
enable_approach=getattr(args, "enable_private_approach_proof", False), enable_selection=getattr(args, "enable_private_selection_proof", False), enable_held=getattr(args, "enable_private_held_action_proof", False))
query = display.X11(bound['display'])
while time.monotonic() < deadline:
if child is not None and child.poll() is not None:
@@ -1198,8 +1410,8 @@ def main(argv=None):
guard.check()
keyboard = Keyboard(query)
keyboard.require_idle()
mouse = RelativeMouse(query, keyboard, owner, enable_approach=getattr(args, "enable_private_approach_proof", False), enable_alignment=getattr(args, "enable_private_alignment_proof", False), enable_coarse_approach=getattr(args, "enable_private_coarse_approach_proof", False)) if args.enable_private_look_proof else None
sequence(guard, keyboard, observer, report, mouse=mouse, approach=getattr(args, "enable_private_approach_proof", False), alignment=getattr(args, "enable_private_alignment_proof", False), selection=getattr(args, "enable_private_selection_proof", False), coarse_approach=getattr(args, "enable_private_coarse_approach_proof", False))
mouse = RelativeMouse(query, keyboard, owner, enable_approach=getattr(args, "enable_private_approach_proof", False), enable_alignment=getattr(args, "enable_private_alignment_proof", False), enable_coarse_approach=getattr(args, "enable_private_coarse_approach_proof", False), enable_coarse_facing=getattr(args, 'enable_private_coarse_facing_proof', False), enable_selection=getattr(args, 'enable_private_selection_proof', False)) if args.enable_private_look_proof else None
sequence(guard, keyboard, observer, report, mouse=mouse, approach=getattr(args, "enable_private_approach_proof", False), alignment=getattr(args, "enable_private_alignment_proof", False), selection=getattr(args, "enable_private_selection_proof", False), coarse_approach=getattr(args, "enable_private_coarse_approach_proof", False), coarse_facing=getattr(args, 'enable_private_coarse_facing_proof', False), held_action=getattr(args, 'enable_private_held_action_proof', False))
except (OSError, ValueError, UnicodeError, subprocess.SubprocessError) as error:
report['error'] = str(error)
finally:
@@ -1296,6 +1508,50 @@ def supervision_failure(record, key, reason, button=None):
os.close(fd)
class HeldSupervisor:
"""Independent absolute observer/F deadlines; other key leases stay1.5s."""
def __init__(self, enabled):
self.enabled = enabled; self.observer_deadline = None
self.key_deadline = None; self.key = None; self.attempted = False; self.failed = False
def consume(self, event, now, *, other_pending=False):
kind = event.get('kind')
if not isinstance(kind,str) or not kind.startswith('held-'): return False
if self.enabled is not True or type(now) not in (int,float) or not math.isfinite(now):
self.failed = True; return True
value = event.get('deadline_monotonic')
numeric = type(value) in (int,float) and math.isfinite(value)
if kind == 'held-observer-deadline':
if self.observer_deadline is not None or not numeric or not now < value <= now+45:
self.failed = True
else:self.observer_deadline = value
elif kind == 'held-action-pending':
if self.observer_deadline is None or not numeric or not now < value <= self.observer_deadline:
self.failed = True
else:self.observer_deadline = value
elif kind == 'held-key-pending':
if (event.get('key') != 'F' or self.attempted or other_pending or self.observer_deadline is None or
not numeric or not now < value <= min(now+5,self.observer_deadline)):
self.failed = True
else:
self.attempted = True; self.key = 'F'; self.key_deadline = value
elif kind == 'held-key-release-confirmed':
if event.get('key') != 'F' or self.key != 'F':self.failed = True
else:
if now >= self.key_deadline:self.failed = True
self.key = None; self.key_deadline = None
elif kind != 'held-action-finished':self.failed = True
return True
def expired(self, now, proof_finished=False):
return (self.failed or (self.key_deadline is not None and now >= self.key_deadline) or
(not proof_finished and self.observer_deadline is not None and now >= self.observer_deadline))
def cleanup_ack(self, event):
if event.get('kind') == 'held-key-release-confirmed' and event.get('key') == self.key == 'F':
self.key = None; self.key_deadline = None
def supervise(argv=None):
# Fork before loading Xlib or opening any display. The worker owns the one
# connection. Parent never opens a second connection or retries an event.
@@ -1313,6 +1569,8 @@ def supervise(argv=None):
approach_deadline = None; approach_finished = False
button_at = None; held_button = None
look_at = None; held_at = None; held_key = None; owned_child = None; report_record = None; proof_finished = False; expired = False
raw_args = sys.argv[1:] if argv is None else argv
held_scope = HeldSupervisor(raw_args.count('--enable-private-held-action-proof') == 1)
deadline = time.monotonic() + 190
try:
child.start(); child_pipe.close()
@@ -1322,7 +1580,9 @@ def supervise(argv=None):
event = parent.recv()
except EOFError:
event = None
if event and event['kind'] == 'alignment-pending':
if event and str(event.get('kind','')).startswith('held-') and held_scope.consume(event,time.monotonic(),other_pending=held_key is not None or held_button is not None or look_at is not None):
pass
elif event and event['kind'] == 'alignment-pending':
proposed = event.get('deadline_monotonic')
current = time.monotonic()
if type(proposed) not in (int, float) or not math.isfinite(proposed) or proposed > current + 8:
@@ -1359,7 +1619,7 @@ def supervise(argv=None):
elif event and event['kind'] == 'proof-finished':
proof_finished = event['successful']
now = time.monotonic()
if received or now >= deadline or (alignment_deadline is not None and not alignment_finished and now >= alignment_deadline) or (approach_deadline is not None and not approach_finished and now >= approach_deadline) or (button_at is not None and now - button_at > 1.5) or (held_at is not None and now - held_at > 1.5) or (look_at is not None and now - look_at > 4):
if received or now >= deadline or held_scope.expired(now,proof_finished) or (alignment_deadline is not None and not alignment_finished and now >= alignment_deadline) or (approach_deadline is not None and not approach_finished and now >= approach_deadline) or (button_at is not None and now - button_at > 1.5) or (held_at is not None and now - held_at > 1.5) or (look_at is not None and now - look_at > 4):
expired = True
child.terminate() # asks worker finally to release if still provable
child.join(1)
@@ -1372,6 +1632,7 @@ def supervise(argv=None):
last = parent.recv()
except EOFError:
break
held_scope.cleanup_ack(last)
if last['kind'] == 'release-confirmed':
held_key = None
elif last['kind'] == 'button-release-confirmed' and last['button'] == held_button:
@@ -1380,14 +1641,14 @@ def supervise(argv=None):
report_record = last
elif last['kind'] == 'proof-finished':
proof_finished = last['successful']
if not (received and proof_finished and held_key is None and held_button is None):
supervision_failure(report_record, held_key, 'Private input worker timed out or was interrupted', button=held_button)
if not (received and proof_finished and held_key is None and held_scope.key is None and held_button is None):
supervision_failure(report_record, held_scope.key or held_key, 'Private input worker timed out or was interrupted', button=held_button)
break
child.join(2)
if child.exitcode != 0 and not expired:
stop_exact_child(owned_child)
if not (received and proof_finished and held_key is None and held_button is None):
supervision_failure(report_record, held_key, 'Private input worker exited unsuccessfully', button=held_button)
if not (received and proof_finished and held_key is None and held_scope.key is None and held_button is None):
supervision_failure(report_record, held_scope.key or held_key, 'Private input worker exited unsuccessfully', button=held_button)
return 1 if expired or child.exitcode != 0 else 0
finally:
if child.pid and child.is_alive():
+4
View File
@@ -13,6 +13,7 @@ p.add_argument('--steam', type=Path, default=Path.home()/'.local/share/Steam')
p.add_argument('--compat', type=Path, required=True, help='Disposable cloned Proton compatdata directory outside Steam')
p.add_argument('--profile', type=Path, required=True, help='Separate disposable successor Workbench profile')
p.add_argument('--smoke', choices=['aircraft-field', 'aircraft-route', 'native-end-active', 'native-end-preparing', 'aircraft-control', 'aircraft-cancel', 'aircraft-translate', 'map-ownership', 'mortar-refresh', 'mortar-salvo', 'mortar-courier', 'station-teardown', 'prison-breach', 'powered-flight', 'powered-translate', 'local-admission', 'mortar-expiry', 'mortar-transfer', 'mortar-fire', 'patrol-hq', 'victory', 'lost-helicopter', 'player-death', 'radio-network', 'hq-response', 'mortar-inventory', 'startup-failure', 'site-survey', 'cache-loss', 'extraction-capacity', 'early-helicopter-loss', 'extraction-startup-failure', 'extraction-boundary-failure', 'transport-loss', 'transport-survey', 'lifecycle', 'objective-ui', 'recovery', 'prisoner-kit', 'medical', 'casualty-load', 'casualty-direct', 'casualty-bench', 'casualty-remove', 'environment', 'environment-restart', 'patrols', 'radio-document-loss', 'radio-document-loss-partial', 'guard-cancel', 'casualty-service'], default='victory')
p.add_argument('--field-terrain-audit', action='store_true', help='After a fixed aircraft-field survey refusal, log one read-only 1681-node coarse terrain grid; never selects or qualifies a corridor')
p.add_argument('--field-service-cancel', action='store_true', help='Explicit aircraft-field variant: Stop the original retained service during measured cruise; requires physical cancellation landing')
p.add_argument('--route-service-cancel', action='store_true', help='Explicit aircraft-route variant: stop the retained service after actual airborne translation and require controlled cancellation landing')
p.add_argument('--station-teardown-diagnostics', action='store_true', help='Opt-in bounded native deletion diagnostics; preserves all validation errors')
@@ -26,6 +27,8 @@ a = p.parse_args()
steam, compat, profile = a.steam.resolve(), a.compat.resolve(), a.profile.resolve()
if not 1 <= a.rounds <= 10 or not 60 <= a.timeout <= 1800:
p.error('Use 1..10 rounds and a 60..1800 second timeout')
if a.field_terrain_audit and a.smoke != 'aircraft-field': p.error('--field-terrain-audit requires --smoke aircraft-field')
if a.field_terrain_audit and a.field_service_cancel: p.error('--field-terrain-audit and --field-service-cancel are mutually exclusive')
if a.field_service_cancel and a.smoke != 'aircraft-field': p.error('--field-service-cancel requires --smoke aircraft-field')
if a.route_service_cancel and a.smoke != 'aircraft-route': p.error('--route-service-cancel requires --smoke aircraft-route')
if a.smoke == 'mortar-courier' and (a.project != 'chat' or a.rounds != 1 or a.timeout < 500):
@@ -81,6 +84,7 @@ for proc in Path('/proc').iterdir():
except (FileNotFoundError, PermissionError, ProcessLookupError): pass
command = ['gamescope', '--backend', 'headless', '-W', '1280', '-H', '720', '-w', '1280', '-h', '720', '-r', '30', '--', str(proton), 'run', str(wb/'ArmaReforgerWorkbenchSteamDiag.exe'), '-gproj', 'Z:'+str(ROOT/'addons'/a.project/'addon.gproj'), '-addonsDir', 'Z:'+str(ROOT/'addons'), '-profile', profile_arg, '-logconsole', '-wbModule=WorldEditor', '-load', 'Worlds/ERR_Everon.ent', '-plugin=ERR_ValidateWorldPlugin', '-errPlay', '1', '-errSmoke', '1', '-errSmokeOutcome', a.smoke, '-noThrow', '-disableCrashReporter']
if a.field_service_cancel: command += ['-errSmokeFieldServiceCancel', '1']
if a.field_terrain_audit: command += ['-errSmokeFieldTerrainAudit', '1']
if a.route_service_cancel: command += ['-errSmokeRouteServiceCancel', '1']
if a.station_teardown_diagnostics: command += ['-errStationTeardownDiag', '1']
if a.flight_input_diagnostics: command += ['-errFlightInputDiag', '1']
+2 -2
View File
@@ -7,10 +7,10 @@ from prison_alignment_evidence import validate_facing_evidence
from prison_approach_evidence import need,number,neutral,yaw,angle,horizontal
def validate_selection_evidence(content,nonce,look_proof,approach_proof,facing_proof,proof):
def validate_selection_evidence(content,nonce,look_proof,approach_proof,facing_proof,proof,*,facing_profile="standard"):
result={'verified':False,'errors':[],'scope':'one guarded private wheel pair and native selection of the original prison lock after verified approach/facing; no F hold, unlock, exit or multiplayer qualification','held_action_verified':False,'escape_verified':False}
try:
facing=validate_facing_evidence(content,nonce,look_proof,approach_proof,facing_proof)
facing=validate_facing_evidence(content,nonce,look_proof,approach_proof,facing_proof,profile=facing_profile)
need(facing['verified'],'independent native facing prerequisite failed: '+str(facing['errors']))
need(type(proof) is dict and proof.get('requested') is True and proof.get('completed') is True and proof.get('nonce')==nonce and not proof.get('error') and not proof.get('events') and not proof.get('motions'),'selection did not complete under exact nonce without extra input')
need(set(proof)=={'requested','completed','nonce','geometry','started_monotonic','finished_monotonic','deadline_monotonic','initial_sample','final_sample','selection_samples','actions','wheel','samples'},'unexpected selection proof fields or extra input')
+11 -7
View File
@@ -10,16 +10,20 @@ def validate_alignment_evidence(content, nonce, look_proof, approach_proof, proo
return _validate(content,nonce,look_proof,approach_proof,proof)
def validate_facing_evidence(content, nonce, look_proof, approach_proof, proof):
return _validate(content,nonce,look_proof,approach_proof,proof,facing=True)
def validate_facing_evidence(content, nonce, look_proof, approach_proof, proof, *, profile="standard"):
return _validate(content,nonce,look_proof,approach_proof,proof,facing=True,profile=profile)
def _validate(content, nonce, look_proof, approach_proof, proof, facing=False):
def _validate(content, nonce, look_proof, approach_proof, proof, facing=False, profile="standard"):
result={'verified':False,'errors':[],'scope':'stationary yaw-only alignment and native selection of the original prison lock after a verified interior approach; no F hold, unlock, exit or multiplayer qualification','held_action_verified':False,'escape_verified':False}
if facing:
result['scope']='stationary yaw facing the original gate with exact disabled door and available lock diagnostics; lock selection, held action and escape remain unverified'
result['lock_selection_verified']=False
try:
need(type(profile) is str and profile in ('standard','coarse') and (facing or profile == 'standard'), 'Unknown expected facing profile')
need(type(proof) is dict and proof.get('profile','standard') == profile, 'Facing profile differs from explicit verifier capability')
need(profile != 'coarse' or approach_proof.get('profile') == 'coarse', 'Coarse facing lacks coarse approach prerequisite')
max_pixels, max_angle = (384,35) if profile == 'coarse' else (128,15)
approach=validate_approach_evidence(content,nonce,look_proof,approach_proof)
need(approach['verified'],'prior native approach is unverified: '+str(approach['errors']))
calibration=validate_look_evidence(content,nonce,look_proof)
@@ -28,7 +32,7 @@ def _validate(content, nonce, look_proof, approach_proof, proof, facing=False):
need(.01<=abs(gain)<=.5,'native calibration gain outside alignment range')
need(type(proof) is dict and not proof.get('events') and proof.get('requested') is True and proof.get('completed') is True and proof.get('nonce')==nonce and not proof.get('error'),'alignment did not complete under this nonce')
if facing:
need(set(proof)=={'requested','completed','nonce','geometry','started_monotonic','finished_monotonic','deadline_monotonic','initial_sample','final_sample','facing_samples','actions','motions','samples'},'unexpected facing proof fields or lock-selection claim')
need(set(proof)==({'requested','completed','nonce','geometry','started_monotonic','finished_monotonic','deadline_monotonic','initial_sample','final_sample','facing_samples','actions','motions','samples'} | ({'profile'} if 'profile' in proof else set())),'unexpected facing proof fields or lock-selection claim')
start=number(proof['started_monotonic']);finish=number(proof['finished_monotonic']);deadline=number(proof['deadline_monotonic'])
need(approach_proof['finished_monotonic']<=start<finish<=deadline<=start+8,'alignment helper interval outside original stage bound')
if facing:
@@ -80,15 +84,15 @@ def _validate(content, nonce, look_proof, approach_proof, proof, facing=False):
old_index=first;old_time=start;pixel_sum=0
for motion in motions:
dx=motion['dx'];at=number(motion['monotonic']);before=motion['after_sample'];after=motion['response_sample']
need(type(dx) is int and 1<=abs(dx)<=128 and type(motion['dy']) is int and motion['dy']==0,'alignment motion is not bounded horizontal input')
need(type(dx) is int and 1<=abs(dx)<=max_pixels and type(motion['dy']) is int and motion['dy']==0,'alignment motion is not bounded horizontal input')
need(type(before) is int and type(after) is int and old_index<=before<after<=last,'alignment motion references reversed')
need(old_time<=at<=finish and before in receipts and after in receipts and receipts[before]<=at<=receipts[after] and at-receipts[before]<=.5 and receipts[after]-at<=1.5,'alignment input timestamps contradict native samples')
baseline=yaw(samples[before]['look']['direction']);wanted=angle(heading(samples[before]),baseline)
change=angle(yaw(samples[after]['look']['direction']),baseline)
need(abs(wanted)>3 and dx*gain*wanted>0 and .05<=abs(change)<=15 and change*dx*gain>0,'native turn did not follow same-run signed calibration toward handle')
need(abs(wanted)>3 and dx*gain*wanted>0 and .05<=abs(change)<=max_angle and change*dx*gain>0,'native turn did not follow same-run signed calibration toward handle')
for i in range(before,after+1):
d=angle(yaw(samples[i]['look']['direction']),baseline)
need(abs(d)<=15 and (abs(d)<.05 or d*dx*gain>0),'intermediate native turn reversed or exceeded bound')
need(abs(d)<=max_angle and (abs(d)<.05 or d*dx*gain>0),'intermediate native turn reversed or exceeded bound')
need(after-1>=before and 100<=samples[after]['real_ms']-samples[after-1]['real_ms']<=500 and abs(angle(yaw(samples[after]['look']['direction']),yaw(samples[after-1]['look']['direction'])))<=.2,'native turn response did not settle over consecutive samples')
need(samples[after]['real_ms']-samples[before]['real_ms']<=2500,'native turn response interval is unbounded')
old_index=after;old_time=at;pixel_sum+=abs(dx)
+28 -12
View File
@@ -32,12 +32,16 @@ def perform_alignment(guard, require_idle, mouse, observe, geometry, calibration
return _perform_alignment(guard, require_idle, mouse, observe, geometry, calibration, approach_evidence, report, clock=clock, sleep=sleep, notify=notify)
def perform_facing(guard, require_idle, mouse, observe, geometry, calibration, approach_evidence, report, *, clock, sleep, notify):
def perform_facing(guard, require_idle, mouse, observe, geometry, calibration, approach_evidence, report, *, clock, sleep, notify, profile="standard"):
"""Separate facing-only outcome; requires exact disabled-door/lock diagnostics."""
return _perform_alignment(guard, require_idle, mouse, observe, geometry, calibration, approach_evidence, report, clock=clock, sleep=sleep, notify=notify, facing=True)
return _perform_alignment(guard, require_idle, mouse, observe, geometry, calibration, approach_evidence, report, clock=clock, sleep=sleep, notify=notify, facing=True, profile=profile)
def _perform_alignment(guard, require_idle, mouse, observe, geometry, calibration, approach_evidence, report, *, clock, sleep, notify, facing=False):
def _perform_alignment(guard, require_idle, mouse, observe, geometry, calibration, approach_evidence, report, *, clock, sleep, notify, facing=False, profile="standard"):
need(type(profile) is str and profile in ('standard', 'coarse') and (facing or profile == 'standard'), 'Unknown or non-facing coarse profile')
coarse = profile == 'coarse'
need(not coarse or (report.get('coarse_facing_requested') is True and report.get('coarse_approach_requested') is True and report.get('selection_requested') is True), 'Coarse facing requires explicit matching capabilities')
max_pixels, desired_angle, max_angle = (384, 25., 35.) if coarse else (128, 10., 15.)
proof_key = 'facing_proof' if facing else 'alignment_proof'
event_prefix = 'facing' if facing else 'alignment'
need(proof_key not in report, 'Alignment attempt already exists')
@@ -48,6 +52,7 @@ def _perform_alignment(guard, require_idle, mouse, observe, geometry, calibratio
approach.get('nonce') == pinned['nonce'] and approach.get('geometry') == pinned and
approach_evidence.get('last_sample') == approach.get('final_sample'),
'Alignment requires independently completed same-run approach')
need(not coarse or approach.get('profile') == 'coarse', 'Coarse facing requires the accepted coarse approach')
prior = approach.get('samples', [])
need(prior and prior[-1]['sample'] == approach['final_sample'], 'Original approach final body sample unavailable')
body = vector(prior[-1]['origin'])
@@ -70,9 +75,10 @@ def _perform_alignment(guard, require_idle, mouse, observe, geometry, calibratio
'initial_sample': None, 'final_sample': None, 'selection_samples': [], 'motions': [], 'samples': []}
report[proof_key] = state
if facing:
if coarse: state['profile'] = profile
state['facing_samples'] = []
del state['selection_samples']
previous = None; active_turn = None; requests = 0
previous = None; active_turn = None; requests = 0; pixels = 0
def neutral(s):
return abs(s['forward']) <= .01 and length(s['input']) <= .01 and length(s['velocity']) <= .05
@@ -109,7 +115,7 @@ def _perform_alignment(guard, require_idle, mouse, observe, geometry, calibratio
if active_turn is not None:
before_yaw, sign = active_turn
change = delta(yaw(s['direction']), before_yaw)
need(abs(change) <= 15, 'Native yaw exceeded alignment turn bound')
need(abs(change) <= max_angle, 'Native yaw exceeded alignment turn bound')
if abs(change) >= .05:
need(change*sign > 0, 'Native yaw reversed alignment request')
if previous:
@@ -169,12 +175,20 @@ def _perform_alignment(guard, require_idle, mouse, observe, geometry, calibratio
while clock() < deadline:
pair = selection_pair()
if pair:
current = read()
pair = selection_pair()
if not pair:
continue
if not facing:
current = read()
pair = selection_pair()
if not pair:
continue
# Facing already has a fully consumed, guarded stable pair.
# Return its exact span; selection still consumes all later
# history and rechecks ownership before any wheel request.
require_idle()
need(clock() < deadline, 'Frozen alignment deadline exceeded at completion')
completed_at = clock()
if facing:
need(started <= completed_at and 0 <= completed_at-state['samples'][-1]['received_monotonic'] <= .5,
'Final native alignment observation is stale or clock reversed')
need(completed_at < deadline, 'Frozen alignment deadline exceeded at completion')
state['facing_samples' if facing else 'selection_samples'] = pair; state['completed'] = True
return state
error = delta(bearing(current), yaw(current['direction']))
@@ -191,9 +205,11 @@ def _perform_alignment(guard, require_idle, mouse, observe, geometry, calibratio
error = delta(bearing(before), yaw(before['direction']))
if abs(error) <= 3:
current = before; continue
desired = max(-10., min(10., .75*error))
dx = max(-128, min(128, int(round(desired/gain))))
desired = max(-desired_angle, min(desired_angle, .75*error))
dx = max(-max_pixels, min(max_pixels, int(round(desired/gain))))
if dx == 0: dx = 1 if desired/gain > 0 else -1
need(pixels+abs(dx) <= 768, 'Alignment cumulative pixel budget exhausted')
pixels += abs(dx) # Retire the attempted input before any uncertain native write.
active_turn = (yaw(before['direction']), dx*gain)
mouse.move(dx, 0, guard, deadline=deadline)
requests += 1
+162
View File
@@ -0,0 +1,162 @@
"""Dormant independent raw-console held-F verifier. Never sends input.
Primary installed contracts: ScriptedUserAction.GetActionProgressScript adds
OnPostFrame timeSlice and returns seconds; SCR_InteractionHandlerComponent resets
progress in the same frame as DoPerformObjectAction; BaseWorld.GetWorldTime is
milliseconds. INPUT already records that world clock. Exact sampler/post-frame
ordering is not documented: timing checks conservatively allow ONE observed
adjacent world-sample interval plus2ms print rounding at each boundary, and
record that inference. They never replace duration with a guessed near4 cutoff
or wall-clock sleep. The source diagnostic skip-duration path would fail the
normal-duration timing checks. Full native object pins come from the unchanged
nonce-bound observer/source provenance; geometry alone cannot prove identity.
Earlier look/approach/facing/selection spans are revalidated without relaxing any
old validator. Only this held span permits phase2 and moving original-door
geometry. The runner still must verify exact process/display/source ownership,
actual F-only adapter requests, hard supervision and native keymap release.
"""
import math
import re
from ordinary_gate_choices import join_choice_snapshots, exact_prison_choices
from prison_action_selection_evidence import validate_selection_evidence
from prison_approach_evidence import number, need, yaw, angle, norm
SCOPE='one original local prison lock hold, authoritative phase transition and physical door response; no passage, full escape, multiplayer or FPS qualification'
def validate_held_action_evidence(content, nonce, look_proof, approach_proof, facing_proof, selection_proof, proof, *, facing_profile='standard'):
result={'verified':False,'held_action_verified':False,'escape_verified':False,'errors':[],
'scope':SCOPE,'unlock_observed':False,'gate_motion_observed':False,
'timing_basis':'native world milliseconds; one adjacent sampled world interval plus2ms allowance for undocumented post-frame/sampler ordering',
'adapter_release_confirmation_verified':False}
try:
selected=validate_selection_evidence(content,nonce,look_proof,approach_proof,facing_proof,selection_proof,facing_profile=facing_profile)
need(selected['verified'],'prior independent selection failed: '+str(selected['errors']))
required={'requested','completed','status','input_attempted','unlock_observed','gate_motion_observed','release_confirmed',
'unconfirmed_held_key','paired_release_errors','notification_errors','events','samples','progress_samples',
'transition_sample','control_sample','motion_sample','released_sample','initial_sample','final_sample',
'started_monotonic','finished_monotonic','press_attempted_monotonic','down_monotonic','up_monotonic',
'press_sample','original_deadline_monotonic','held_deadline_monotonic','nonce','geometry','actions',
'selection_final_sample','release_barrier_sample'}
need(type(proof) is dict and set(proof)==required,'unknown or missing held proof fields')
need(proof['requested'] is True and proof['completed'] is True and proof['status']=='verified' and proof['nonce']==nonce and
proof['input_attempted'] is True and proof['release_confirmed'] is True and proof['unlock_observed'] is True and
proof['gate_motion_observed'] is True and proof['unconfirmed_held_key'] is None and
proof['paired_release_errors']==[] and proof['notification_errors']==[], 'held proof did not complete cleanly')
data=join_choice_snapshots(content,nonce);frames=data['snapshots']
first=proof['initial_sample'];last=proof['final_sample'];anchor=selected['last_sample'];before=proof['press_sample']
need(all(type(i) is int for i in (first,last,anchor,before)) and first==anchor==proof['selection_final_sample'] and first<before<last<=450,
'held span or original selection handoff invalid')
need(proof['geometry']==selection_proof['geometry'] and proof['actions']==selection_proof['actions'],'held geometry/actions replaced selection binding')
refs=proof['samples'];need(type(refs) is list and 2<=len(refs)<=450,'held native references missing')
need([x['sample'] for x in refs]==list(range(first,last+1)),'held native references omitted, duplicated or reordered')
start=number(proof['started_monotonic']);finish=number(proof['finished_monotonic']);deadline=number(proof['original_deadline_monotonic'])
attempt=number(proof['press_attempted_monotonic']);down=number(proof['down_monotonic']);up=number(proof['up_monotonic']);lease=number(proof['held_deadline_monotonic'])
need(number(selection_proof['finished_monotonic'])<=start<=attempt<=down<up<finish<deadline and up<lease<=attempt+5 and lease<=deadline,
'held request, release or completion exceeded immutable deadline')
need(down+6<=deadline,'actual F request lacked six seconds of original observation budget')
queued=re.findall(r'ERR INPUT OBSERVE: run='+re.escape(nonce)+r' sample=0 real=(\d+) world=[^ ]+ QUEUED(?:\r?$)',content,re.MULTILINE)
need(len(queued)==1,'original QUEUED clock missing or ambiguous');queued=int(queued[0]);ready=data['ready']['real_ms']
original_host_end=number(approach_proof['deadline_monotonic'])-35+(45000-(ready-queued))/1000-.5
anchor_ref=selection_proof['samples'][-1]
anchor_end=number(anchor_ref['received_monotonic'])+(queued+45000-number(anchor_ref['real_ms']))/1000-.5
need(deadline<=min(original_host_end,anchor_end),'held stage renewed original observation clock')
events=proof['events'];need(type(events) is list and len(events)==2,'expected one F down and one F up only')
for e,is_down,at in zip(events,(True,False),(down,up)):
keys={'key','down','attempted_monotonic','confirmed','monotonic'} | (set() if is_down else {'cleanup'})
need(type(e) is dict and set(e)==keys and e['key']=='F' and e['down'] is is_down and e['confirmed'] is True and
number(e['monotonic'])==at and number(e['attempted_monotonic'])<=at and
(is_down or e['cleanup'] is False),'unexpected key, retry, cleanup or unconfirmed F event')
need(events[0]['attempted_monotonic']==attempt and down<=number(events[1]['attempted_monotonic'])<lease,'F attempted-event clocks disagree')
receipts={};prior_receipt=-1
for r in refs:
i=r['sample'];need(i in frames and type(r['real_ms']) is int and r['real_ms']==frames[i]['real_ms'],'held reference differs from native clock')
received=number(r['received_monotonic']);need(0<=received<=finish and received>=prior_receipt,'held receipts reversed or unbounded')
if 'world_ms' in r:need(number(r['world_ms'])==frames[i]['input']['world_ms'],'held world reference differs from native clock')
receipts[i]=received;prior_receipt=received
need(refs[0]['real_ms']==anchor_ref['real_ms'] and refs[0]['received_monotonic']==anchor_ref['received_monotonic'],'original selection receipt changed at held handoff')
need(0<=finish-receipts[last]<=.5 and receipts[before]<=attempt and down-receipts[before]<=.5,'held input/final native evidence is stale')
for cancellation in (data['cancelled'],data['look_cancelled']):
need(cancellation is None or cancellation['sample']>last,'original native observer cancelled within held span')
body=frames[anchor]['input']['origin'];direction=yaw(frames[anchor]['look']['direction']);geometry=proof['geometry'];actions=proof['actions']
need(actions[1]['id']==selected['selected_action_id'],'original selected lock ID differs')
progress=[];prior_progress=0.;pressed_seen=False;transition=None;control=None;motion=None;previous=None;last_positive=None
phase=1;allowance_max=0.;world_before=frames[before]['input']['world_ms']
# Check the two fresh, selected pre-input native samples themselves.
need(before-1>=first and 100<=frames[before]['real_ms']-frames[before-1]['real_ms']<=500,'F lacks a consecutive admission pair')
for i in range(first,last+1):
need(i in frames and 'choices' in frames[i],'held raw join/choice missing')
s=frames[i];a=s['action'];g=s['geometry'];native=s['input'];view=s['look']
need(queued<=s['real_ms']<queued+45000 and native['inventory'] is False,'held native lifetime/menu changed')
need(a['duration']==4 and 0<=a['progress']<=4,'original native four-second action duration/progress changed')
need(math.dist(body,native['origin'])<=.05 and abs(native['origin'][0]-geometry['prison'][0])<=5.25 and abs(native['origin'][2]-geometry['prison'][2])<=5.25 and
abs(native['forward'])<=.01 and norm(native['input'])<=.01 and norm(native['velocity'])<=.05 and norm(view['turn'])<=.01 and
abs(angle(yaw(view['direction']),direction))<=.2,'held body/view/movement changed')
need(a['phase'] in (1,2) and a['phase']>=phase,'held native phase reversed or advanced beyond RADIO_SEARCH')
need(math.dist(g['prison'],geometry['prison'])<=.01,'original prison geometry changed')
if previous:
need(0<s['real_ms']-previous['real_ms']<=500,'held native observation gap')
world_delta=(native['world_ms']-previous['input']['world_ms'])/1000
need(world_delta>=0,'native world clock reversed')
adjacent=world_delta
if i-2>=first:adjacent=max(adjacent,(previous['input']['world_ms']-frames[i-2]['input']['world_ms'])/1000)
else:world_delta=0.;adjacent=0.
tolerance=adjacent+.002;allowance_max=max(allowance_max,tolerance)
if a['phase']==1:
for name in ('gate','context'):need(math.dist(g[name],geometry[name])<=.01,'closed original door/context geometry changed')
need(math.dist(g['gate_forward'],geometry['gate_forward'])<=.001 and abs(g['radius']-geometry['radius'])<=.001 and g['door_state']==0 and g['door_control']==0,
'closed gate changed before accepted action transition')
c=exact_prison_choices(s)
need(c['actions']==actions and c['selected_id']==actions[1]['id'] and c['selected_class']==actions[1]['class'] and a['selected'] and a['context_selected'] and a['cached_performable'] and a['progress_bound'],
'held original lock selection/permission/binding lost')
if i<=before:
need(a['pressed']==0 and a['progress']==0 and not a['performing'],'held action appeared before own F request')
else:
need(receipts[i]>=down,'native action observation predates actual F request')
if a['pressed']>0:pressed_seen=True
if a['progress']>0:
need(a['performing'] and a['pressed']>0 and pressed_seen and a['progress']>=prior_progress,'native held action interrupted or progress decreased')
need(a['progress']<=4 and a['progress']<=(native['world_ms']-world_before)/1000+tolerance,
'native action progress exceeds available world time')
need(a['progress']-prior_progress<=world_delta+tolerance,'native action progress jumped beyond adjacent world interval')
if a['progress']>prior_progress:progress.append(i)
prior_progress=a['progress'];last_positive=i
elif prior_progress>0:raise ValueError('native action progress reset before phase transition')
if prior_progress>0:need(a['performing'] and a['pressed']>0,'native action interrupted before phase transition')
else:
need(i>before and receipts[i]>=down and pressed_seen and len(progress)>=2 and last_positive is not None,'phase2 lacks advancing bound progress from this F attempt')
if transition is None:
remaining=(native['world_ms']-frames[last_positive]['input']['world_ms'])/1000
need(prior_progress+remaining+tolerance>=4 and (native['world_ms']-world_before)/1000+tolerance>=4,
'phase2 occurs before four seconds of reachable native action progress')
transition=i;result['unlock_observed']=True
# Raw parser and native original-object pins still apply. Only
# closed geometry and selected/progress cache may now change.
if abs(g['door_control'])>.001 and control is None:control=i
if abs(g['door_state'])>.001 and motion is None:motion=i
phase=a['phase'];previous=s
need(transition is not None and control is not None and motion is not None,'original door transition/control/physical motion missing')
result['gate_motion_observed']=True
need(receipts[transition]<=number(events[1]['attempted_monotonic'])<=up,'normal F release preceded observed authoritative transition')
need(proof['progress_samples']==progress and proof['transition_sample']==transition and proof['control_sample']==control and proof['motion_sample']==motion,
'helper progress/transition/door references differ from raw observations')
barrier=proof['release_barrier_sample'];released=proof['released_sample']
need(type(barrier) is int and type(released) is int and transition<=barrier<released==last and barrier in receipts and released in receipts and
receipts[barrier]>=up and receipts[released]>=up,'release lacks post-keyup drain and newer native acknowledgement')
a=frames[released]['action'];need(a['phase']==2 and a['pressed']==0 and a['progress']==0 and not a['performing'],'native released action input not observed at final sample')
acknowledged=False
for i in range(barrier+1,last+1):
action=frames[i]['action'];neutral=action['pressed']==0 and action['progress']==0 and not action['performing']
if acknowledged:need(neutral,'native action input renewed after release acknowledgement')
if receipts[i]>=up and neutral:acknowledged=True
need(acknowledged,'newer native release acknowledgement missing')
need(any(receipts[i]>=down and frames[i]['action']['pressed']>0 for i in range(before+1,transition)), 'native PerformAction acknowledgement missing')
result.update(verified=True,held_action_verified=True,first_sample=first,last_sample=last,transition_sample=transition,
control_sample=control,motion_sample=motion,released_sample=released,selected_action_id=actions[1]['id'],
native_world_duration_ms=frames[transition]['input']['world_ms']-world_before,
maximum_timing_allowance_seconds=allowance_max,
release_confirmation_scope='actual native released input verified; native keymap/FFI release attestation remains separate runner responsibility')
except (ValueError,KeyError,TypeError,OverflowError,IndexError) as error:
result['errors'].append(str(error))
return result
+267
View File
@@ -0,0 +1,267 @@
"""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<deadline, 'Original observation lifetime expired')
def consume(raw):
nonlocal previous, phase, progress, pressed_ack
s=copy.deepcopy(raw); index=s['sample'];real=number(s['real_ms']);receipt=number(s['received_monotonic'])
need(type(index) is int and anchor['sample']<=index<=450 and queued<=real<queued+45000 and
0<=receipt<=clock(), 'Held native index/clock invalid')
if previous:
need(index>=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<real-previous['real_ms']<=500, 'Held native history has a gap')
else: need(index==anchor['sample'], 'Held handoff omitted selection final sample')
for name in ('origin','camera','direction','body_forward','input','velocity','turn'):vector(s[name])
need(inside(s['origin'],prison) and math.dist(body,s['origin'])<=.05 and
abs(number(s['forward']))<=.01 and length(s['input'])<=.01 and length(s['velocity'])<=.05 and
length(s['turn'])<=.01 and abs(delta(yaw(s['direction']),view))<=.2 and s['inventory'] is False,
'Original stationary inside-prison body/view/input changed')
need(type(s['phase']) is int and s['phase'] in (1,2) and s['phase']>=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<number(geo['radius'])<=10,'Invalid live original door geometry')
if s['phase']==1:
need(geo==pinned and door==0 and control==0, 'Closed gate changed before accepted transition')
observed=choices_for(s,pinned,selected_lock=True)
need(observed==actions, 'Original selected action identities changed')
if down is None or index<=state['press_sample']:
need(pressed==0 and value==0 and not s['performing'], 'Action/input appeared before this F attempt')
else:
need(receipt>=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()<deadline, 'Original held observation deadline expired')
guard.check()
if idle:require_idle()
batch=observe();need(type(batch) is list and 1<=len(batch)<=450,'Missing ordered held snapshots')
for raw in batch:current=consume(raw)
need(0<=clock()-current['received_monotonic']<=.5 and clock()<deadline,'Held native evidence stale or expired')
return current
notify({'kind':'held-action-pending','deadline_monotonic':deadline})
current=read(idle=True)
while True:
samples=state['samples']
if len(samples)>=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,'Actual F request exceeded admission/lease')
event.update(monotonic=down,confirmed=True);state['down_monotonic']=down
while True:
if held 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