from pathlib import Path import os,subprocess,json,hashlib,difflib root=Path('/home/jakub/devel/escapistsrereintroduced');out=Path('/tmp/erri-pair-service-0054');rel='addons/core/Scripts/Game/ERR/10_AI/ERR_ConvoyService.c';test='tests/test_convoy_intercept_pair.py' env=os.environ.copy();env.update(PYTHONPATH=str(root/'tests'),PYTHONDONTWRITEBYTECODE='1') def check(name,source,expected): env['ERR_CONVOY_SERVICE']=str(source) p=subprocess.run(['python3',str(out/test)],cwd=root,env=env,capture_output=True,text=True) (out/name).write_text(p.stdout+p.stderr);assert (p.returncode==0)==expected,(name,p.returncode) return p.returncode check('baseline-red.log',out/'baseline'/rel,False) s=(out/rel).read_text() mut=out/'mutation-rollback.c';mut.write_text(s.replace('{ lead.ClearIntercept(first); return false; }','{ return false; }',1));check('mutation-rollback-red.log',mut,False) mut=out/'mutation-spacing.c';mut.write_text(s.replace('return vector.DistanceXZ(first.Position, second.Position) >= 40;','return vector.DistanceXZ(first.Position, second.Position) >= 0;',1));check('mutation-spacing-red.log',mut,False) check('green.log',out/rel,True) patch=''.join(difflib.unified_diff((out/'baseline'/rel).read_text().splitlines(True),s.splitlines(True),fromfile='a/'+rel,tofile='b/'+rel)) patch+=''.join(difflib.unified_diff([], (out/test).read_text().splitlines(True),fromfile='/dev/null',tofile='b/'+test)) (out/'fix.patch').write_text(patch) p=subprocess.run(['git','apply','--check',str(out/'fix.patch')],cwd=root,capture_output=True,text=True);(out/'apply-check.log').write_text(p.stdout+p.stderr);assert p.returncode==0 manifest={f:hashlib.sha256((out/f).read_bytes()).hexdigest() for f in [rel,test,'fix.patch']} (out/'source-manifest.json').write_text(json.dumps(manifest,indent=2)+'\n') (out/'finding.json').write_text(json.dumps({'scope':'One original convoy pair, distinct original escorts and HQ tokens, same delivered memory/timing, minimum 40m horizontal separation. No actors/items/ammo spawned. Only two native waypoint entities allocated.','files':[rel,test],'tests':{'pair':'green.log','singleton_lifecycle':'lifecycle.log','geometry_existing':'rules.log','baseline':'baseline-red.log is explicit absent pair API assertion, not a claimed runtime behavior failure','mutations':['mutation-rollback-red.log','mutation-spacing-red.log']},'limits':['Offline engine API doubles; physical driving/native callback timing unqualified.','Preallocation and precommit failures leave both original routes unchanged; native ClearOrder/AddWaypoint boundary failures cancel exact claims, without atomic rollback or route restoration claim.','Existing singleton behavior and legacy direct recursive ClearIntercept callback handling unchanged; no concrete native recursive callback demonstrated.'],'adapters':'No existing harness changes needed; test_hq_mounted_intercept extracts geometry only. New pair test reuses unchanged lifecycle native doubles, extracts complete actual vehicle and actual service methods.'},indent=2)+'\n') print(json.dumps(manifest,indent=2))