Judge → maybe-report. Serialized on ctx["lock"] so two simultaneous arrivals don't both claim NEW for the same root cause. Report dispatch happens outside the lock (the slow part).
(
run_idx: int,
target: TargetConfig,
model: str,
agent_env: dict[str, str],
crash: CrashArtifact,
grade_status: str,
grade_score: float,
ctx: dict,
)
| 379 | |
| 380 | |
| 381 | async def _stream_dispatch( |
| 382 | run_idx: int, |
| 383 | target: TargetConfig, |
| 384 | model: str, |
| 385 | agent_env: dict[str, str], |
| 386 | crash: CrashArtifact, |
| 387 | grade_status: str, |
| 388 | grade_score: float, |
| 389 | ctx: dict, |
| 390 | ) -> None: |
| 391 | """Judge → maybe-report. Serialized on ctx["lock"] so two simultaneous |
| 392 | arrivals don't both claim NEW for the same root cause. Report dispatch |
| 393 | happens outside the lock (the slow part).""" |
| 394 | reports_root: Path = ctx["reports_root"] |
| 395 | reports_root.mkdir(parents=True, exist_ok=True) |
| 396 | excerpt = asan_excerpt(crash.crash_output) |
| 397 | |
| 398 | async with ctx["lock"]: |
| 399 | manifest = _read_manifest(reports_root) |
| 400 | print(color(f"[judge:{run_idx}] {len(manifest)} bug(s) in manifest ...", "judge")) |
| 401 | jv, _jr, elapsed = await run_judge( |
| 402 | asan_excerpt=excerpt, dup_check=crash.dup_check, |
| 403 | grade_status=grade_status, grade_score=grade_score, |
| 404 | poc_size=len(crash.poc_bytes), |
| 405 | manifest_entries=manifest, |
| 406 | model=model, image_tag=target.image_tag, agent_env=agent_env, |
| 407 | container_name=f"judge_{target.name}_{run_idx}", |
| 408 | transcript_path=str(reports_root / f"judge_run{run_idx:03d}.jsonl"), |
| 409 | progress_prefix=f"[judge:{run_idx}]", |
| 410 | system_prompt=ctx["system_prompt"], |
| 411 | ) |
| 412 | _jline = (f"[judge:{run_idx}] {jv.judgment} in {elapsed:.1f}s" |
| 413 | + (f" → bug_{jv.bug_id:02d}" if jv.bug_id is not None else "")) |
| 414 | print(color(_jline, "red") if jv.judgment == "NEW" else _jline) |
| 415 | |
| 416 | if jv.judgment == "DUP_SKIP": |
| 417 | _log_judge(reports_root, run_idx, jv, bug_id=jv.bug_id) |
| 418 | return |
| 419 | |
| 420 | if jv.judgment == "NEW": |
| 421 | bug_id = _next_bug_id(manifest) |
| 422 | _append_manifest(reports_root, bug_id, run_idx, excerpt) |
| 423 | else: # DUP_BETTER |
| 424 | bug_id = jv.bug_id |
| 425 | assert bug_id is not None # _parse_judge enforces |
| 426 | _log_judge(reports_root, run_idx, jv, bug_id=bug_id) |
| 427 | |
| 428 | # Lock released — report agent runs without serializing the batch. |
| 429 | task = asyncio.create_task(_stream_report( |
| 430 | run_idx, bug_id, crash, target, model, agent_env, |
| 431 | reports_root, re_report=(jv.judgment == "DUP_BETTER"), |
| 432 | novelty=ctx["novelty"], max_turns=ctx["report_max_turns"], |
| 433 | system_prompt=ctx["system_prompt"], |
| 434 | )) |
| 435 | ctx["report_tasks"].append(task) |
| 436 | |
| 437 | |
| 438 | def _log_judge(reports_root: Path, run_idx: int, jv, bug_id: int | None) -> None: |
no test coverage detected