The evidence reducer solves concurrent writes, but operator.add also keeps earlier evidence when a rejected review returns to the planner. After a retry, the synthesizer may see results from two different plans without knowing which search produced each item.
I would attach a plan or attempt identifier to evidence and make the merge step's reuse policy explicit: keep prior evidence deliberately, or synthesize only from the current attempt. A fixture where the second plan changes the service being investigated would expose accidental carryover. Bounded retries then constrain execution while the evidence contract constrains what each attempt can conclude.
The evidence reducer solves concurrent writes, but operator.add also keeps earlier evidence when a rejected review returns to the planner. After a retry, the synthesizer may see results from two different plans without knowing which search produced each item.
I would attach a plan or attempt identifier to evidence and make the merge step's reuse policy explicit: keep prior evidence deliberately, or synthesize only from the current attempt. A fixture where the second plan changes the service being investigated would expose accidental carryover. Bounded retries then constrain execution while the evidence contract constrains what each attempt can conclude.