Files
ARCADIA-Studio/harness/experiments/allocation-drawing-301126f-20260923/native/check.py
T

109 lines
7.6 KiB
Python

"""Complete saved-bundle Allocation oracle; only OA/SA relation UUIDs may bind."""
from pathlib import Path,PurePosixPath
import argparse,copy,datetime,json,re,subprocess,uuid
from stage import HERE,record,read,verify,write,copy_new,child_env,canonical
def safe(p):
p=p.absolute()
if not p.is_relative_to(HERE):raise RuntimeError('Outside native root')
q=p
while True:
if q.exists() and (q.is_symlink() or q.is_junction() or getattr(q.lstat(),'st_file_attributes',0)&1024):raise RuntimeError('Linked/reparse path')
if q==HERE:break
q=q.parent
if not p.resolve().is_relative_to(HERE.resolve()):raise RuntimeError('Resolved path escapes native root')
return p
def inventory(root):
safe(root);out={}
for p in root.rglob('*'):
safe(p)
if p.is_file() and p.suffix.lower()=='.arcadia':out[p.relative_to(root).as_posix()]={k:record(p)[k] for k in ('bytes','sha256')}
return out
def identities(value):
result=set()
def walk(v):
if isinstance(v,dict):
for k,x in v.items():walk(k);walk(x)
elif isinstance(v,list):
for x in v:walk(x)
elif isinstance(v,str):
try:result.add(str(uuid.UUID(v)))
except ValueError:pass
walk(value);return result
def main():
ap=argparse.ArgumentParser();ap.add_argument('--expected',choices=['B','O','OS'],required=True);ap.add_argument('--checkpoint',required=True,type=Path);a=ap.parse_args()
dest=safe(a.checkpoint if a.checkpoint.is_absolute() else HERE/a.checkpoint)
if dest.exists() or dest==HERE:raise RuntimeError('Fresh checkpoint directory required')
if (HERE/'UNACCEPTED.json').exists():raise RuntimeError('Trial quarantined; never delete or relearn binding')
stage=read(HERE/'staging-record.json');verify(stage['manifest']);manifest=read(HERE/'input-manifest.json')
for r in manifest['immutable_files']:verify(r)
catalog=read(HERE/'expected/catalog.json');contract=read(catalog['contract']['path']);baseline=read(catalog['checkpoints']['B']['path'])
bindings={};binding_records={}
for key in ('OA','SA'):
p=HERE/(key+'-binding.json')
if p.exists():
safe(p);b=read(p);verify(b['first_receipt']);first=read(b['first_receipt']['path'])
if b['source_commit']!=manifest['source_commit'] or first['source_commit']!=manifest['source_commit'] or not first['accepted'] or first['new_bindings'].get(key)!=b['relation_uuid'] or b['manifest']['sha256']!=stage['manifest']['sha256']:raise RuntimeError('Binding lacks complete accepted checkpoint')
bindings[key]=b['relation_uuid'];binding_records[key]=record(p)
if 'SA' in bindings and 'OA' not in bindings:raise RuntimeError('Invalid binding order')
if a.expected=='OS' and 'OA' not in bindings:raise RuntimeError('First O must bind before first OS')
entry=safe(Path(manifest['saved_working_path']));work=HERE/'working'
if entry.parent!=work:raise RuntimeError('Unexpected saved entry')
dest.mkdir(parents=True);safe(dest)
receipt={'started_utc':datetime.datetime.now(datetime.timezone.utc).isoformat(),'source_commit':manifest['source_commit'],'converter_source_commit':manifest['converter_source_commit'],'expected':a.expected,'accepted':False,'failure':None,'manifest':stage['manifest'],'catalog':record(HERE/'expected/catalog.json'),'bindings_before':binding_records,'new_bindings':{},'commands':[]}
new={}
try:
before=inventory(work);receipt['original_before']=before
# Fixed generated bundle: only direct entry includes. No path rewriting.
text=entry.read_text(encoding='utf-8-sig');includes=re.findall(r'\binclude\s+"([^"\r\n]+)"\s*;',text)
if len(re.findall(r'\binclude\b',text))!=len(includes):raise RuntimeError('Unsupported include syntax')
for name in includes:
p=PurePosixPath(name)
if p.is_absolute() or '..' in p.parts or str(p)!=name or ':' in name or '\\' in name or name not in before:raise RuntimeError('Unsafe/missing include')
if re.search(r'\binclude\b',(work/name).read_text(encoding='utf-8-sig')):raise RuntimeError('Nested includes not predeclared')
if set(before)!={entry.name,*includes}:raise RuntimeError('Unexpected source files')
if any(x in before for x in ('converted.arcadia','state.arcadia')):raise RuntimeError('Snapshot filename collision')
for name in before:
target=dest/name;target.parent.mkdir(parents=True,exist_ok=True);copy_new(work/name,target)
if inventory(dest)!=before or inventory(work)!=before:raise RuntimeError('Bundle changed while copying')
def run(name,binary,input_path,output):
argv=[binary['path'],str(input_path),str(output)]
with (dest/(name+'.stdout.log')).open('xb') as out,(dest/(name+'.stderr.log')).open('xb') as err:p=subprocess.run(argv,cwd=HERE/'unrelated-cwd',env=child_env(),stdout=out,stderr=err)
receipt['commands'].append({'argv':argv,'cwd':str(HERE/'unrelated-cwd'),'binary':binary,'exit_code':p.returncode,'stdout':record(dest/(name+'.stdout.log')),'stderr':record(dest/(name+'.stderr.log'))})
if p.returncode or (dest/(name+'.stderr.log')).stat().st_size:raise RuntimeError(name+' failed')
converted=dest/'converted.arcadia';run('converter',manifest['converter'],dest/entry.name,converted)
actual=dest/'actual.project.json';run('evaluator',manifest['evaluator'],converted,actual)
observed=read(actual);expected=copy.deepcopy(baseline);needed=contract['states'][a.expected]
known={bindings[k] for k in needed if k in bindings}
unseen=set(observed['relations'])-set(baseline['relations'])-known
missing=[k for k in needed if k not in bindings]
if len(missing)>1 or len(unseen)!=len(missing):raise RuntimeError('Exactly one new relation identity at first O/OS only')
if missing:
rid=next(iter(unseen));u=uuid.UUID(rid)
if str(u)!=rid or u.version!=4 or u.variant!=uuid.RFC_4122 or rid in identities(baseline) or rid in bindings.values():raise RuntimeError('Not a distinct fresh canonical UUIDv4')
new[missing[0]]=rid
for key in needed:
rid=bindings.get(key,new.get(key));relation=copy.deepcopy(contract['relations'][key]);relation['id']=rid;expected['relations'][rid]=relation
if canonical(observed)!=canonical(expected):raise RuntimeError('Complete Project differs from fixed B/O/OS')
after=inventory(work);snapshot=inventory(dest);expected_snapshot=dict(before);expected_snapshot['converted.arcadia']={k:record(converted)[k] for k in ('bytes','sha256')}
receipt['original_after']=after;receipt['snapshot_after']=snapshot
if after!=before or snapshot!=expected_snapshot:raise RuntimeError('Bundle changed during evaluation')
for r in manifest['immutable_files']:verify(r)
verify(stage['manifest'])
for r in binding_records.values():verify(r)
safe(dest);receipt['new_bindings']=new;receipt['actual_project']=record(actual);receipt['converted_source']=record(converted);receipt['accepted']=True
except Exception as e:receipt['failure']=str(e)
receipt['finished_utc']=datetime.datetime.now(datetime.timezone.utc).isoformat()
try:
write(dest/'receipt.json',receipt)
if not receipt['accepted']:raise RuntimeError(receipt['failure'])
for key,rid in new.items():write(HERE/(key+'-binding.json'),{'source_commit':manifest['source_commit'],'relation_uuid':rid,'manifest':stage['manifest'],'catalog':record(HERE/'expected/catalog.json'),'first_receipt':record(dest/'receipt.json'),'scope':'UUID only, after full bundle and complete Project equality; never relearn'})
except Exception as e:
if not (HERE/'UNACCEPTED.json').exists():write(HERE/'UNACCEPTED.json',{'checkpoint':str(dest),'failure':str(e),'scope':'Any bindings created by this failed outer operation are unaccepted; stop and preserve'})
raise
print(a.expected+': complete saved bundle and Project exact; relation identities fixed')
if __name__=='__main__':main()