Files
ARCADIA-Studio/harness/scenario-group-spacing-evidence-20260924/native/verify.py
T

100 lines
9.7 KiB
Python

"""Offline archive/source/lifetime evidence checks. Screenshots require independent human review."""
from pathlib import Path,PurePosixPath
from decimal import Decimal
import argparse,hashlib,json,re,zipfile
def pin(data):return {'bytes':len(data),'sha256':hashlib.sha256(data).hexdigest()}
def main():
parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('directory',type=Path);args=parser.parse_args();root=args.directory.resolve()
manifest=json.loads((root/'manifest.json').read_text(encoding='utf-8'));raw=(root/'native-evidence.zip').read_bytes();assert pin(raw)==manifest['archive'],'Archive pin mismatch'
with zipfile.ZipFile(root/'native-evidence.zip') as archive:
names=archive.namelist();assert len(names)==len(set(names)) and set(names)==set(manifest['members']),'Archive member inventory mismatch'
for name in names:
p=PurePosixPath(name);assert not p.is_absolute() and '..' not in p.parts and '\\' not in name and ((archive.getinfo(name).external_attr>>16)&0o170000)!=0o120000,'Unsafe member'
files={name:archive.read(name) for name in names}
for name,data in files.items():assert pin(data)==manifest['members'][name],name
assert not any(PurePosixPath(n).suffix.lower() in ('.exe','.dll') for n in files),'Binary bytes unexpectedly included'
assert (root/'verify.py').read_bytes()==files['helpers/native-evidence-verify.py'],'External verifier differs from archived exact helper'
def js(name):return json.loads(files[name].decode('utf-8-sig'))
fixture=js('fixtures/fixture-manifest.json')
for name,expected in fixture['files'].items():assert pin(files['fixtures/'+name])==expected,'Fixture pin mismatch'
phase_names={'baseline':'baseline.arcadia','messages':'expected-messages.arcadia','messages-and-lanes':'expected-messages-and-lanes.arcadia'}
number=rb'[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?'
fields=[(rb'(occurrence @alpha_report; \}; send_y )('+number+rb')(;)',Decimal(184)),(rb'(occurrence @gamma_report; \}; send_y )('+number+rb')(;)',Decimal(384)),(rb'(lifeline @intake_lane; x )('+number+rb')(;)',Decimal(172)),(rb'(lifeline @review_lane; x )('+number+rb')(;)',Decimal(432))]
def check_source(actual,phase):
expected=files['fixtures/'+phase_names[phase]]
if phase=='baseline':assert actual==expected,'Baseline source differs';return
def section(data):
a=b' diagram trial_a ';b=b' diagram trial_b ';assert data.count(a)==data.count(b)==1
start=data.index(a);end=data.index(b);assert start<end;return start,end
ea,eb=section(expected);aa,ab=section(actual);replacements=[]
for pattern,wanted in fields[:2 if phase=='messages' else 4]:
em=list(re.finditer(pattern,expected[ea:eb]));am=list(re.finditer(pattern,actual[aa:ab]));assert len(em)==len(am)==1
value=Decimal(am[0].group(2).decode('ascii'));assert value.is_finite() and value==wanted==Decimal(em[0].group(2).decode('ascii')),'Wrong moved coordinate'
replacements.append((aa+am[0].start(2),aa+am[0].end(2),em[0].group(2)))
for start,end,spelling in sorted(replacements,reverse=True):actual=actual[:start]+spelling+actual[end:]
assert actual==expected,'Other source bytes differ'
config=js('review-config.json');assert config['runs']==manifest['runs'];reports=[]
for run in config['runs']:
prefix='runs/'+run['name']+'/'
prepared=js(prefix+'prepared.json');started=js(prefix+'started.json');finished=js(prefix+'finished.json');problems=[]
def require(condition,description):
if not condition: problems.append(description)
require(pin(files[prefix+'prepared.json'])==started['prepared'],'Started prepared receipt binding')
for rel,expected in prepared['immutable'].items():
name=prefix+rel
require((pin(files[name]) if name in files else manifest['excluded_binary_bytes'].get(name))==expected,'Immutable pin: '+rel)
require(prepared['helper']==pin(files[prefix+'evidence/native-harness.py']),'Native helper binding')
receipt=js(prefix+'evidence/result.json');proof=js(prefix+'evidence/source-proof.json');inputs=js(prefix+'evidence/inputs.json')
require(receipt['exitCode']==0 and receipt['inputsUnchanged'] is True,'Closed successful unchanged build')
require(proof['result']==pin(files[prefix+'evidence/result.json']),'Build result proof pin')
require(proof['inputMap']==receipt['inputs']==pin(files[prefix+'evidence/inputs.json']),'Input map binding')
require(proof['inputCount']==receipt['inputCount']==len(inputs),'Input inventory count')
require(proof['commit']==receipt['head']==prepared['source'],'Source identity')
gui=[a for a in receipt['artifacts'] if a['cargo']['target']['name']=='arcadia-studio' and not a['cargo']['profile']['test']]
require(len(gui)==1 and gui[0]['readback']==prepared['artifact']==manifest['excluded_binary_bytes'].get(prefix+'bin/arcadia-studio.exe'),'Exact GUI artifact binding')
require(finished['exitCode']==0 and finished['immutableUnchanged'] is True,'Normal exit and immutable report')
for stream in ['stdout','stderr']:require(finished[stream]==pin(files[prefix+'app.'+stream+'.log']),'Final log pin: '+stream)
require(finished['working']==pin(files[prefix+'working.arcadia']),'Final working source pin')
if prefix+'reopen-origin.json' in files:
origin=js(prefix+'reopen-origin.json');from_name='runs/'+origin['from_run']+'/'+origin['from_file'];require(from_name in files,'Reopen source present')
if from_name in files:require(pin(files[from_name])==origin['from_pin']==origin['copied_pin']==started['workingBefore'],'Reopened input exact copy binding')
else:require(started['workingBefore']==fixture['files']['baseline.arcadia'],'Fresh run begins at original baseline')
phases=dict(run.get('source_phases',{}));source_files=[n for n in files if n.startswith(prefix) and n.endswith('.arcadia') and '/evidence/' not in n and n!=prefix+'baseline.arcadia']
for name in source_files:
rel=name[len(prefix):];sidecar=name[:-8]+'.json'
phase=phases.get(rel)
if sidecar in files:
saved=js(sidecar)
if 'phase' in saved:
require(phase is None or phase==saved['phase'],'Snapshot phase assignment consistency');phase=phase or saved['phase']
require(saved['pin']==pin(files[name]),'Snapshot receipt source pin')
if phase not in phase_names:problems.append('Explicit phase missing: '+rel);continue
try:check_source(files[name],phase)
except (AssertionError,ValueError,KeyError) as error:problems.append('Source comparison '+rel+': '+str(error))
# Every referenced screenshot must be present; archive inventory pins its exact bytes.
captures=0
for name in files:
if name.startswith(prefix) and name.endswith('.json'):
obj=js(name)
if isinstance(obj,dict) and 'images' in obj:
captures+=1
for image in obj['images']:require(prefix+image['file'] in files,'Capture image missing: '+image['file'])
require(captures>0,'No native capture observations retained')
reports.append({'run':run['name'],'reviewer_accepted':run['accepted'],'checks_pass':not problems,'problems':problems,'capture_records':captures})
if run['accepted']:assert not problems,json.dumps(reports[-1],indent=2)
old=js('preflight/fixture-preflight-1/result.json') # Retained as history, never promoted to a pass.
current=js('preflight/fixture-preflight-2/result.json');assert current['status'].startswith('PASS') and current['cliUnchanged'] is True
cp='preflight/fixture-preflight-2/';cr=js(cp+'evidence/result.json');proof=js(cp+'evidence/source-proof.json')
assert current['receipt']==proof['result']==pin(files[cp+'evidence/result.json']) and current['proof']==pin(files[cp+'evidence/source-proof.json'])
cli=[a for a in cr['artifacts'] if a['cargo']['target']['name']=='arcadia' and not a['cargo']['profile']['test']];assert len(cli)==1 and cli[0]['readback']==current['cli']==manifest['excluded_binary_bytes'][cp+'bin/arcadia.exe']
assert {check['fixture'] for check in current['checks']}==set(fixture['files']) and len(current['checks'])==3,'All three fixture preflights required'
assert cr['exitCode']==0 and cr['inputsUnchanged'] is True and current['source']==cr['head']==proof['commit'],'Current CLI closed source binding'
for check in current['checks']:
name=check['fixture'];assert check['exitCode']==0 and check['json_report'] and check['fixtureUnchanged']
assert pin(files[cp+name+'.stdout.json'])==check['stdout'] and pin(files[cp+name+'.stderr.log'])==check['stderr']
assert pin(files[cp+'fixtures/'+name])==fixture['files'][name]
report=js(cp+name+'.stdout.json');assert isinstance(report,dict) and report['operation']=='check' and report['exit_code']==0 and report['written'] is False and not any(d['severity']=='error' for d in report['diagnostics']),'Raw CLI report must independently confirm valid read-only check'
print(json.dumps({'status':'PASS offline archive, source and receipt consistency checks','runs':reports,'old_preflight_retained':True,'limitations':['Human visual/interaction claims not inferred from screenshots.','Omitted executable/DLL bytes cannot be rehashed offline.','Build input map/source proof consistency checked; Git blobs not independently available offline.','Failed attempts retained with accepted=false are reported, not silently asserted passing.']},indent=2))
if __name__=='__main__': main()