from pathlib import Path import subprocess,os,json,hashlib,difflib r=Path('/home/jakub/devel/escapistsrereintroduced');o=Path('/tmp/erri-mine-zones-tests-0558');a=Path('/tmp/erri-base-review-0558');rel='addons/core/Scripts/Game/ERR/10_AI/ERR_EngineerMine.c';p=a/rel s=p.read_text();old='if (!groupUtility || !groupUtility.IsPositionAllowed(m_Position)) return false;';assert old in s mutation=o/'begin-only.c';mutation.write_text(s.replace(old,'if (m_Started < 0 && (!groupUtility || !groupUtility.IsPositionAllowed(m_Position))) return false;',1)) env=dict(os.environ,PYTHONPATH=str(r/'tests'),TMPDIR=str(o/'scratch')) results=[] for name,source,expected in [('baseline-red',a/'baseline'/rel,False),('continuation-mutation-red',mutation,False),('green',p,True)]: env['ERR_ENGINEER_MINE_SOURCE']=str(source) with (o/(name+'.log')).open('w') as f: proc=subprocess.run(['python3',str(o/'tests/test_engineer_mine.py')],env=env,stdout=f,stderr=subprocess.STDOUT) log=(o/(name+'.log')).read_text();assert (proc.returncode==0)==expected,(name,log) if not expected: assert 'Assertion' in log and 'failed.' in log and 'g++' not in log,(name,log) results.append({'name':name,'exit_code':proc.returncode,'source_sha256':hashlib.sha256(source.read_bytes()).hexdigest(),'log_sha256':hashlib.sha256((o/(name+'.log')).read_bytes()).hexdigest(),'compiled':True}) before=(r/'tests/test_engineer_mine.py').read_text();after=(o/'tests/test_engineer_mine.py').read_text();patch=''.join(difflib.unified_diff(before.splitlines(True),after.splitlines(True),fromfile='a/tests/test_engineer_mine.py',tofile='b/tests/test_engineer_mine.py'));(o/'fix.patch').write_text(patch) review={'status':'pass','source_sha256':hashlib.sha256(p.read_bytes()).hexdigest(),'test_sha256':hashlib.sha256((o/'tests/test_engineer_mine.py').read_bytes()).hexdigest(),'test_baseline_sha256':hashlib.sha256((r/'tests/test_engineer_mine.py').read_bytes()).hexdigest(),'patch_sha256':hashlib.sha256((o/'fix.patch').read_bytes()).hexdigest(),'results':results,'coverage':['Missing group utility and strict 30m equality refuse before attempted-item insert, intel capture, action creation or inventory removal.','3D native defend envelope rejects x25/y17 but accepts x25/y16; x29.999 accepted. Autonomous envelope uses current group center and strict radius.','12 continuation cases: all four controller phases times changed defend waypoint, replacement denying utility, or missing utility. Exact owned action completed once; unrelated action untouched.','Reopened envelope and late callback cannot resume or arm. Item tombstone retained. Existing entire harness remains, including fixed180s deadline,10s continuous preparation,256-item quarantine, custody, native refusal and20m clearance.'],'boundary':'Group utility is a native boundary double matching installed SCR_AIGroupUtilityComponent.IsPositionAllowed lines917 onward. Actual production Begin,Owned,Tick,Stop and related methods are extracted unchanged apart from existing C++ syntax adaptation. This is the native group movement envelope, not navmesh or general forbidden-zone proof.','limits':['No native or Enforce compilation.','No target/original writes, no full suite.'],'all_compilers_finished':True} (o/'review.json').write_text(json.dumps(review,indent=2)+'\n');print(json.dumps(review,indent=2))