Capture current mission, AI, map and administration development

Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
This commit is contained in:
2026-10-13 22:52:53 +02:00
parent a951a96edc
commit 6a667d8deb
8104 changed files with 2124945 additions and 2061 deletions
@@ -0,0 +1,19 @@
check: /tmp/err-policy-3p7h95dp/check.cpp:128: int main(): Assertion `!owner.reads&&!actor.reads&&!look.inputReads' failed.
Traceback (most recent call last):
File "/tmp/erri-random-radius-tests-0504/tests/test_native_random_radius_trace.py", line 28, in <module>
run(r'''
~~~^^^^^
#include <cassert>
^^^^^^^^^^^^^^^^^^
...<68 lines>...
}
^
''')
^^^^
File "/home/jakub/devel/escapistsrereintroduced/tests/policy_harness.py", line 14, in run
subprocess.run([str(p/'check')],check=True)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/subprocess.py", line 578, in run
raise CalledProcessError(retcode, process.args,
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['/tmp/err-policy-3p7h95dp/check']' died with <Signals.SIGABRT: 6>.
@@ -0,0 +1,108 @@
// Explicit Workbench diagnostic only. Preserve every native superclass result,
// output and random draw; this observes zero-radius callers without correcting them.
#ifdef WORKBENCH
class ERR_NativeRandomRadiusTrace
{
protected static bool s_Checked;
protected static bool s_Enabled;
protected static int s_Count;
static bool CanTrace()
{
if (!s_Checked)
{
s_Checked = true;
string value;
s_Enabled = System.GetCLIParam("errTraceRandomRadius", value) && value == "1";
}
return s_Count < 16;
}
static void Log(string context, AIAgent owner, float inner, float outer, string details, Node node = null)
{
if (!CanTrace()) return;
s_Count++;
string nodeStack;
if (node) node.GetCallstackStr(nodeStack);
PrintFormat("ERR ZERO RADIUS TRACE: sample=%1/16 class=%2 owner=%3 inner=%4 outer=%5 %6 nodeStack=%7", s_Count, context, owner, inner, outer, details, nodeStack);
Debug.DumpStack();
}
}
modded class SCR_AIGetRandomPoint
{
override ENodeResult EOnTaskSimulate(AIAgent owner, float dt)
{
ENodeResult result = super.EOnTaskSimulate(owner, dt);
// The superclass updates these fields from the actual waypoint/input ports.
if (ERR_NativeRandomRadiusTrace.CanTrace() && result == ENodeResult.SUCCESS && m_ExclusionRadius == 0 && m_Radius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AIGetRandomPoint", owner, m_ExclusionRadius, m_Radius, string.Format("phase=after-success node=%1", this), this);
return result;
}
}
modded class SCR_AIGetRandomLookPosition
{
override ENodeResult EOnTaskSimulate(AIAgent owner, float dt)
{
if (ERR_NativeRandomRadiusTrace.CanTrace() && owner)
{
IEntity controlledEntity = owner.GetControlledEntity();
vector inPos;
if (controlledEntity && GetVariableIn(PORT_IN_POS, inPos))
{
float distance = vector.Distance(controlledEntity.GetOrigin(), inPos);
float radius = distance * m_fTangent;
if (radius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AIGetRandomLookPosition", owner, 0, radius, string.Format("phase=before-super node=%1 entity=%2 inPos=%3 distance=%4 tangent=%5", this, controlledEntity, inPos, distance, m_fTangent), this);
}
}
return super.EOnTaskSimulate(owner, dt);
}
}
modded class SCR_AICalculateNextCombatMovePos
{
override protected vector RandomizeDestinationPos(float distance, vector centerPos)
{
if (ERR_NativeRandomRadiusTrace.CanTrace())
{
float radius = 0.1 * distance;
if (radius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AICalculateNextCombatMovePos", null, 0, radius, string.Format("phase=before-super node=%1 center=%2 distance=%3 scale=0.1", this, centerPos, distance), this);
}
return super.RandomizeDestinationPos(distance, centerPos);
}
}
modded class SCR_AIGetRandomPointWithExclude
{
override protected bool FindPosition2D(out vector randomPos, vector randomSphereOrigin, float randomSphereRadius, vector excludeSphereOrigin = vector.Zero, float excludeRadius = 0, int iterationCount = 50)
{
if (ERR_NativeRandomRadiusTrace.CanTrace())
{
if (randomSphereOrigin == excludeSphereOrigin || excludeRadius < 1.0e-8)
{
if (excludeRadius == 0 && randomSphereRadius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AIGetRandomPointWithExclude", null, excludeRadius, randomSphereRadius, string.Format("phase=before-super branch=direct node=%1 origin=%2 excludedOrigin=%3 excludeRadius=%4 iterations=%5", this, randomSphereOrigin, excludeSphereOrigin, excludeRadius, iterationCount), this);
}
else if (iterationCount > 0 && randomSphereRadius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AIGetRandomPointWithExclude", null, 0, randomSphereRadius, string.Format("phase=before-super branch=iterative node=%1 origin=%2 excludedOrigin=%3 excludeRadius=%4 iterations=%5", this, randomSphereOrigin, excludeSphereOrigin, excludeRadius, iterationCount), this);
}
return super.FindPosition2D(randomPos, randomSphereOrigin, randomSphereRadius, excludeSphereOrigin, excludeRadius, iterationCount);
}
}
modded class SCR_RecoilCameraShakeParams
{
override protected vector RandomVectorSphere(vector min, vector max, bool uniform = true)
{
if (ERR_NativeRandomRadiusTrace.CanTrace())
{
float inner = min.Length();
float outer = max.Length();
if (inner == 0 && outer == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_RecoilCameraShakeParams", null, inner, outer, string.Format("phase=before-super params=%1 min=%2 max=%3 uniform=%4", this, min, max, uniform));
}
return super.RandomVectorSphere(min, max, uniform);
}
}
#endif
@@ -0,0 +1,19 @@
check: /tmp/err-policy-89ac3_bz/check.cpp:121: void count(int): Assertion `(int)rows.size()==n&&Debug::dumps==n&&ERR_NativeRandomRadiusTrace::s_Count==n' failed.
Traceback (most recent call last):
File "/tmp/erri-random-radius-tests-0504/tests/test_native_random_radius_trace.py", line 28, in <module>
run(r'''
~~~^^^^^
#include <cassert>
^^^^^^^^^^^^^^^^^^
...<68 lines>...
}
^
''')
^^^^
File "/home/jakub/devel/escapistsrereintroduced/tests/policy_harness.py", line 14, in run
subprocess.run([str(p/'check')],check=True)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/subprocess.py", line 578, in run
raise CalledProcessError(retcode, process.args,
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['/tmp/err-policy-89ac3_bz/check']' died with <Signals.SIGABRT: 6>.
@@ -0,0 +1,108 @@
// Explicit Workbench diagnostic only. Preserve every native superclass result,
// output and random draw; this observes zero-radius callers without correcting them.
#ifdef WORKBENCH
class ERR_NativeRandomRadiusTrace
{
protected static bool s_Checked;
protected static bool s_Enabled;
protected static int s_Count;
static bool CanTrace()
{
if (!s_Checked)
{
s_Checked = true;
string value;
s_Enabled = System.GetCLIParam("errTraceRandomRadius", value) && value == "1";
}
return s_Enabled && s_Count < 16;
}
static void Log(string context, AIAgent owner, float inner, float outer, string details, Node node = null)
{
if (!CanTrace()) return;
s_Count++;
string nodeStack;
if (node) node.GetCallstackStr(nodeStack);
PrintFormat("ERR ZERO RADIUS TRACE: sample=%1/16 class=%2 owner=%3 inner=%4 outer=%5 %6 nodeStack=%7", s_Count, context, owner, inner, outer, details, nodeStack);
Debug.DumpStack();
}
}
modded class SCR_AIGetRandomPoint
{
override ENodeResult EOnTaskSimulate(AIAgent owner, float dt)
{
ENodeResult result = super.EOnTaskSimulate(owner, dt);
// The superclass updates these fields from the actual waypoint/input ports.
if (ERR_NativeRandomRadiusTrace.CanTrace() && result == ENodeResult.SUCCESS && m_ExclusionRadius == 0 && m_Radius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AIGetRandomPoint", owner, m_ExclusionRadius, m_Radius, string.Format("phase=after-success node=%1", this), this);
return result;
}
}
modded class SCR_AIGetRandomLookPosition
{
override ENodeResult EOnTaskSimulate(AIAgent owner, float dt)
{
if (ERR_NativeRandomRadiusTrace.CanTrace() && owner)
{
IEntity controlledEntity = owner.GetControlledEntity();
vector inPos;
if (controlledEntity && GetVariableIn(PORT_IN_POS, inPos))
{
float distance = vector.Distance(controlledEntity.GetOrigin(), inPos);
float radius = distance * m_fTangent;
if (radius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AIGetRandomLookPosition", owner, 0, radius, string.Format("phase=before-super node=%1 entity=%2 inPos=%3 distance=%4 tangent=%5", this, controlledEntity, inPos, distance, m_fTangent), this);
}
}
return super.EOnTaskSimulate(owner, dt);
}
}
modded class SCR_AICalculateNextCombatMovePos
{
override protected vector RandomizeDestinationPos(float distance, vector centerPos)
{
if (ERR_NativeRandomRadiusTrace.CanTrace())
{
float radius = 0.1 * distance;
if (radius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AICalculateNextCombatMovePos", null, 0, radius, string.Format("phase=before-super node=%1 center=%2 distance=%3 scale=0.1", this, centerPos, distance), this);
}
return super.RandomizeDestinationPos(distance, centerPos);
}
}
modded class SCR_AIGetRandomPointWithExclude
{
override protected bool FindPosition2D(out vector randomPos, vector randomSphereOrigin, float randomSphereRadius, vector excludeSphereOrigin = vector.Zero, float excludeRadius = 0, int iterationCount = 50)
{
if (ERR_NativeRandomRadiusTrace.CanTrace())
{
if (randomSphereOrigin == excludeSphereOrigin || excludeRadius < 1.0e-8)
{
if (excludeRadius == 0 && randomSphereRadius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AIGetRandomPointWithExclude", null, excludeRadius, randomSphereRadius, string.Format("phase=before-super branch=direct node=%1 origin=%2 excludedOrigin=%3 excludeRadius=%4 iterations=%5", this, randomSphereOrigin, excludeSphereOrigin, excludeRadius, iterationCount), this);
}
else if (randomSphereRadius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AIGetRandomPointWithExclude", null, 0, randomSphereRadius, string.Format("phase=before-super branch=iterative node=%1 origin=%2 excludedOrigin=%3 excludeRadius=%4 iterations=%5", this, randomSphereOrigin, excludeSphereOrigin, excludeRadius, iterationCount), this);
}
return super.FindPosition2D(randomPos, randomSphereOrigin, randomSphereRadius, excludeSphereOrigin, excludeRadius, iterationCount);
}
}
modded class SCR_RecoilCameraShakeParams
{
override protected vector RandomVectorSphere(vector min, vector max, bool uniform = true)
{
if (ERR_NativeRandomRadiusTrace.CanTrace())
{
float inner = min.Length();
float outer = max.Length();
if (inner == 0 && outer == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_RecoilCameraShakeParams", null, inner, outer, string.Format("phase=before-super params=%1 min=%2 max=%3 uniform=%4", this, min, max, uniform));
}
return super.RandomVectorSphere(min, max, uniform);
}
}
#endif
@@ -0,0 +1,89 @@
/tmp/err-policy-pd_h_loz/check.cpp:36:92: error: ‘Node’ has not been declared
36 | static void Log(string context, AIAgent* owner, float inner, float outer, string details, Node node = nullptr)
| ^~~~
/tmp/err-policy-pd_h_loz/check.cpp:36:104: error: could not convert ‘nullptr’ from ‘std::nullptr_t’ to ‘int’
36 | static void Log(string context, AIAgent* owner, float inner, float outer, string details, Node node = nullptr)
| ^~~~~~~
| |
| std::nullptr_t
/tmp/err-policy-pd_h_loz/check.cpp: In static member function ‘static void ERR_NativeRandomRadiusTrace::Log(string, AIAgent*, float, float, string, int)’:
/tmp/err-policy-pd_h_loz/check.cpp:41:18: error: request for member ‘GetCallstackStr’ in ‘node’, which is of non-class type ‘int’
41 | if (node) node.GetCallstackStr(nodeStack);
| ^~~~~~~~~~~~~~~
/tmp/err-policy-pd_h_loz/check.cpp:42:14: error: too many arguments to function ‘void PrintFormat(const char*, int, string, AIAgent*, float, float, string)’
42 | PrintFormat("ERR ZERO RADIUS TRACE: sample=%1/16 class=%2 owner=%3 inner=%4 outer=%5 %6 nodeStack=%7", s_Count, context, owner, inner, outer, details, nodeStack);
| ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/tmp/err-policy-pd_h_loz/check.cpp:14:6: note: declared here
14 | void PrintFormat(const char*,int count,string context,AIAgent*owner,float inner,float outer,string details){rows.push_back({count,context,owner,inner,outer,details});}
| ^~~~~~~~~~~
/tmp/err-policy-pd_h_loz/check.cpp: In member function ‘ENodeResult SCR_AIGetRandomPoint::EOnTaskSimulate(AIAgent*, float)’:
/tmp/err-policy-pd_h_loz/check.cpp:52:150: error: invalid conversion from ‘SCR_AIGetRandomPoint*’ to ‘int’ [-fpermissive]
52 | ERR_NativeRandomRadiusTrace::Log("SCR_AIGetRandomPoint", owner, m_ExclusionRadius, m_Radius, string::Format("phase=after-success node=%1", this), this);
| ^~~~
| |
| SCR_AIGetRandomPoint*
/tmp/err-policy-pd_h_loz/check.cpp:36:97: note: initializing argument 6 of ‘static void ERR_NativeRandomRadiusTrace::Log(string, AIAgent*, float, float, string, int)’
36 | static void Log(string context, AIAgent* owner, float inner, float outer, string details, Node node = nullptr)
| ~~~~~^~~~~~~~~~~~~~
/tmp/err-policy-pd_h_loz/check.cpp: In member function ‘ENodeResult SCR_AIGetRandomLookPosition::EOnTaskSimulate(AIAgent*, float)’:
/tmp/err-policy-pd_h_loz/check.cpp:69:229: error: invalid conversion from ‘SCR_AIGetRandomLookPosition*’ to ‘int’ [-fpermissive]
69 | ERR_NativeRandomRadiusTrace::Log("SCR_AIGetRandomLookPosition", owner, 0, radius, string::Format("phase=before-super node=%1 entity=%2 inPos=%3 distance=%4 tangent=%5", this, controlledEntity, inPos, distance, m_fTangent), this);
| ^~~~
| |
| SCR_AIGetRandomLookPosition*
/tmp/err-policy-pd_h_loz/check.cpp:36:97: note: initializing argument 6 of ‘static void ERR_NativeRandomRadiusTrace::Log(string, AIAgent*, float, float, string, int)’
36 | static void Log(string context, AIAgent* owner, float inner, float outer, string details, Node node = nullptr)
| ~~~~~^~~~~~~~~~~~~~
/tmp/err-policy-pd_h_loz/check.cpp: In member function ‘vector SCR_AICalculateNextCombatMovePos::RandomizeDestinationPos(float, vector)’:
/tmp/err-policy-pd_h_loz/check.cpp:83:199: error: invalid conversion from ‘SCR_AICalculateNextCombatMovePos*’ to ‘int’ [-fpermissive]
83 | ERR_NativeRandomRadiusTrace::Log("SCR_AICalculateNextCombatMovePos", nullptr, 0, radius, string::Format("phase=before-super node=%1 center=%2 distance=%3 scale=0.1", this, centerPos, distance), this);
| ^~~~
| |
| SCR_AICalculateNextCombatMovePos*
/tmp/err-policy-pd_h_loz/check.cpp:36:97: note: initializing argument 6 of ‘static void ERR_NativeRandomRadiusTrace::Log(string, AIAgent*, float, float, string, int)’
36 | static void Log(string context, AIAgent* owner, float inner, float outer, string details, Node node = nullptr)
| ~~~~~^~~~~~~~~~~~~~
/tmp/err-policy-pd_h_loz/check.cpp: In member function ‘bool SCR_AIGetRandomPointWithExclude::FindPosition2D(vector&, vector, float, vector, float, int)’:
/tmp/err-policy-pd_h_loz/check.cpp:97:315: error: invalid conversion from ‘SCR_AIGetRandomPointWithExclude*’ to ‘int’ [-fpermissive]
97 | ERR_NativeRandomRadiusTrace::Log("SCR_AIGetRandomPointWithExclude", nullptr, excludeRadius, randomSphereRadius, string::Format("phase=before-super branch=direct node=%1 origin=%2 excludedOrigin=%3 excludeRadius=%4 iterations=%5", this, randomSphereOrigin, excludeSphereOrigin, excludeRadius, iterationCount), this);
| ^~~~
| |
| SCR_AIGetRandomPointWithExclude*
/tmp/err-policy-pd_h_loz/check.cpp:36:97: note: initializing argument 6 of ‘static void ERR_NativeRandomRadiusTrace::Log(string, AIAgent*, float, float, string, int)’
36 | static void Log(string context, AIAgent* owner, float inner, float outer, string details, Node node = nullptr)
| ~~~~~^~~~~~~~~~~~~~
/tmp/err-policy-pd_h_loz/check.cpp:100:305: error: invalid conversion from ‘SCR_AIGetRandomPointWithExclude*’ to ‘int’ [-fpermissive]
100 | ERR_NativeRandomRadiusTrace::Log("SCR_AIGetRandomPointWithExclude", nullptr, 0, randomSphereRadius, string::Format("phase=before-super branch=iterative node=%1 origin=%2 excludedOrigin=%3 excludeRadius=%4 iterations=%5", this, randomSphereOrigin, excludeSphereOrigin, excludeRadius, iterationCount), this);
| ^~~~
| |
| SCR_AIGetRandomPointWithExclude*
/tmp/err-policy-pd_h_loz/check.cpp:36:97: note: initializing argument 6 of ‘static void ERR_NativeRandomRadiusTrace::Log(string, AIAgent*, float, float, string, int)’
36 | static void Log(string context, AIAgent* owner, float inner, float outer, string details, Node node = nullptr)
| ~~~~~^~~~~~~~~~~~~~
/tmp/err-policy-pd_h_loz/check.cpp: In member function ‘vector SCR_RecoilCameraShakeParams::RandomVectorSphere(vector, vector, bool)’:
/tmp/err-policy-pd_h_loz/check.cpp:114:37: error: cannot convert ‘std::nullptr_t’ to ‘int’
114 | ERR_NativeRandomRadiusTrace::Log("SCR_RecoilCameraShakeParams", nullptr, inner, outer, string::Format("phase=before-super params=%1 min=%2 max=%3 uniform=%4", this, min, max, uniform));
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| std::nullptr_t
/tmp/err-policy-pd_h_loz/check.cpp:36:97: note: initializing argument 6 of ‘static void ERR_NativeRandomRadiusTrace::Log(string, AIAgent*, float, float, string, int)’
36 | static void Log(string context, AIAgent* owner, float inner, float outer, string details, Node node = nullptr)
| ~~~~~^~~~~~~~~~~~~~
Traceback (most recent call last):
File "/tmp/erri-random-radius-tests-0504/tests/test_native_random_radius_trace.py", line 28, in <module>
run(r'''
~~~^^^^^
#include <cassert>
^^^^^^^^^^^^^^^^^^
...<67 lines>...
}
^
''')
^^^^
File "/home/jakub/devel/escapistsrereintroduced/tests/policy_harness.py", line 13, in run
subprocess.run(['g++','-std=c++17','-Wall','-Werror',str(p/'check.cpp'),'-o',str(p/'check')],check=True)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/subprocess.py", line 578, in run
raise CalledProcessError(retcode, process.args,
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['g++', '-std=c++17', '-Wall', '-Werror', '/tmp/err-policy-pd_h_loz/check.cpp', '-o', '/tmp/err-policy-pd_h_loz/check']' returned non-zero exit status 1.
@@ -0,0 +1,103 @@
--- /dev/null
+++ b/tests/test_native_random_radius_trace.py
@@ -0,0 +1,100 @@
+"""Execute opt-in diagnostic helper/wrappers with transparent native superclass doubles."""
+import os,re
+from pathlib import Path
+from policy_harness import ROOT,body,run
+p=Path(os.environ.get('ERR_NATIVE_RANDOM_RADIUS_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeRandomRadiusTrace.c'))
+source=p.read_text()
+assert '#ifdef WORKBENCH' in source and source.rstrip().endswith('#endif')
+# The diagnosis must not repair/clamp/reroll values or bypass native execution.
+for token in ('Math.Clamp','GenerateRandomPointInRadius(', 'SetVariableOut(', 'SetOrigin(', 'CallLater(', 'Math.Random'):
+ assert token not in source,token
+
+def adapt(s):
+ s=s.replace('override ','').replace('protected ','').replace('out vector','vector&')
+ s=s.replace('AIAgent owner','AIAgent* owner').replace('IEntity controlledEntity','Entity* controlledEntity')
+ for name in ('owner','controlledEntity'):s=s.replace(name+'.',name+'->')
+ for name in ('ERR_NativeRandomRadiusTrace','ENodeResult','System','Debug','string','vector'):s=s.replace(name+'.',name+'::')
+ s=s.replace('null','nullptr').replace('Node node','Node* node').replace('node.','node->')
+ s=re.sub(r'\b(bool|int|float) (\w+);',r'\1 \2{};',s)
+ return s
+helper=adapt(body(p,'class ERR_NativeRandomRadiusTrace')).replace('class ERR_','struct ERR_').replace('static bool s_','static inline bool s_').replace('static int s_','static inline int s_')+';'
+classes={'SCR_AIGetRandomPoint':'PointBase','SCR_AIGetRandomLookPosition':'LookBase','SCR_AICalculateNextCombatMovePos':'CombatBase','SCR_AIGetRandomPointWithExclude':'ExcludeBase','SCR_RecoilCameraShakeParams':'RecoilBase'}
+wrappers=[]
+for cls,base in classes.items():
+ raw=body(p,'modded class '+cls)
+ assert raw.count('super.')==1,(cls,'must call superclass exactly once')
+ code=adapt(raw).replace('modded class '+cls,'struct '+cls+' : '+base).replace('super.',base+'::')+';'
+ wrappers.append(code)
+run(r'''
+#include <cassert>
+#include <cmath>
+#include <string>
+#include <vector>
+struct string:std::string{using std::string::string;template<class...T>static string Format(const char*s,T...){return s;}};
+struct vector{float x=0,y=0,z=0;vector()=default;vector(float a,float b,float c):x(a),y(b),z(c){}bool operator==(vector b)const{return x==b.x&&y==b.y&&z==b.z;}static float Distance(vector a,vector b){return std::sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));}float Length()const{return Distance(*this,{});}static const vector Zero;};const vector vector::Zero{};
+struct Entity{vector position;int reads=0;vector GetOrigin(){reads++;return position;}};
+struct AIAgent{Entity*entity=nullptr;int reads=0;Entity*GetControlledEntity(){reads++;return entity;}};
+enum class ENodeResult{FAIL,SUCCESS,RUNNING};
+struct System{static inline bool present=false;static inline string value="";static inline int reads=0;static bool GetCLIParam(const char*,string&v){reads++;v=value;return present;}};
+struct Debug{static inline int dumps=0;static void DumpStack(){dumps++;}};
+struct Row{int count;string context;AIAgent*owner;float inner,outer;string details,stack;};std::vector<Row> rows;
+void PrintFormat(const char*,int count,string context,AIAgent*owner,float inner,float outer,string details,string stack){rows.push_back({count,context,owner,inner,outer,details,stack});}
+struct Node{int stackReads=0;void GetCallstackStr(string&out){stackReads++;out="native-tree-context";}};
+struct SimBase:Node{int supers=0;AIAgent*lastOwner=nullptr;float lastDt=-1;ENodeResult next=ENodeResult::SUCCESS;vector output{19,23,29};void called(AIAgent*o,float dt){supers++;lastOwner=o;lastDt=dt;output={31,37,41};}};
+struct PointBase:SimBase{float m_ExclusionRadius=7,m_Radius=9,innerAfter=0,outerAfter=0;ENodeResult EOnTaskSimulate(AIAgent*o,float dt){called(o,dt);m_ExclusionRadius=innerAfter;m_Radius=outerAfter;return next;}};
+struct LookBase:SimBase{float m_fTangent=.5;static inline string PORT_IN_POS="InPos";bool hasInput=true;vector input;int inputReads=0;bool GetVariableIn(string,vector&v){inputReads++;v=input;return hasInput;}ENodeResult EOnTaskSimulate(AIAgent*o,float dt){called(o,dt);return next;}};
+struct CombatBase:Node{int supers=0;float lastDistance=-1;vector lastCenter,output{43,47,53};vector RandomizeDestinationPos(float distance,vector centerPos){supers++;lastDistance=distance;lastCenter=centerPos;return output;}};
+struct ExcludeBase:Node{int supers=0;bool result=true;vector output{59,61,67},lastInput,lastOrigin,lastExclude;float lastRadius=-1,lastExcludeRadius=-1;int lastIterations=-1;bool FindPosition2D(vector&randomPos,vector randomSphereOrigin,float randomSphereRadius,vector excludeSphereOrigin=vector::Zero,float excludeRadius=0,int iterationCount=50){supers++;lastInput=randomPos;lastOrigin=randomSphereOrigin;lastRadius=randomSphereRadius;lastExclude=excludeSphereOrigin;lastExcludeRadius=excludeRadius;lastIterations=iterationCount;randomPos=output;return result;}};
+struct RecoilBase{int supers=0;vector lastMin,lastMax,output{71,73,79};bool lastUniform=false;vector RandomVectorSphere(vector min,vector max,bool uniform=true){supers++;lastMin=min;lastMax=max;lastUniform=uniform;return output;}};
+'''+helper+'\n'.join(wrappers)+r'''
+void reset(bool enabled){ERR_NativeRandomRadiusTrace::s_Checked=false;ERR_NativeRandomRadiusTrace::s_Enabled=false;ERR_NativeRandomRadiusTrace::s_Count=0;System::present=enabled;System::value=enabled?"1":"";System::reads=0;Debug::dumps=0;rows.clear();}
+void count(int n){assert((int)rows.size()==n&&Debug::dumps==n&&ERR_NativeRandomRadiusTrace::s_Count==n);}
+int main(){
+ Entity actor;AIAgent owner;owner.entity=&actor;
+ // Disabled diagnostics are transparent even when every radius is zero.
+ reset(false);SCR_AIGetRandomPoint point;SCR_AIGetRandomLookPosition look;SCR_AICalculateNextCombatMovePos combat;SCR_AIGetRandomPointWithExclude exclude;SCR_RecoilCameraShakeParams recoil;vector pos{1,2,3},center{4,5,6};
+ assert(point.EOnTaskSimulate(&owner,.25)==ENodeResult::SUCCESS&&point.supers==1&&point.output==vector(31,37,41));
+ assert(look.EOnTaskSimulate(&owner,.5)==ENodeResult::SUCCESS&&look.supers==1&&look.output==vector(31,37,41));
+ assert(!owner.reads&&!actor.reads&&!look.inputReads);
+ assert(combat.RandomizeDestinationPos(0,center)==combat.output&&combat.supers==1&&combat.lastCenter==center&&combat.lastDistance==0);
+ assert(exclude.FindPosition2D(pos,center,0,center,0,0)&&pos==exclude.output&&exclude.supers==1&&exclude.lastInput==vector(1,2,3));
+ assert(recoil.RandomVectorSphere({}, {},false)==recoil.output&&recoil.supers==1&&!recoil.lastUniform);count(0);assert(System::reads==1&&!point.stackReads&&!look.stackReads&&!combat.stackReads&&!exclude.stackReads);
+ System::present=true;System::value="1";point.EOnTaskSimulate(&owner,1);count(0);assert(System::reads==1); // cached disabled flag
+ for(const char*flag:{"0","true","","2"}){reset(true);System::value=flag;assert(!ERR_NativeRandomRadiusTrace::CanTrace());count(0);}
+ // Point uses actual post-super fields, only on success, with exact owner/result.
+ reset(true);point.innerAfter=point.outerAfter=0;point.next=ENodeResult::FAIL;int calls=point.supers;assert(point.EOnTaskSimulate(&owner,.75)==ENodeResult::FAIL&&point.supers==calls+1);count(0);
+ point.next=ENodeResult::RUNNING;assert(point.EOnTaskSimulate(&owner,.8)==ENodeResult::RUNNING);count(0);
+ point.next=ENodeResult::SUCCESS;point.m_Radius=10;point.m_ExclusionRadius=2;assert(point.EOnTaskSimulate(&owner,.9)==ENodeResult::SUCCESS);count(1);assert(point.stackReads==1&&rows.back().stack=="native-tree-context");assert(rows.back().owner==&owner&&point.lastOwner==&owner&&point.lastDt==.9f);
+ point.outerAfter=.001;point.EOnTaskSimulate(&owner,1);count(1);point.outerAfter=0;point.innerAfter=.001;point.EOnTaskSimulate(&owner,1);count(1);
+ // Look observes only native-valid controlled entity/input, preserves failures.
+ reset(true);owner.reads=actor.reads=0;look.inputReads=0;actor.position={1,2,3};look.input=actor.position;look.next=ENodeResult::RUNNING;calls=look.supers;
+ assert(look.EOnTaskSimulate(&owner,1)==ENodeResult::RUNNING&&look.supers==calls+1);count(1);assert(owner.reads==1&&actor.reads==1&&look.inputReads==1);
+ look.input={2,2,3};look.EOnTaskSimulate(&owner,1);count(1);look.m_fTangent=0;look.EOnTaskSimulate(&owner,1);count(2);
+ look.hasInput=false;look.next=ENodeResult::FAIL;assert(look.EOnTaskSimulate(&owner,1)==ENodeResult::FAIL);count(2);look.hasInput=true;owner.entity=nullptr;look.EOnTaskSimulate(&owner,1);count(2);owner.entity=&actor;
+ // Combat calls native randomization once with unmodified arguments/result.
+ reset(true);calls=combat.supers;assert(combat.RandomizeDestinationPos(0,center)==combat.output&&combat.supers==calls+1);count(1);
+ assert(combat.RandomizeDestinationPos(1,center)==combat.output&&combat.lastDistance==1);count(1);combat.RandomizeDestinationPos(-1,center);count(1);
+ // Exclusion native branch: same centers uses exclusion radius even at0iterations;
+ // different centers withpositiveexclusion loops only wheniterations>0.
+ reset(true);pos={8,9,10};calls=exclude.supers;exclude.result=false;
+ assert(!exclude.FindPosition2D(pos,center,0,center,0,0)&&exclude.supers==calls+1&&pos==exclude.output&&exclude.lastInput==vector(8,9,10));count(1);
+ exclude.FindPosition2D(pos,center,0,center,1,50);count(1);
+ vector different{11,12,13};exclude.FindPosition2D(pos,center,0,different,1,0);count(1);
+ exclude.FindPosition2D(pos,center,0,different,1,-1);count(1);
+ exclude.FindPosition2D(pos,center,0,different,1,1);count(2);
+ exclude.FindPosition2D(pos,center,0,different,0,0);count(3);
+ exclude.FindPosition2D(pos,center,.001,different,0,1);count(3);
+ exclude.FindPosition2D(pos,center,0,different,1.e-9f,0);count(3); // native inner is tiny positive, notzero
+ assert(exclude.lastOrigin==center&&exclude.lastExclude==different&&exclude.lastRadius==0&&exclude.lastExcludeRadius==1.e-9f&&exclude.lastIterations==0);
+ // Recoil values, uniform flag, result and one native draw remain untouched.
+ reset(true);calls=recoil.supers;assert(recoil.RandomVectorSphere({},{},false)==recoil.output&&recoil.supers==calls+1&&!recoil.lastUniform);count(1);assert(rows.back().stack.empty());
+ recoil.RandomVectorSphere({.001,0,0},{},true);count(1);recoil.RandomVectorSphere({},{0,0,.001},true);count(1);assert(recoil.lastMin==vector::Zero&&recoil.lastMax==vector(0,0,.001)&&recoil.lastUniform);
+ // Shared cap includes allwrappers and prevents further observational inputreads.
+ reset(true);for(int i=0;i<20;i++)combat.RandomizeDestinationPos(0,center);count(16);for(int i=0;i<16;i++)assert(rows[i].count==i+1);assert(System::reads==1);
+ int ownerReads=owner.reads,positionReads=actor.reads,inputReads=look.inputReads;calls=look.supers;look.EOnTaskSimulate(&owner,1);assert(look.supers==calls+1&&owner.reads==ownerReads&&actor.reads==positionReads&&look.inputReads==inputReads);count(16);
+ point.innerAfter=point.outerAfter=0;point.next=ENodeResult::SUCCESS;calls=point.supers;point.EOnTaskSimulate(&owner,1);assert(point.supers==calls+1);count(16);
+ calls=exclude.supers;exclude.FindPosition2D(pos,center,0,center,0,0);assert(exclude.supers==calls+1&&pos==exclude.output);count(16);
+ calls=recoil.supers;recoil.RandomVectorSphere({},{});assert(recoil.supers==calls+1);count(16);
+}
+''')
+print('PASS: actual five random-radius diagnostic wrappers, disabled transparency, cached opt-in, exact zero and exclusion branch, native arguments/returns/outarg preservation, single superclass call and shared16-log cap')
@@ -0,0 +1 @@
PASS: actual five random-radius diagnostic wrappers, disabled transparency, cached opt-in, exact zero and exclusion branch, native arguments/returns/outarg preservation, single superclass call and shared16-log cap
@@ -0,0 +1,19 @@
check: /tmp/err-policy-7rfkwvwo/check.cpp:131: int main(): Assertion `recoil.RandomVectorSphere({}, {},false)==recoil.output&&recoil.supers==1&&!recoil.lastUniform' failed.
Traceback (most recent call last):
File "/tmp/erri-random-radius-tests-0504/tests/test_native_random_radius_trace.py", line 28, in <module>
run(r'''
~~~^^^^^
#include <cassert>
^^^^^^^^^^^^^^^^^^
...<68 lines>...
}
^
''')
^^^^
File "/home/jakub/devel/escapistsrereintroduced/tests/policy_harness.py", line 14, in run
subprocess.run([str(p/'check')],check=True)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/subprocess.py", line 578, in run
raise CalledProcessError(retcode, process.args,
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['/tmp/err-policy-7rfkwvwo/check']' died with <Signals.SIGABRT: 6>.
@@ -0,0 +1,108 @@
// Explicit Workbench diagnostic only. Preserve every native superclass result,
// output and random draw; this observes zero-radius callers without correcting them.
#ifdef WORKBENCH
class ERR_NativeRandomRadiusTrace
{
protected static bool s_Checked;
protected static bool s_Enabled;
protected static int s_Count;
static bool CanTrace()
{
if (!s_Checked)
{
s_Checked = true;
string value;
s_Enabled = System.GetCLIParam("errTraceRandomRadius", value) && value == "1";
}
return s_Enabled && s_Count < 16;
}
static void Log(string context, AIAgent owner, float inner, float outer, string details, Node node = null)
{
if (!CanTrace()) return;
s_Count++;
string nodeStack;
if (node) node.GetCallstackStr(nodeStack);
PrintFormat("ERR ZERO RADIUS TRACE: sample=%1/16 class=%2 owner=%3 inner=%4 outer=%5 %6 nodeStack=%7", s_Count, context, owner, inner, outer, details, nodeStack);
Debug.DumpStack();
}
}
modded class SCR_AIGetRandomPoint
{
override ENodeResult EOnTaskSimulate(AIAgent owner, float dt)
{
ENodeResult result = super.EOnTaskSimulate(owner, dt);
// The superclass updates these fields from the actual waypoint/input ports.
if (ERR_NativeRandomRadiusTrace.CanTrace() && result == ENodeResult.SUCCESS && m_ExclusionRadius == 0 && m_Radius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AIGetRandomPoint", owner, m_ExclusionRadius, m_Radius, string.Format("phase=after-success node=%1", this), this);
return result;
}
}
modded class SCR_AIGetRandomLookPosition
{
override ENodeResult EOnTaskSimulate(AIAgent owner, float dt)
{
if (ERR_NativeRandomRadiusTrace.CanTrace() && owner)
{
IEntity controlledEntity = owner.GetControlledEntity();
vector inPos;
if (controlledEntity && GetVariableIn(PORT_IN_POS, inPos))
{
float distance = vector.Distance(controlledEntity.GetOrigin(), inPos);
float radius = distance * m_fTangent;
if (radius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AIGetRandomLookPosition", owner, 0, radius, string.Format("phase=before-super node=%1 entity=%2 inPos=%3 distance=%4 tangent=%5", this, controlledEntity, inPos, distance, m_fTangent), this);
}
}
return super.EOnTaskSimulate(owner, dt);
}
}
modded class SCR_AICalculateNextCombatMovePos
{
override protected vector RandomizeDestinationPos(float distance, vector centerPos)
{
if (ERR_NativeRandomRadiusTrace.CanTrace())
{
float radius = 0.1 * distance;
if (radius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AICalculateNextCombatMovePos", null, 0, radius, string.Format("phase=before-super node=%1 center=%2 distance=%3 scale=0.1", this, centerPos, distance), this);
}
return super.RandomizeDestinationPos(distance, centerPos);
}
}
modded class SCR_AIGetRandomPointWithExclude
{
override protected bool FindPosition2D(out vector randomPos, vector randomSphereOrigin, float randomSphereRadius, vector excludeSphereOrigin = vector.Zero, float excludeRadius = 0, int iterationCount = 50)
{
if (ERR_NativeRandomRadiusTrace.CanTrace())
{
if (randomSphereOrigin == excludeSphereOrigin || excludeRadius < 1.0e-8)
{
if (excludeRadius == 0 && randomSphereRadius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AIGetRandomPointWithExclude", null, excludeRadius, randomSphereRadius, string.Format("phase=before-super branch=direct node=%1 origin=%2 excludedOrigin=%3 excludeRadius=%4 iterations=%5", this, randomSphereOrigin, excludeSphereOrigin, excludeRadius, iterationCount), this);
}
else if (iterationCount > 0 && randomSphereRadius == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_AIGetRandomPointWithExclude", null, 0, randomSphereRadius, string.Format("phase=before-super branch=iterative node=%1 origin=%2 excludedOrigin=%3 excludeRadius=%4 iterations=%5", this, randomSphereOrigin, excludeSphereOrigin, excludeRadius, iterationCount), this);
}
return super.FindPosition2D(randomPos, randomSphereOrigin, randomSphereRadius, excludeSphereOrigin, excludeRadius, iterationCount);
}
}
modded class SCR_RecoilCameraShakeParams
{
override protected vector RandomVectorSphere(vector min, vector max, bool uniform = true)
{
if (ERR_NativeRandomRadiusTrace.CanTrace())
{
float inner = min.Length();
float outer = max.Length();
if (inner == 0 && outer == 0)
ERR_NativeRandomRadiusTrace.Log("SCR_RecoilCameraShakeParams", null, inner, outer, string.Format("phase=before-super params=%1 min=%2 max=%3 uniform=%4", this, min, max, uniform));
}
return super.RandomVectorSphere(min, max, !uniform);
}
}
#endif
@@ -0,0 +1,40 @@
{
"complete": true,
"verdict": "Five actual wrappers/helper pass transparency and bounded diagnostic contract; no source blocker found.",
"source_sha256": "7e946406067092e30b6b75cc6ef0c56db7f866249e02bd13648156933ee578d9",
"test_sha256": "a87f553de26a32b5f242c2cc8ea31564eb54d29f1d0cab7018c1c408888b8101",
"patch_sha256": "7ba3322faf9445e907721cbf38bd3167fbb6b333b2b4a2953c51cfb69ca5e11f",
"green_log_sha256": "3f1e3b861d5acafc5cad948ed85c785ab68f72d51fc6b20a55fce26183155bab",
"mutations": {
"disabled-gate": {
"exit": 1,
"compiled_then_runtime_assertion_failed": true,
"log_sha256": "67196a43c889beac1b7b70eadd4557141c5d712b98e181a6631794cc3150a54f"
},
"exclusion-branch": {
"exit": 1,
"compiled_then_runtime_assertion_failed": true,
"log_sha256": "8759e415a3993f7e9c6d65bc7ae4fe3c2fb3656e6908a0c677d50bef0294c229"
},
"recoil-uniform": {
"exit": 1,
"compiled_then_runtime_assertion_failed": true,
"log_sha256": "6877cddcd00e549b8e0ec514e6aa49e4fc366b771473582e461182f5c5abbd2d"
}
},
"actual_methods": "Complete helper and all five modded wrapper method bodies extracted from supplied source. Native superclass methods and API boundaries are doubles.",
"coverage": [
"CLI opt-in cached once; missing/0/true/empty/2 disabled. Disabled and cap-exhausted paths perform no extra actor/input/node-stack reads.",
"Point uses fields after its exact single superclass invocation and logs only SUCCESS with both zero; return/output preserved across SUCCESS/FAIL/RUNNING.",
"Look uses controlled body and input and logs exactly distance*tangent==0, without altering native result/output or arguments.",
"Combat uses0.1*distance diagnostic but forwards exact distance/center/result.",
"WithExclude exact direct versus iterative branching,0/negative iteration loop skips,nonzero tiny exclusion direct radius,unchanged outarg and return on failure.",
"Recoil forwards exact min/max/uniform and result; only two zero vector lengths log; no fabricated node owner.",
"All wrappers call superclass exactly once, shared16 witnesses/stack dumps, node stack captured only on actual permitted AI witness."
],
"limits": [
"Offline syntax-adapted wrapper execution only; installed native superclass/RNG behavior, engine hook compatibility and caller attribution require parent-owned diagnostic native run.",
"No native error suppressed, no radius clamp, no extra RNG draw, no proof yet of which caller produced prior zero-radius error."
],
"command": "PYTHONPATH=/home/jakub/devel/escapistsrereintroduced/tests ERR_NATIVE_RANDOM_RADIUS_SOURCE=/tmp/erri-random-radius-source-0504/addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeRandomRadiusTrace.c python3 /tmp/erri-random-radius-tests-0504/tests/test_native_random_radius_trace.py"
}
@@ -0,0 +1,12 @@
from pathlib import Path
import os,subprocess,json,hashlib,difflib
b=Path('/tmp/erri-random-radius-tests-0504');src=Path('/tmp/erri-random-radius-source-0504/addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeRandomRadiusTrace.c');test=b/'tests/test_native_random_radius_trace.py';text=src.read_text();sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest();env=dict(os.environ,PYTHONPATH='/home/jakub/devel/escapistsrereintroduced/tests');results={}
mutations={'disabled-gate':('return s_Enabled && s_Count < 16;','return s_Count < 16;'),'exclusion-branch':('else if (iterationCount > 0 && randomSphereRadius == 0)','else if (randomSphereRadius == 0)'),'recoil-uniform':('return super.RandomVectorSphere(min, max, uniform);','return super.RandomVectorSphere(min, max, !uniform);')}
for name,(old,new) in mutations.items():
assert text.count(old)==1;file=b/(name+'.c');file.write_text(text.replace(old,new));env['ERR_NATIVE_RANDOM_RADIUS_SOURCE']=str(file);r=subprocess.run(['python3',str(test)],env=env,capture_output=True,text=True);log=r.stdout+r.stderr;(b/(name+'-red.log')).write_text(log)
assert r.returncode!=0 and 'Assertion' in log and 'died with' in log and "['g++'" not in log,(name,log)
results[name]={'exit':r.returncode,'compiled_then_runtime_assertion_failed':True,'log_sha256':sha(b/(name+'-red.log'))}
env['ERR_NATIVE_RANDOM_RADIUS_SOURCE']=str(src);r=subprocess.run(['python3',str(test)],env=env,capture_output=True,text=True);(b/'green.log').write_text(r.stdout+r.stderr);assert r.returncode==0,r.stderr
(b/'fix.patch').write_text(''.join(difflib.unified_diff([],test.read_text().splitlines(True),fromfile='/dev/null',tofile='b/tests/test_native_random_radius_trace.py')))
v={'complete':True,'verdict':'Five actual wrappers/helper pass transparency and bounded diagnostic contract; no source blocker found.','source_sha256':sha(src),'test_sha256':sha(test),'patch_sha256':sha(b/'fix.patch'),'green_log_sha256':sha(b/'green.log'),'mutations':results,'actual_methods':'Complete helper and all five modded wrapper method bodies extracted from supplied source. Native superclass methods and API boundaries are doubles.','coverage':['CLI opt-in cached once; missing/0/true/empty/2 disabled. Disabled and cap-exhausted paths perform no extra actor/input/node-stack reads.','Point uses fields after its exact single superclass invocation and logs only SUCCESS with both zero; return/output preserved across SUCCESS/FAIL/RUNNING.','Look uses controlled body and input and logs exactly distance*tangent==0, without altering native result/output or arguments.','Combat uses0.1*distance diagnostic but forwards exact distance/center/result.','WithExclude exact direct versus iterative branching,0/negative iteration loop skips,nonzero tiny exclusion direct radius,unchanged outarg and return on failure.','Recoil forwards exact min/max/uniform and result; only two zero vector lengths log; no fabricated node owner.','All wrappers call superclass exactly once, shared16 witnesses/stack dumps, node stack captured only on actual permitted AI witness.'],'limits':['Offline syntax-adapted wrapper execution only; installed native superclass/RNG behavior, engine hook compatibility and caller attribution require parent-owned diagnostic native run.','No native error suppressed, no radius clamp, no extra RNG draw, no proof yet of which caller produced prior zero-radius error.'],'command':'PYTHONPATH=/home/jakub/devel/escapistsrereintroduced/tests ERR_NATIVE_RANDOM_RADIUS_SOURCE='+str(src)+' python3 '+str(test)}
(b/'review.json').write_text(json.dumps(v,indent=2)+'\n');print(json.dumps({'source_sha256':sha(src),'test_sha256':sha(test),'patch_sha256':sha(b/'fix.patch'),'review_sha256':sha(b/'review.json')},indent=2))