Prepare independent successor playtest with spawn recovery and casualty feedback
This commit is contained in:
+88
-6
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user