68 lines
4.4 KiB
Python
68 lines
4.4 KiB
Python
"""Strict read-only joins for optional native gate action-choice diagnostics."""
|
|
import re
|
|
from ordinary_gate_evidence import join_gate_snapshots
|
|
|
|
PREFIX='ERR GATE CHOICE: '
|
|
IDENT=r'([A-Za-z_][A-Za-z_0-9]{0,127}):(-?\d+)'
|
|
BOOL=r'(0|1|true|false)'
|
|
LINE=re.compile(r'run=([A-Za-z0-9]{1,32}) sample=(\d+) real=(\d+) selected='+IDENT+r' context='+BOOL+r' actions=(\d+) permissions=(\d+) shown=(\d+) truncated='+BOOL+r' ordered=\[(.*)\]')
|
|
ENTRY=re.compile(r'(\d+)='+IDENT+r':(-?\d+)')
|
|
|
|
def need(value,reason):
|
|
if not value: raise ValueError(reason)
|
|
|
|
|
|
def parse_choice_record(line,nonce):
|
|
need(type(nonce) is str and re.fullmatch(r'[A-Za-z0-9]{1,32}',nonce),'invalid choice nonce')
|
|
if PREFIX.rstrip() not in line:return None
|
|
need(PREFIX in line and line.count(PREFIX)==1 and len(line)<=4096,'invalid choice line')
|
|
match=LINE.fullmatch(line.split(PREFIX,1)[1].strip());need(match is not None,'malformed choice record')
|
|
run,index,real,selected_class,selected_id,context,count,permissions,shown,truncated,ordered=match.groups()
|
|
index,real,selected_id,count,permissions,shown=map(int,(index,real,selected_id,count,permissions,shown))
|
|
need(run==nonce and 1<=index<=450 and 0<=real<=2147483647,'choice nonce or clock mismatch')
|
|
need(-1<=selected_id<=2147483647 and ((selected_class=='none')==(selected_id==-1)),'invalid selected action identity')
|
|
need(0<=count<=4096 and 0<=permissions<=4096 and shown==min(count,8) and (truncated in ('1','true'))==(count>shown),'choice list bounds disagree')
|
|
entries=[] if not ordered else ordered.split(',');need(len(entries)==shown,'choice entry count disagrees')
|
|
actions=[]
|
|
for i,text in enumerate(entries):
|
|
m=ENTRY.fullmatch(text);need(m is not None,'malformed ordered action')
|
|
n,cls,identity,permission=m.groups();n,identity,permission=map(int,(n,identity,permission))
|
|
need(n==i and -1<=identity<=2147483647 and ((cls=='none')==(identity==-1)),'ordered action identity/index invalid')
|
|
need(permission in (-1,0,1) and ((permission==-1)==(i>=permissions)),'cached permission index mismatch')
|
|
actions.append({'class':cls,'id':identity,'permitted':None if permission==-1 else bool(permission)})
|
|
return {'nonce':nonce,'sample':index,'real_ms':real,'selected_class':selected_class,'selected_id':selected_id,'context_selected':context in ('1','true'),'action_count':count,'permission_count':permissions,'truncated':truncated in ('1','true'),'actions':actions}
|
|
|
|
|
|
def parse_choice_records(content,nonce):
|
|
need(type(content) is str and len(content)<=32*1024*1024,'choice content bound')
|
|
records={};previous_real=-1
|
|
for line in content.splitlines():
|
|
r=parse_choice_record(line,nonce)
|
|
if r is None:continue
|
|
need(r['sample']==len(records)+1 and r['real_ms']>previous_real,'choice sequence missing, repeated or reversed')
|
|
records[r['sample']]=r;previous_real=r['real_ms']
|
|
need(records,'native choices absent')
|
|
return records
|
|
|
|
|
|
def join_choice_snapshots(content,nonce):
|
|
data=join_gate_snapshots(content,nonce);records=parse_choice_records(content,nonce)
|
|
for i,c in records.items():
|
|
need(i in data['snapshots'],'choice has no native gate peer')
|
|
s=data['snapshots'][i];a=s['action'];need(c['real_ms']==s['real_ms'] and c['context_selected']==a['context_selected'],'choice/gate clock or context mismatch')
|
|
if a['selected']:need(c['selected_class']=='ERR_UnlockPrisonAction','selected lock class disagrees')
|
|
if c['selected_class']=='ERR_UnlockPrisonAction':need(a['selected'],'native selected lock flag disagrees')
|
|
s['choices']=c
|
|
return data
|
|
|
|
|
|
def exact_prison_choices(snapshot):
|
|
"""Known non-aggregating closed Open/lock pair; not a general action sorter."""
|
|
c=snapshot.get('choices');need(type(c) is dict,'native choice snapshot absent')
|
|
a=c['actions'];need(c['context_selected'] and not c['truncated'] and c['action_count']==c['permission_count']==len(a)==2,'expected exact original two-action context')
|
|
need([e['class'] for e in a]==['ERR_PrisonDoorAction','ERR_UnlockPrisonAction'],'unsupported native action order')
|
|
need(all(type(e['id']) is int and e['id']>=0 for e in a) and a[0]['id']!=a[1]['id'],'invalid original action IDs')
|
|
need(a[0]['permitted'] is False and a[1]['permitted'] is True,'native closed-door/lock permissions changed')
|
|
need((c['selected_class'],c['selected_id']) in [(e['class'],e['id']) for e in a],'selected action outside original pair')
|
|
return c
|