float_library_acceptance.py (5744B)
1 #!/usr/bin/env python3 2 """Check the public contract-composition demo and three bounded usability smokes. 3 4 Uses the preceding library-only boundary run, verifies its source receipt, and 5 checks fresh-process workloads against an explicit host-local latency budget. 6 """ 7 import argparse 8 import json 9 from pathlib import Path 10 11 from float_boundary import ROOT, Runner, sha, ok, err, nat, pair, tree_list, LEAF, TRUE, expect 12 from float_ieee import class_words, boundary_pairs 13 from float_chains import chain_oracle, payload, groups, raw_rows 14 15 16 def main(): 17 p=argparse.ArgumentParser(description=__doc__) 18 p.add_argument('tricu',type=Path);p.add_argument('--boundary-run',type=Path,required=True) 19 p.add_argument('--directory',type=Path,required=True) 20 p.add_argument('--support-bundle',type=Path,help='exercise the published demo and library providers') 21 args=p.parse_args() 22 prior=json.loads((args.boundary_run/'report.json').read_text()) 23 assert prior['complete'] and prior['library_source'] 24 assert bool(args.support_bundle)==bool(prior.get('artifact_providers')) 25 if args.support_bundle: 26 assert sha(args.support_bundle)==prior['artifact_providers']['binary64']['bundle_sha256'] 27 paths={'driver.tri':'test/float_boundary_driver.tri','binary64.tri':'lib/math/binary64.tri','native_math.tri':'lib/math/native.tri'} 28 paths.update({'binary64_'+f.name:str(f.relative_to(ROOT)) for f in (ROOT/'lib/math/binary64').glob('*.tri')}) 29 assert {k:sha(ROOT/v) for k,v in paths.items()}==prior['sources'] 30 assert sha(args.tricu)==prior['runtime_sha256'] 31 root=args.directory.resolve();root.mkdir(parents=True,exist_ok=False);work=root/'workspace';work.mkdir() 32 (work/'tricu.workspace').write_text('tricu.workspace.v1\n') 33 paths.pop('driver.tri');paths.update({'demo.tri':'demos/binary64.tri','base.tri':'lib/base.tri'}) 34 for n,path in paths.items():(work/n).write_bytes((ROOT/path).read_bytes()) 35 (work/'driver.tri').write_text('!import demo as D\n!export batch\ntriage l s f = t (t l s) f\nbatch xs = triage t (_ : t) (a b : t (D.main a) (batch b)) xs\n') 36 runner=Runner(args.tricu,root,1200,memory_mib=2048) 37 report=dict(complete=False,sources={n:sha(work/n) for n in [*paths,'driver.tri']},harness_sha256=sha(Path(__file__)), 38 runtime_sha256=sha(args.tricu),boundary_bundle_sha256=prior['bundle_sha256'],checks=0,smokes=[]) 39 try: 40 if args.support_bundle: 41 from float_fixture import stage_providers 42 report['artifact_providers']=stage_providers(runner,work,args.support_bundle,['demos_binary64']) 43 (work/'demo.tri').write_bytes((work/'demos_binary64.tri').read_bytes()) 44 report['workspace_sources']={p.name:sha(p) for p in work.glob('*.tri')} 45 tool=runner.imported(ROOT/'bootstrap/build-stable.arboricx','compiler');bundle=root/'demo.arboricx' 46 runner.run('compile',['compile','--file',work/'driver.tri','--toolchain',tool,'--tool-store',runner.store, 47 '--store',runner.store,'--output',bundle,'--compile-timeout','240'],270) 48 pin=runner.imported(bundle,'demo');report['demo_bundle_sha256']=sha(bundle) 49 def invoke(label,pin,name,raw,wanted,smoke=False): 50 file=root/(label+'.input.tree');file.write_bytes(raw) 51 actual=runner.invoke(label,pin,name,['--arg-tree-file',file,'--profile-full-result']) 52 expect(actual,wanted,label) 53 if smoke: 54 points={v['profile']:v for line in (root/(label+'.log')).read_text().splitlines() if line.startswith('{') for v in [json.loads(line)]} 55 start,finish=points['invoke-begin-1'],points['force-end-1'] 56 elapsed=(finish['wall_ns']-start['wall_ns'])/1e9 57 report['smokes'].append(dict(name=label,seconds=elapsed,allocated_bytes=finish['allocated_bytes']-start['allocated_bytes'], 58 maximum_live_bytes=runner.records[-1]['rts_process']['maximum_live_bytes'],budget_seconds=2,within_budget=elapsed<=2)) 59 assert elapsed<=2,(label,'local usability smoke budget exceeded') 60 def expected(a,b):return ok(payload(chain_oracle((a,[b,a],[(2,0),(0,1)])))) 61 pairs=list(dict.fromkeys([(a,b) for a in class_words() for b in class_words()]+boundary_pairs())) 62 for start in range(0,len(pairs),12): 63 batch=pairs[start:start+12] 64 invoke('demo-'+str(start),pin,'batch',tree_list([pair(nat(a),nat(b)) for a,b in batch]),tree_list([expected(a,b) for a,b in batch])) 65 report['checks']+=len(pairs) 66 not_pair=pair(LEAF,pair(tree_list([nat(ord(c)) for c in 'not a pair']),LEAF)) 67 invalid=[LEAF,TRUE,pair(TRUE,nat(1)),pair(nat(1),nat(1<<64))] 68 invoke('demo-errors',pin,'batch',tree_list(invalid),tree_list([not_pair,not_pair,err(),err()])) 69 report['checks']+=len(invalid) 70 small=[(0x3ff0000000000000,0x4000000000000000),(0x3fe0000000000000,0x3ff0000000000000), 71 (0xbff0000000000000,0x3fe0000000000000),(0,0x4000000000000000)] 72 invoke('four-affine-values',pin,'batch',tree_list([pair(nat(a),nat(b)) for a,b in small]), 73 tree_list([expected(a,b) for a,b in small]),True) 74 old_bundle=args.boundary_run/'boundary.arboricx';assert sha(old_bundle)==prior['bundle_sha256'] 75 chain_pin=runner.imported(old_bundle,'chains') 76 for name in ['add-reuse-16','divide-reuse-4']: 77 rows=groups()[name] 78 invoke(name,chain_pin,'chains',raw_rows(rows),tree_list([payload(chain_oracle(row)) for row in rows]),True) 79 report['complete']=True 80 print(json.dumps(report['smokes'],indent=2)) 81 finally:(root/'report.json').write_text(json.dumps(report,indent=2)+'\n') 82 83 if __name__=='__main__':main()