pub async fn screen(
hits: Vec<Hit>,
text: &str,
review_branch: Option<&str>,
judge: &(dyn Fn(String, Vec<Hit>) -> JudgeFuture + Sync),
) -> Result<Screened, Duplicate>Expand description
The one decision point every caller shares. hits is check’s output:
empty passes without the judge being asked. Otherwise the judge is asked
once (a long text is squeezed to its head and tail first), and only a duplicate: true answer refuses (with its reason).
Fail mode: open. If the judge cannot answer (agent error, timeout,
quota, unparseable reply, no readable config) the work is let through as Screened::Unjudged and a
tracing::warn is logged; callers also say so on stderr. A mechanical
match cannot tell “continue from PR #28” from a real duplicate, so refusing
whenever the judge is away would bring back exactly the false positives the
judge exists to remove. The cost is that a real duplicate slips through
while no agent is available, which is why it is never silent.
For a review-only request text is empty, so review_branch is put in
front of the judge as the thing the work is about.