coder-eval 0.8.3__tar.gz → 0.8.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (544) hide show
  1. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/harness-candidates.md +10 -4
  2. {coder_eval-0.8.3 → coder_eval-0.8.4}/CHANGELOG.md +59 -0
  3. {coder_eval-0.8.3 → coder_eval-0.8.4}/CLAUDE.md +6 -4
  4. {coder_eval-0.8.3 → coder_eval-0.8.4}/PKG-INFO +8 -2
  5. {coder_eval-0.8.3 → coder_eval-0.8.4}/README.md +6 -1
  6. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/AB_EXPERIMENTS.md +34 -0
  7. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/TASK_DEFINITION_GUIDE.md +56 -0
  8. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/tutorials/04-writing-a-task.md +1 -0
  9. coder_eval-0.8.4/evalboard/app/_components/__tests__/search-box.test.tsx +120 -0
  10. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/_components/search-box.tsx +20 -4
  11. coder_eval-0.8.4/experiments/early-stop-ab.yaml +23 -0
  12. {coder_eval-0.8.3 → coder_eval-0.8.4}/pyproject.toml +2 -1
  13. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/__init__.py +1 -1
  14. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/agent.py +19 -1
  15. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/agents/antigravity_agent.py +7 -1
  16. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/agents/claude_code_agent.py +58 -11
  17. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/agents/codex_agent.py +6 -0
  18. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/agents/noop_agent.py +6 -0
  19. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/cli/plan_command.py +8 -0
  20. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/base.py +59 -1
  21. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/command_executed.py +129 -37
  22. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/skill_triggered.py +68 -2
  23. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/__init__.py +4 -0
  24. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/criteria.py +12 -0
  25. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/limits.py +11 -0
  26. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/results.py +88 -0
  27. coder_eval-0.8.4/src/coder_eval/orchestration/early_stop.py +328 -0
  28. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/orchestration/experiment.py +8 -0
  29. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/orchestrator.py +49 -2
  30. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/reports.py +8 -0
  31. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/reports_experiment.py +8 -0
  32. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/reports_html.py +15 -3
  33. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/sandbox.py +43 -8
  34. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/streaming/events.py +2 -0
  35. coder_eval-0.8.4/tests/lint/rules/ce025_live_verdict_consistency.py +111 -0
  36. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/runner.py +2 -0
  37. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_custom_lint.py +65 -0
  38. coder_eval-0.8.4/tests/test_early_stop.py +1278 -0
  39. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_sandbox.py +43 -2
  40. {coder_eval-0.8.3 → coder_eval-0.8.4}/uv.lock +6 -4
  41. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/commands/coder-eval-code-review-full.md +0 -0
  42. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/commands/coder-eval-code-review-wf.md +0 -0
  43. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/commands/coder-eval-code-review.md +0 -0
  44. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/commands/coder-eval-create-plan.md +0 -0
  45. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/commands/coder-eval-implement-plan.md +0 -0
  46. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/commands/coder-eval-review.md +0 -0
  47. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/commands/coder-eval-run-analysis.md +0 -0
  48. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/commands/coder-eval-task-create.md +0 -0
  49. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/shared/axes.md +0 -0
  50. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/shared/multi-model-review.md +0 -0
  51. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/shared/review-rubric.md +0 -0
  52. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/shared/run-layout.md +0 -0
  53. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/workflows/cr-axis.js +0 -0
  54. {coder_eval-0.8.3 → coder_eval-0.8.4}/.claude/workflows/cr-parent.js +0 -0
  55. {coder_eval-0.8.3 → coder_eval-0.8.4}/.env.example +0 -0
  56. {coder_eval-0.8.3 → coder_eval-0.8.4}/.github/CODEOWNERS +0 -0
  57. {coder_eval-0.8.3 → coder_eval-0.8.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  58. {coder_eval-0.8.3 → coder_eval-0.8.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  59. {coder_eval-0.8.3 → coder_eval-0.8.4}/.github/code_review.md +0 -0
  60. {coder_eval-0.8.3 → coder_eval-0.8.4}/.github/dependabot.yml +0 -0
  61. {coder_eval-0.8.3 → coder_eval-0.8.4}/.github/workflows/claude-pr-review.yml +0 -0
  62. {coder_eval-0.8.3 → coder_eval-0.8.4}/.github/workflows/codeql.yml +0 -0
  63. {coder_eval-0.8.3 → coder_eval-0.8.4}/.github/workflows/conventional-commits.yml +0 -0
  64. {coder_eval-0.8.3 → coder_eval-0.8.4}/.github/workflows/docker-publish.yml +0 -0
  65. {coder_eval-0.8.3 → coder_eval-0.8.4}/.github/workflows/pr-checks.yml +0 -0
  66. {coder_eval-0.8.3 → coder_eval-0.8.4}/.github/workflows/publish-testpypi.yml +0 -0
  67. {coder_eval-0.8.3 → coder_eval-0.8.4}/.github/workflows/release.yml +0 -0
  68. {coder_eval-0.8.3 → coder_eval-0.8.4}/.gitignore +0 -0
  69. {coder_eval-0.8.3 → coder_eval-0.8.4}/.pre-commit-config.yaml +0 -0
  70. {coder_eval-0.8.3 → coder_eval-0.8.4}/.python-version +0 -0
  71. {coder_eval-0.8.3 → coder_eval-0.8.4}/CODE_OF_CONDUCT.md +0 -0
  72. {coder_eval-0.8.3 → coder_eval-0.8.4}/CONTRIBUTING.md +0 -0
  73. {coder_eval-0.8.3 → coder_eval-0.8.4}/LICENSE +0 -0
  74. {coder_eval-0.8.3 → coder_eval-0.8.4}/Makefile +0 -0
  75. {coder_eval-0.8.3 → coder_eval-0.8.4}/NOTICE +0 -0
  76. {coder_eval-0.8.3 → coder_eval-0.8.4}/SECURITY.md +0 -0
  77. {coder_eval-0.8.3 → coder_eval-0.8.4}/docker/Dockerfile +0 -0
  78. {coder_eval-0.8.3 → coder_eval-0.8.4}/docker/Dockerfile.runtime +0 -0
  79. {coder_eval-0.8.3 → coder_eval-0.8.4}/docker/coder_eval_entrypoint.sh +0 -0
  80. {coder_eval-0.8.3 → coder_eval-0.8.4}/docker/coder_eval_runtime_entrypoint.sh +0 -0
  81. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/BYOD.md +0 -0
  82. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/CODEX_AGENT_GUIDE.md +0 -0
  83. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/DOCKER_ISOLATION.md +0 -0
  84. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/IDEAS.md +0 -0
  85. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/USER_GUIDE.md +0 -0
  86. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/assets/hero.gif +0 -0
  87. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/tutorials/01-first-evaluation.md +0 -0
  88. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/tutorials/02-ci-pipeline.md +0 -0
  89. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/tutorials/03-evalboard-local.md +0 -0
  90. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/tutorials/05-comparing-models.md +0 -0
  91. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/tutorials/06-use-docker-isolation.md +0 -0
  92. {coder_eval-0.8.3 → coder_eval-0.8.4}/docs/tutorials/README.md +0 -0
  93. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/.gitignore +0 -0
  94. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/README.md +0 -0
  95. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/_components/col-help.tsx +0 -0
  96. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/_components/collapsible-rail.tsx +0 -0
  97. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/_components/harness-badge.tsx +0 -0
  98. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/_components/scroll-table.tsx +0 -0
  99. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/_components/unit-toggle.tsx +0 -0
  100. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/_components/version-list.tsx +0 -0
  101. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/_components/window-selector.tsx +0 -0
  102. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/_overview/daily-chart.tsx +0 -0
  103. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/_overview/tag-rail.tsx +0 -0
  104. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/_overview/turn-budget-chart.tsx +0 -0
  105. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/_overview/window-summary.tsx +0 -0
  106. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/api/download/route.ts +0 -0
  107. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/api/file/route.ts +0 -0
  108. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/api/refresh/__tests__/route.test.ts +0 -0
  109. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/api/refresh/route.ts +0 -0
  110. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/error.tsx +0 -0
  111. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/globals.css +0 -0
  112. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/icon.png +0 -0
  113. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/layout.tsx +0 -0
  114. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/page.tsx +0 -0
  115. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/path-to-ga/page.tsx +0 -0
  116. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/trends/__tests__/trends-view.test.tsx +0 -0
  117. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/trends/actions.ts +0 -0
  118. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/trends/page.tsx +0 -0
  119. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/trends/trends-view.tsx +0 -0
  120. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/watchlist/__tests__/watchlist-view.test.tsx +0 -0
  121. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/watchlist/page.tsx +0 -0
  122. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/app/watchlist/watchlist-view.tsx +0 -0
  123. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/next-env.d.ts +0 -0
  124. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/next.config.mjs +0 -0
  125. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/package.json +0 -0
  126. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/pnpm-lock.yaml +0 -0
  127. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/postcss.config.mjs +0 -0
  128. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/public/harness/antigravity.png +0 -0
  129. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/public/harness/claude-code.png +0 -0
  130. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/public/harness/codex.png +0 -0
  131. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/public/uipath.png +0 -0
  132. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/tailwind.config.ts +0 -0
  133. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/tsconfig.json +0 -0
  134. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/vitest.config.ts +0 -0
  135. {coder_eval-0.8.3 → coder_eval-0.8.4}/evalboard/vitest.setup.ts +0 -0
  136. {coder_eval-0.8.3 → coder_eval-0.8.4}/experiments/default.yaml +0 -0
  137. {coder_eval-0.8.3 → coder_eval-0.8.4}/experiments/model-comparison.yaml +0 -0
  138. {coder_eval-0.8.3 → coder_eval-0.8.4}/experiments/permissions-smoke.yaml +0 -0
  139. {coder_eval-0.8.3 → coder_eval-0.8.4}/experiments/plugin-comparison.yaml +0 -0
  140. {coder_eval-0.8.3 → coder_eval-0.8.4}/experiments/prompt-mutations-example.yaml +0 -0
  141. {coder_eval-0.8.3 → coder_eval-0.8.4}/experiments/smoke_variants.yaml +0 -0
  142. {coder_eval-0.8.3 → coder_eval-0.8.4}/osv-scanner.toml +0 -0
  143. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/.gitattributes +0 -0
  144. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/agents/__init__.py +0 -0
  145. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/agents/_logging.py +0 -0
  146. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/agents/registry.py +0 -0
  147. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/agents/watchdog.py +0 -0
  148. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/analysis.py +0 -0
  149. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/cli/__init__.py +0 -0
  150. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/cli/aggregate_command.py +0 -0
  151. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/cli/console.py +0 -0
  152. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/cli/evaluate_command.py +0 -0
  153. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/cli/report_command.py +0 -0
  154. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/cli/run_command.py +0 -0
  155. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/cli/run_helpers.py +0 -0
  156. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/cli/run_task_internal_command.py +0 -0
  157. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/cli/utils.py +0 -0
  158. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/config.py +0 -0
  159. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/__init__.py +0 -0
  160. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/_classification_aggregate.py +0 -0
  161. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/agent_judge.py +0 -0
  162. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/classification_match.py +0 -0
  163. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/commands_efficiency.py +0 -0
  164. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/file_check.py +0 -0
  165. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/file_contains.py +0 -0
  166. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/file_exists.py +0 -0
  167. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/file_matches_regex.py +0 -0
  168. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/json_check.py +0 -0
  169. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/llm_judge.py +0 -0
  170. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/reference_comparison.py +0 -0
  171. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/run_command.py +0 -0
  172. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/criteria/uipath_eval.py +0 -0
  173. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/errors/__init__.py +0 -0
  174. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/errors/agent.py +0 -0
  175. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/errors/budget.py +0 -0
  176. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/errors/categories.py +0 -0
  177. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/errors/categorization.py +0 -0
  178. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/errors/executor.py +0 -0
  179. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/errors/judge.py +0 -0
  180. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/errors/retry.py +0 -0
  181. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/errors/timeout.py +0 -0
  182. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/evaluation/__init__.py +0 -0
  183. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/evaluation/checker.py +0 -0
  184. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/evaluation/judge_anthropic.py +0 -0
  185. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/evaluation/judge_bedrock.py +0 -0
  186. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/evaluation/judge_context.py +0 -0
  187. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/evaluation/judge_models.py +0 -0
  188. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/evaluation/judge_persistence.py +0 -0
  189. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/evaluation/judge_usage.py +0 -0
  190. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/evaluation/sub_agent.py +0 -0
  191. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/evaluation/summaries.py +0 -0
  192. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/evaluation/verdict_tool.py +0 -0
  193. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/formatting.py +0 -0
  194. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/isolation/__init__.py +0 -0
  195. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/isolation/docker_runner.py +0 -0
  196. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/logging_config.py +0 -0
  197. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/agent_config.py +0 -0
  198. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/container_paths.py +0 -0
  199. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/enums.py +0 -0
  200. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/experiment.py +0 -0
  201. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/judge.py +0 -0
  202. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/judge_defaults.py +0 -0
  203. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/merge_strategy.py +0 -0
  204. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/mutations.py +0 -0
  205. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/routing.py +0 -0
  206. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/sandbox.py +0 -0
  207. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/tasks.py +0 -0
  208. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/telemetry.py +0 -0
  209. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/models/templates.py +0 -0
  210. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/orchestration/__init__.py +0 -0
  211. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/orchestration/batch.py +0 -0
  212. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/orchestration/config.py +0 -0
  213. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/orchestration/config_merge.py +0 -0
  214. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/orchestration/evaluation.py +0 -0
  215. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/orchestration/overrides.py +0 -0
  216. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/orchestration/task_loader.py +0 -0
  217. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/path_utils.py +0 -0
  218. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/plugins.py +0 -0
  219. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/pricing.py +0 -0
  220. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/py.typed +0 -0
  221. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/reports_stats.py +0 -0
  222. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/resources/__init__.py +0 -0
  223. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/resources/default_ignore_patterns.yaml +0 -0
  224. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/resources/tags.yaml +0 -0
  225. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/scoring/__init__.py +0 -0
  226. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/scoring/ast_similarity.py +0 -0
  227. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/scoring/complexity.py +0 -0
  228. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/scoring/quality.py +0 -0
  229. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/scoring/signature_similarity.py +0 -0
  230. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/scoring/similarity.py +0 -0
  231. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/scoring/token_similarity.py +0 -0
  232. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/simulation/__init__.py +0 -0
  233. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/simulation/termination.py +0 -0
  234. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/simulation/user_simulator.py +0 -0
  235. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/streaming/__init__.py +0 -0
  236. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/streaming/callbacks.py +0 -0
  237. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/streaming/collector.py +0 -0
  238. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/streaming/renderers.py +0 -0
  239. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/streaming/wire.py +0 -0
  240. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/telemetry.py +0 -0
  241. {coder_eval-0.8.3 → coder_eval-0.8.4}/src/coder_eval/utils.py +0 -0
  242. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/README.md +0 -0
  243. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agentless_smoke_test.yaml +0 -0
  244. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/antigravity_hello_world.yaml +0 -0
  245. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/antigravity_hello_world_docker.yaml +0 -0
  246. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/claude_hello_world.yaml +0 -0
  247. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/claude_hello_world_docker.yaml +0 -0
  248. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/claude_parallel_single_gen.yaml +0 -0
  249. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/claude_subagent_test.yaml +0 -0
  250. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/codex_disallowed_tools_test.yaml +0 -0
  251. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/codex_hello_world.yaml +0 -0
  252. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/codex_parallel_commands.yaml +0 -0
  253. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/codex_parallel_single_gen.yaml +0 -0
  254. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/codex_skills_test.yaml +0 -0
  255. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/codex_string_utils.yaml +0 -0
  256. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/codex_subagent_test.yaml +0 -0
  257. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/subagent_bash_long_input.yaml +0 -0
  258. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/agents/subagent_merge_sort.yaml +0 -0
  259. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/byod_smoke_test.yaml +0 -0
  260. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/dataset_example.yaml +0 -0
  261. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/datasets/sentiment.jsonl +0 -0
  262. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/dockerfile_build_example/dockerfile_build_example.yaml +0 -0
  263. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/dockerfile_build_example/environment/Dockerfile +0 -0
  264. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/dockerfile_build_example/environment/Dockerfile.workdir +0 -0
  265. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/dockerfile_build_example/environment/input.txt +0 -0
  266. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/dockerfile_build_example/working_dir_auto_example.yaml +0 -0
  267. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/dockerfile_build_example/working_dir_concrete_example.yaml +0 -0
  268. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/fibonacci_with_template.yaml +0 -0
  269. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/hello_date.yaml +0 -0
  270. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/inline_starter_example.yaml +0 -0
  271. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/internal/session_resumption.yaml +0 -0
  272. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/mock_path_dirs_smoke.yaml +0 -0
  273. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/mock_path_dirs_template_dir/mock-cli-bins/README.md +0 -0
  274. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/mock_path_dirs_template_dir/mock-cli-bins/mocks/echo_args +0 -0
  275. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/mock_path_dirs_template_dir/mock-cli-bins/mocks/fixtures/config.json +0 -0
  276. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/mock_path_dirs_template_dir/mock-cli-bins/mocks/say_hello +0 -0
  277. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/mock_path_dirs_template_dir/task.yaml +0 -0
  278. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/python_cli_simulated_judged/echo_simulated_judged.yaml +0 -0
  279. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/3d-scan-calc/3d-scan-calc.yaml +0 -0
  280. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/3d-scan-calc/environment/Dockerfile +0 -0
  281. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/3d-scan-calc/environment/material_density_table.md +0 -0
  282. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/3d-scan-calc/environment/scan_data.stl +0 -0
  283. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/3d-scan-calc/verifier/test.sh +0 -0
  284. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/3d-scan-calc/verifier/test_outputs.py +0 -0
  285. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/README.md +0 -0
  286. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/court-form-filling/court-form-filling.yaml +0 -0
  287. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/court-form-filling/environment/Dockerfile +0 -0
  288. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/court-form-filling/environment/sc100-blank.pdf +0 -0
  289. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/court-form-filling/verifier/test.sh +0 -0
  290. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/court-form-filling/verifier/test_outputs.py +0 -0
  291. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/dialogue-parser/dialogue-parser.yaml +0 -0
  292. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/dialogue-parser/environment/Dockerfile +0 -0
  293. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/dialogue-parser/environment/script.txt +0 -0
  294. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/dialogue-parser/verifier/test.sh +0 -0
  295. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/samples/skillsbench/dialogue-parser/verifier/test_outputs.py +0 -0
  296. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/sentiment_classification.yaml +0 -0
  297. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/smoke_agent_judge.yaml +0 -0
  298. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/smoke_budget_exceeded.yaml +0 -0
  299. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/smoke_cost_budget_exceeded.yaml +0 -0
  300. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/smoke_llm_judge.yaml +0 -0
  301. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/smoke_negative_path.yaml +0 -0
  302. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/smoke_task_timeout.yaml +0 -0
  303. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/smoke_variants.yaml +0 -0
  304. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/test_sandbox.yaml +0 -0
  305. {coder_eval-0.8.3 → coder_eval-0.8.4}/tasks/token_check.yaml +0 -0
  306. {coder_eval-0.8.3 → coder_eval-0.8.4}/templates/byod_smoke_test/Dockerfile +0 -0
  307. {coder_eval-0.8.3 → coder_eval-0.8.4}/templates/fibonacci-starter/README.md +0 -0
  308. {coder_eval-0.8.3 → coder_eval-0.8.4}/templates/fibonacci-starter/src/main.py +0 -0
  309. {coder_eval-0.8.3 → coder_eval-0.8.4}/templates/fibonacci-starter/tests/test_main.py +0 -0
  310. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/__init__.py +0 -0
  311. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/__init__.py +0 -0
  312. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/__init__.py +0 -0
  313. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/_scrub.py +0 -0
  314. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/claude_fixtures.py +0 -0
  315. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/codex_fixtures.py +0 -0
  316. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/claude_a_single_text_turn.json +0 -0
  317. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/claude_b_tool_use_result.json +0 -0
  318. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/claude_c_multi_emission_delta.json +0 -0
  319. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/claude_d_subagent_terminal.json +0 -0
  320. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/claude_e_model_usage_and_backfill.json +0 -0
  321. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/claude_f_orphaned_tool.json +0 -0
  322. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/claude_g_crash_format_placeholder.json +0 -0
  323. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/claude_h1_timeout_process_error.json +0 -0
  324. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/claude_h2_process_error_crash.json +0 -0
  325. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/claude_i_in_loop_deadline_break.json +0 -0
  326. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/codex_a_agent_message_only.json +0 -0
  327. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/codex_b_command_execution.json +0 -0
  328. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/codex_c_reasoning_placeholder.json +0 -0
  329. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/codex_d_cross_flush_is_error.json +0 -0
  330. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/codex_e_orphan_tool.json +0 -0
  331. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/codex_f_collab_fallback.json +0 -0
  332. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/codex_g_items_rebuild.json +0 -0
  333. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/golden_streams/expected/codex_h_no_turn_completed_crash.json +0 -0
  334. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/report_snapshots/__init__.py +0 -0
  335. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/report_snapshots/_snapshot.py +0 -0
  336. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/report_snapshots/experiment_2variant.md +0 -0
  337. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/report_snapshots/experiment_3variant.md +0 -0
  338. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/report_snapshots/experiment_replicates.md +0 -0
  339. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/report_snapshots/run_full.md +0 -0
  340. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_fixtures/report_snapshots/run_minimal.md +0 -0
  341. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/_path_helpers.py +0 -0
  342. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/conftest.py +0 -0
  343. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/fixtures/__init__.py +0 -0
  344. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/fixtures/byoa_demo_plugin/byoa_demo.py +0 -0
  345. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/fixtures/byoa_demo_plugin/pyproject.toml +0 -0
  346. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/fixtures/mock_agent.py +0 -0
  347. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/fixtures/tasks/test_task_multiple_criteria.yaml +0 -0
  348. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/fixtures/tasks/test_task_pass.yaml +0 -0
  349. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/fixtures/text_stub_agent.py +0 -0
  350. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/__init__.py +0 -0
  351. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/__init__.py +0 -0
  352. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/base.py +0 -0
  353. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/ce014_merge_strategy_declared.py +0 -0
  354. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/ce015_create_subprocess_limit.py +0 -0
  355. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/ce016_no_computed_tokenusage_kwargs.py +0 -0
  356. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/ce017_models_lazy_agent_imports.py +0 -0
  357. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/ce018_no_final_status_name_denylist.py +0 -0
  358. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/ce019_telemetry_non_fatal.py +0 -0
  359. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/ce020_no_sdk_typed_base_agent_fields.py +0 -0
  360. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/ce021_guarded_evaluationresult_parse.py +0 -0
  361. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/ce022_dialog_loop_statement_cap.py +0 -0
  362. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/ce023_no_proxy_shim_import.py +0 -0
  363. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/ce024_discriminated_unions.py +0 -0
  364. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/no_agent_timing_access.py +0 -0
  365. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/no_blocking_io_in_async.py +0 -0
  366. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/no_cli_imports_in_core.py +0 -0
  367. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/no_silent_except.py +0 -0
  368. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/no_submodule_model_imports.py +0 -0
  369. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/no_top_level_run_limits_access.py +0 -0
  370. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/no_transcript_regex_in_eval.py +0 -0
  371. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/no_type_name_string_dispatch.py +0 -0
  372. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/open_explicit_encoding.py +0 -0
  373. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/read_text_explicit_encoding.py +0 -0
  374. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/register_criterion_required.py +0 -0
  375. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/subprocess_run_explicit_encoding.py +0 -0
  376. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/rules/yaml_models_forbid_extras.py +0 -0
  377. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/lint/violation.py +0 -0
  378. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_agent.py +0 -0
  379. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_agent_config_no_timing_fields.py +0 -0
  380. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_agent_config_optional_type.py +0 -0
  381. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_agent_config_registry_dispatch.py +0 -0
  382. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_agent_config_sdk_decoupling.py +0 -0
  383. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_agent_golden_master.py +0 -0
  384. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_agent_judge_criterion.py +0 -0
  385. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_agent_telemetry.py +0 -0
  386. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_agent_telemetry_advanced.py +0 -0
  387. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_agent_timeout.py +0 -0
  388. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_agentless.py +0 -0
  389. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_aggregate.py +0 -0
  390. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_antigravity_agent.py +0 -0
  391. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_byoa_plugin.py +0 -0
  392. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_byoa_plugin_live.py +0 -0
  393. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_byod_feature.py +0 -0
  394. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_checker_logging.py +0 -0
  395. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_classification_match.py +0 -0
  396. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_claude_settings_enforcement_live.py +0 -0
  397. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_cleanup_preservation_guard.py +0 -0
  398. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_cli_backend_flag.py +0 -0
  399. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_cli_empty_glob.py +0 -0
  400. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_cli_sdk_options.py +0 -0
  401. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_cli_set_overrides.py +0 -0
  402. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_cli_telemetry.py +0 -0
  403. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_cli_type_flag.py +0 -0
  404. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_code_review_bugs.py +0 -0
  405. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_codex_agent.py +0 -0
  406. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_codex_agent_live.py +0 -0
  407. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_codex_agent_unit.py +0 -0
  408. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_codex_token_mapping.py +0 -0
  409. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_command_executed.py +0 -0
  410. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_command_statistics.py +0 -0
  411. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_command_telemetry_result_data.py +0 -0
  412. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_commands_efficiency.py +0 -0
  413. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_config_lineage.py +0 -0
  414. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_config_merge_engine.py +0 -0
  415. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_config_precedence.py +0 -0
  416. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_continuous_scoring.py +0 -0
  417. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_criterion_result_round_trip.py +0 -0
  418. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_dataset_expansion.py +0 -0
  419. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_debug_logging.py +0 -0
  420. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_docker_build_failure.py +0 -0
  421. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_docker_runner_container_death.py +0 -0
  422. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_docker_runner_mounts.py +0 -0
  423. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_docker_runner_stream_limit.py +0 -0
  424. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_docker_wildcard_env.py +0 -0
  425. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_docker_workdir_live.py +0 -0
  426. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_driver_resolver.py +0 -0
  427. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_error_handling.py +0 -0
  428. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_evaluate_command.py +0 -0
  429. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_evaluator.py +0 -0
  430. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_event_collector.py +0 -0
  431. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_experiment_cli.py +0 -0
  432. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_experiment_loader.py +0 -0
  433. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_experiment_models.py +0 -0
  434. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_experiment_reports.py +0 -0
  435. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_experiment_resolver.py +0 -0
  436. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_experiment_runner.py +0 -0
  437. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_file_check.py +0 -0
  438. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_file_contains_scoring.py +0 -0
  439. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_formatting.py +0 -0
  440. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_git_clone_failure.py +0 -0
  441. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_heartbeat_watchdog.py +0 -0
  442. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_ignore_patterns_negation.py +0 -0
  443. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_image_from_dockerfiles.py +0 -0
  444. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_integration.py +0 -0
  445. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_json_check.py +0 -0
  446. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_judge_anthropic.py +0 -0
  447. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_judge_bedrock.py +0 -0
  448. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_judge_burn_in_live.py +0 -0
  449. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_judge_context_builder.py +0 -0
  450. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_judge_models.py +0 -0
  451. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_judge_persistence.py +0 -0
  452. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_lint_no_top_level_run_limits.py +0 -0
  453. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_lint_runner.py +0 -0
  454. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_llm_judge_criterion.py +0 -0
  455. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_log_tail_buffer.py +0 -0
  456. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_logging.py +0 -0
  457. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_logging_isolation.py +0 -0
  458. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_merge_characterization.py +0 -0
  459. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_merge_strategy_annotations.py +0 -0
  460. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_merge_unification.py +0 -0
  461. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_models.py +0 -0
  462. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_mutations.py +0 -0
  463. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_new_criteria.py +0 -0
  464. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_node_env_config.py +0 -0
  465. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_optional_dependencies.py +0 -0
  466. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_orchestrator.py +0 -0
  467. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_orchestrator_error_log_tail.py +0 -0
  468. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_orchestrator_telemetry.py +0 -0
  469. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_overrides_engine.py +0 -0
  470. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_parallel.py +0 -0
  471. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_path_utils.py +0 -0
  472. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_plan_command.py +0 -0
  473. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_plugin_processing.py +0 -0
  474. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_plugins.py +0 -0
  475. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_post_run.py +0 -0
  476. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_pr_review_workflow.py +0 -0
  477. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_pre_run.py +0 -0
  478. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_preservation_mode.py +0 -0
  479. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_pricing_registry.py +0 -0
  480. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_reference_comparison_scoring.py +0 -0
  481. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_reference_evaluator.py +0 -0
  482. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_reference_missing_file.py +0 -0
  483. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_reference_models.py +0 -0
  484. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_reference_orchestrator.py +0 -0
  485. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_registry.py +0 -0
  486. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_replicate_stats.py +0 -0
  487. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_report_command.py +0 -0
  488. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_reports.py +0 -0
  489. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_reports_experiment.py +0 -0
  490. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_reports_html.py +0 -0
  491. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_reports_stats.py +0 -0
  492. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_resolve_task_files.py +0 -0
  493. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_resume.py +0 -0
  494. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_retry_logic_comprehensive.py +0 -0
  495. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_routing.py +0 -0
  496. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_run_command_stdout.py +0 -0
  497. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_run_limits_models.py +0 -0
  498. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_run_limits_orchestrator.py +0 -0
  499. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_run_limits_resolver.py +0 -0
  500. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_runtime_tool_versions.py +0 -0
  501. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_sandbox_layer_builder.py +0 -0
  502. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_sandbox_optional.py +0 -0
  503. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_sandbox_security.py +0 -0
  504. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_sandbox_symlink_preservation.py +0 -0
  505. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_sandbox_templates.py +0 -0
  506. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_scorers.py +0 -0
  507. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_scoring_quality.py +0 -0
  508. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_sdk_option_classification.py +0 -0
  509. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_simulation_config.py +0 -0
  510. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_simulation_integration.py +0 -0
  511. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_simulation_termination.py +0 -0
  512. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_simulation_trials.py +0 -0
  513. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_skill_triggered.py +0 -0
  514. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_streaming_agent_integration.py +0 -0
  515. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_streaming_batch.py +0 -0
  516. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_streaming_callbacks.py +0 -0
  517. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_streaming_cli.py +0 -0
  518. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_streaming_events.py +0 -0
  519. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_streaming_orchestrator.py +0 -0
  520. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_streaming_renderers.py +0 -0
  521. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_streaming_wire.py +0 -0
  522. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_sub_agent_runner.py +0 -0
  523. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_success_criterion_union.py +0 -0
  524. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_suite_rollup.py +0 -0
  525. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_summaries.py +0 -0
  526. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_tags.py +0 -0
  527. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_task_definition_unknown_fields.py +0 -0
  528. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_telemetry.py +0 -0
  529. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_template_env_expansion.py +0 -0
  530. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_threshold_enforcement.py +0 -0
  531. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_timeout_batch.py +0 -0
  532. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_timeout_categorization.py +0 -0
  533. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_timeout_exceptions.py +0 -0
  534. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_timeout_models.py +0 -0
  535. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_timeout_orchestrator.py +0 -0
  536. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_token_usage.py +0 -0
  537. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_uipath_eval.py +0 -0
  538. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_user_simulator.py +0 -0
  539. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_utils.py +0 -0
  540. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_utterance_extraction.py +0 -0
  541. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_variant_prompt_file.py +0 -0
  542. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_verdict_tool.py +0 -0
  543. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_watchdog.py +0 -0
  544. {coder_eval-0.8.3 → coder_eval-0.8.4}/tests/test_yaml_migration.py +0 -0
@@ -5,21 +5,27 @@ Deferred lint/test guardrails surfaced during reviews. Promote to a `CExxx` rule
5
5
 
6
6
  ## From code review 260701-1954 (fix-review-top5 run) — deferred to a dedicated guardrail plan
7
7
 
8
- - **CE024** workflow-YAML rule: forbid any `uses:` step pinned to a floating ref
8
+ > Numbering note: these are *proposed* ids. `CE024` (discriminated-unions) and
9
+ > `CE025` (live-verdict consistency) have since been **implemented** for other
10
+ > rules, so the candidates below were renumbered to the next free ids. Always
11
+ > claim the next unused number in `tests/lint/rules/` — the id-uniqueness assert
12
+ > in `tests/lint/runner.py` is the source of truth.
13
+
14
+ - **CE026** — workflow-YAML rule: forbid any `uses:` step pinned to a floating ref
9
15
  (`@v3`, `@main`) rather than a 40-hex commit SHA. Would have caught
10
16
  `mxschmitt/action-tmate@v3` (fixed manually in this run). >30 min: needs a
11
17
  non-Python file-walk branch in `tests/lint/runner.py`.
12
- - **CE025** — retired-token grep gate: fail when a removed-subsystem token
18
+ - **CE027** — retired-token grep gate: fail when a removed-subsystem token
13
19
  (`LLMGW_`, `API_BACKEND=proxy`, `uipath_llmgw_client`) reappears outside an
14
20
  allowlist across docs/config/src. Would have caught the LLM-Gateway residue
15
21
  swept in this run. >30 min: needs an allowlist + repo-wide text scan.
16
- - **CE026** — assert the Makefile `lint:` help does not hardcode a stale `CE0NN`
22
+ - **CE028** — assert the Makefile `lint:` help does not hardcode a stale `CE0NN`
17
23
  upper bound (use `CE001+`). Would have caught the `CE001–CE005` drift fixed here.
18
24
  - **docs-vs-harness smoke test** — execute the CI tutorial's `coder-eval run`
19
25
  command against a NoOp task and assert the produced tree matches the documented
20
26
  globs. Would have caught the `--run-dir runs` layout bug. Not statically
21
27
  reachable (needs a live run).
22
- - [ ] CE-rule: `type: Literal[...]` fields on models in `coder_eval/models/` must declare their tag default (`type: Literal["x"] = "x"`) — a member without the default degrades `validate_registry` diagnostics (PydanticUndefined in expected_types) and breaks direct construction. Nothing guards it today; needs a rule-design call (second violation class inside CE024 vs. a new CE025), and the failure is already double-caught by the MINIMAL_PAYLOADS parity test + direct-construction tests — caught in the 2026-07-03 top5-review-fixes run (Phase 1 quality review).
28
+ - [ ] CE-rule: `type: Literal[...]` fields on models in `coder_eval/models/` must declare their tag default (`type: Literal["x"] = "x"`) — a member without the default degrades `validate_registry` diagnostics (PydanticUndefined in expected_types) and breaks direct construction. Nothing guards it today; needs a rule-design call (second violation class inside CE024 vs. a new CExxx at the next free id), and the failure is already double-caught by the MINIMAL_PAYLOADS parity test + direct-construction tests — caught in the 2026-07-03 top5-review-fixes run (Phase 1 quality review).
23
29
 
24
30
  ## From 2026-07-03 open-source docs cleanup
25
31
 
@@ -2,6 +2,65 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v0.8.4 (2026-07-13)
6
+
7
+ ### Bug Fixes
8
+
9
+ - **deps**: Upgrade click to 8.4.2 to resolve PYSEC-2026-2132
10
+ ([#19](https://github.com/UiPath/coder_eval/pull/19),
11
+ [`a240d4e`](https://github.com/UiPath/coder_eval/commit/a240d4e2f8b970665743d0dc3d212c6c8e8a30ac))
12
+
13
+ - **deps**: Upgrade click to 8.4.2 to resolve PYSEC-2026-2132
14
+ ([#20](https://github.com/UiPath/coder_eval/pull/20),
15
+ [`bba8645`](https://github.com/UiPath/coder_eval/commit/bba8645fc3f6c7b6e9784af496641ac0eaf8bede))
16
+
17
+ - **evalboard**: Address search-box code review comments
18
+ ([#13](https://github.com/UiPath/coder_eval/pull/13),
19
+ [`382d80d`](https://github.com/UiPath/coder_eval/commit/382d80d4a84da39327b0196c97c01a367f094c0e))
20
+
21
+ - **evalboard**: Fix search bar clear issue ([#13](https://github.com/UiPath/coder_eval/pull/13),
22
+ [`382d80d`](https://github.com/UiPath/coder_eval/commit/382d80d4a84da39327b0196c97c01a367f094c0e))
23
+
24
+ - **evalboard**: Prevent search bar from resetting mid-type
25
+ ([#13](https://github.com/UiPath/coder_eval/pull/13),
26
+ [`382d80d`](https://github.com/UiPath/coder_eval/commit/382d80d4a84da39327b0196c97c01a367f094c0e))
27
+
28
+ - **sandbox**: Exclude home-dir dotfiles from capture_to artifacts
29
+ ([#19](https://github.com/UiPath/coder_eval/pull/19),
30
+ [`a240d4e`](https://github.com/UiPath/coder_eval/commit/a240d4e2f8b970665743d0dc3d212c6c8e8a30ac))
31
+
32
+ - **sandbox**: Extend capture_to denylist with credential stores
33
+ ([#19](https://github.com/UiPath/coder_eval/pull/19),
34
+ [`a240d4e`](https://github.com/UiPath/coder_eval/commit/a240d4e2f8b970665743d0dc3d212c6c8e8a30ac))
35
+
36
+ ### Code Style
37
+
38
+ - Fix ruff formatting in _WORKSPACE_CAPTURE_IGNORE
39
+ ([#19](https://github.com/UiPath/coder_eval/pull/19),
40
+ [`a240d4e`](https://github.com/UiPath/coder_eval/commit/a240d4e2f8b970665743d0dc3d212c6c8e8a30ac))
41
+
42
+ ### Documentation
43
+
44
+ - **readme**: Clarify framing before hero gif ([#16](https://github.com/UiPath/coder_eval/pull/16),
45
+ [`b7dee1c`](https://github.com/UiPath/coder_eval/commit/b7dee1c0616d9a98dc98432ca066c1a8c9264ef4))
46
+
47
+ - **readme**: Reframe title toward agents & their skills
48
+ ([#16](https://github.com/UiPath/coder_eval/pull/16),
49
+ [`b7dee1c`](https://github.com/UiPath/coder_eval/commit/b7dee1c0616d9a98dc98432ca066c1a8c9264ef4))
50
+
51
+ ### Features
52
+
53
+ - **early-stop**: Opt-in early stop once armed criteria are decided
54
+ ([#14](https://github.com/UiPath/coder_eval/pull/14),
55
+ [`b0c1ade`](https://github.com/UiPath/coder_eval/commit/b0c1ade364119573f172e4d64ee3fff0a387db32))
56
+
57
+ ### Testing
58
+
59
+ - **sandbox**: Cover home-dir dotfile exclusion in capture_to
60
+ ([#19](https://github.com/UiPath/coder_eval/pull/19),
61
+ [`a240d4e`](https://github.com/UiPath/coder_eval/commit/a240d4e2f8b970665743d0dc3d212c6c8e8a30ac))
62
+
63
+
5
64
  ## v0.8.3 (2026-07-09)
6
65
 
7
66
  ### Bug Fixes
@@ -36,7 +36,7 @@ coder_eval/
36
36
  │ ├── experiment.py # ExperimentDefinition, ExperimentVariant, ResolvedTask, result models
37
37
  │ ├── judge_defaults.py # DEFAULT_JUDGE_MODEL constant (cycle-free leaf)
38
38
  │ ├── mutations.py # PromptMutation variants (prefix/suffix/replace/template/rephrase)
39
- │ ├── results.py # CriterionResult (+ ClassificationCriterionResult), TurnRecord, EvaluationResult, CriterionAggregate, ThresholdCheck, SuiteRollup
39
+ │ ├── results.py # CriterionResult (+ ClassificationCriterionResult), TurnRecord, EvaluationResult, EarlyStopInfo/EarlyStopReason, CriterionAggregate, ThresholdCheck, SuiteRollup
40
40
  │ ├── routing.py # ApiRoute (DirectRoute/BedrockRoute)
41
41
  │ ├── sandbox.py # SandboxConfig, ResourceLimits
42
42
  │ ├── tasks.py # TaskDefinition, AgentConfig, Dataset (dataset fan-out + sample)
@@ -79,6 +79,7 @@ coder_eval/
79
79
  ├── orchestration/ # Batch execution utilities
80
80
  │ ├── batch.py # Parallel task execution (run_batch + run_batch_resolved)
81
81
  │ ├── config.py # Batch run configuration
82
+ │ ├── early_stop.py # validate_early_stop guardrails + EarlyStopWatcher (armed live-verdict observer)
82
83
  │ ├── evaluation.py # Evaluation helpers
83
84
  │ ├── experiment.py # ExperimentRunner, resolve_task_for_variant, load_experiment
84
85
  │ └── task_loader.py # YAML task loading
@@ -138,6 +139,7 @@ templates/ # Sandbox template directories
138
139
  - **Reconciliation message (stream self-reconciles to the turn total)**: The per-message stream consistently under-reports the authoritative turn total — a fixed prompt slice (~512 input tokens on Claude) is billed on no SDK-emitted message, and sub-agent input/cache only partially bubbles up. So `EventCollector.build_turn_record` appends one synthetic `ReconciliationMessage` (`role="reconciliation"`, in the `TranscriptMessage` union) per turn, carrying the per-bucket residual = `token_usage` − Σ(assistant message buckets). The invariant: **summing the four token buckets across `TurnRecord.messages` (assistant + reconciliation) equals `token_usage` exactly**, for both Claude and Codex (Codex's stream is already complete after `_recover_subagent_tool_calls`, so its residual is usually 0 and no entry is emitted). This is what lets the evalboard SUM the message stream as the source of truth instead of reading a separate aggregate ("agent tokens"): `selectTokenTotals` returns the stream sum whenever a reconciliation entry is present, and the timeline renders it as its own row. It is agent-agnostic (booked at the single `EventCollector` seam), carries no cost (cost stays on `token_usage`), and is excluded from generation/turn counts and the cost simulator. The Python `token_usage`/`total_token_usage` aggregate is unchanged and still authoritative for budget/judges/reports.
139
140
  - **sandbox isolation**: Tasks that don't need MCP servers should set `setting_sources: []` in their `agent:` block to isolate the sandbox from the host project's CLAUDE.md and settings. Without this, the host project's CLAUDE.md (often 20 KB+) is injected into every API call, inflating cache-creation tokens and cost significantly.
140
141
  - **Run-time caps (non-criterion enforcement)**: `TaskDefinition.run_limits` (`RunLimits` model) is the single namespace for all run-time caps — `max_turns` / `task_timeout` / `turn_timeout` (structural) and `max_input_tokens` / `max_output_tokens` / `max_total_tokens` / `max_usd` (cumulative budget). Token/USD breaches abort with `FinalStatus.TOKEN_BUDGET_EXCEEDED` or `COST_BUDGET_EXCEEDED` (both `category == "failed"`). Structural caps are set from the CLI via `-D run_limits.max_turns=…` / `-D run_limits.task_timeout=…` / `-D run_limits.turn_timeout=…` (field-merged into `run_limits`); budget caps via `-D run_limits.max_usd=…` etc. or YAML. Layered config uses field-merge — a variant block overrides individual keys without replacing the task's block.
142
+ - **Early stop on criterion (opt-in)**: `run_limits.stop_early` (default off) ends a single-shot Claude run early once the run's **armed** criteria are decided, so a raised `max_turns` isn't wasted on the smoke flavor. A criterion is armed by `stop_when: pass|fail|decided`; only criteria that can decide from a partial trajectory may arm (they declare a non-empty `live_stop_polarities` ClassVar and override `live_verdict` on `BaseCriterion` — currently `skill_triggered`, `command_executed`; CE025 enforces the two stay consistent). It uses a cooperative `should_stop` seam on the Claude agent's between-messages guard (tool-call granularity, no SIGKILL) driven by `orchestration/early_stop.py::EarlyStopWatcher` (own `EventCollector` + stop rule). Live verdicts only *trigger* the stop; the standard `check_all` on the frozen trajectory is authoritative. An early-stopped run gates on the **armed subset** (`EvaluationResult.armed_criteria_passed`); a completed run gates on the full set. Every unsupported use (non-observable criterion, non-Claude agent, wrong polarity, no armed criterion, simulation mode) is an error at resolution (plan *and* run), and a runtime verdict bug **fails open** to a full run. Surfaces: `EarlyStopInfo` (reason + deciding criterion + when), report notes/badges, `stopped_early` run.json rows, and `EarlyStopped`/`EarlyStopReason` telemetry dims. Defaults off ⇒ behavior byte-for-behavior unchanged.
141
143
 
142
144
  ## Success Criteria (14 types)
143
145
 
@@ -158,7 +160,7 @@ templates/ # Sandbox template directories
158
160
  | `llm_judge` | Continuous | LLM grades artifacts + optional trajectory + optional reference; routes through the run's backend (Bedrock / Anthropic) |
159
161
  | `agent_judge` | Continuous | Spawns a Claude Code SDK agent in an isolated sandbox copy; judge uses tools (Bash/Read/Grep/…) to investigate and returns a JSON verdict. Expensive; runs with evaluator credentials — see SECURITY note in the criterion docstring. |
160
162
 
161
- All criteria support `weight` (default 1.0) and `pass_threshold` (default 0.9). On dataset-backed tasks, criteria may also set `suite_thresholds: {metric: min_value}` — the suite gate passes iff every listed metric (from the criterion's `aggregate()` output) meets its minimum.
163
+ All criteria support `weight` (default 1.0) and `pass_threshold` (default 0.9), plus `stop_when` (`pass`/`fail`/`decided`, default `null`) which arms the criterion for early stop when `run_limits.stop_early` is set (observable criteria only). On dataset-backed tasks, criteria may also set `suite_thresholds: {metric: min_value}` — the suite gate passes iff every listed metric (from the criterion's `aggregate()` output) meets its minimum.
162
164
 
163
165
  ## Evaluation Flow
164
166
 
@@ -191,11 +193,11 @@ make format # ruff format
191
193
  make check # ruff check (lint)
192
194
  make typecheck # pyright
193
195
  make test # pytest
194
- make lint # custom architectural lint rules (CE001–CE013)
196
+ make lint # custom architectural lint rules (CE001–CE025)
195
197
  make verify # All of the above + coverage check (CI equivalent)
196
198
  ```
197
199
 
198
- When fixing a bug, ask: *could a custom lint rule have prevented this?* If the root cause is a mechanically detectable pattern (e.g., "always import from `coder_eval.models`", "never call blocking IO in async"), add a rule to `tests/lint/rules/` following the CE001–CE013 pattern and wire it up in `tests/lint/runner.py`. This turns a one-time fix into permanent enforcement. See `tests/test_custom_lint.py` for how rules are tested.
200
+ When fixing a bug, ask: *could a custom lint rule have prevented this?* If the root cause is a mechanically detectable pattern (e.g., "always import from `coder_eval.models`", "never call blocking IO in async"), add a rule to `tests/lint/rules/` following the CE001–CE025 pattern and wire it up in `tests/lint/runner.py`. This turns a one-time fix into permanent enforcement. See `tests/test_custom_lint.py` for how rules are tested.
199
201
 
200
202
  ## Configuration
201
203
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coder-eval
3
- Version: 0.8.3
3
+ Version: 0.8.4
4
4
  Summary: Evaluate, benchmark, and A/B-test AI coding agents (Claude Code, Codex, Gemini/Antigravity) with sandboxed, reproducible YAML task suites.
5
5
  Project-URL: Homepage, https://github.com/UiPath/coder_eval
6
6
  Project-URL: Repository, https://github.com/UiPath/coder_eval
@@ -27,6 +27,7 @@ Requires-Dist: anthropic>=0.86.0
27
27
  Requires-Dist: anyio>=4.13.0
28
28
  Requires-Dist: azure-monitor-opentelemetry-exporter<1.1.0,>=1.0.0b30
29
29
  Requires-Dist: claude-agent-sdk>=0.2.82
30
+ Requires-Dist: click>=8.3.3
30
31
  Requires-Dist: jmespath>=1.1.0
31
32
  Requires-Dist: jsonschema>=4.26.0
32
33
  Requires-Dist: opentelemetry-sdk<2.0.0,>=1.30.0
@@ -59,7 +60,7 @@ Provides-Extra: uipath
59
60
  Requires-Dist: uipath>=2.10.31; extra == 'uipath'
60
61
  Description-Content-Type: text/markdown
61
62
 
62
- # coder_eval — evaluate & benchmark AI coding agents
63
+ # coder_eval — evaluate AI coding agents & their skills
63
64
 
64
65
  [![PyPI](https://img.shields.io/pypi/v/coder-eval.svg)](https://pypi.org/project/coder-eval/)
65
66
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
@@ -67,6 +68,11 @@ Description-Content-Type: text/markdown
67
68
  [![CI](https://github.com/UiPath/coder_eval/actions/workflows/pr-checks.yml/badge.svg)](https://github.com/UiPath/coder_eval/actions/workflows/pr-checks.yml)
68
69
  [![Code style: Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
69
70
 
71
+ A framework for evaluating AI coding agents **and their skills** — built for CLI
72
+ and skill builders — with sandboxing, reproducibility, and data-driven analysis.
73
+ Not an "agentic coding" benchmark: it measures how effective your CLI and skills
74
+ are when used by coding agents.
75
+
70
76
  <p align="center">
71
77
  <img src="docs/assets/hero.gif" alt="coder_eval running the hello_date task: a sandboxed agent writes and runs a script from a YAML task, then the scored result is browsed in evalboard" width="100%">
72
78
  </p>
@@ -1,4 +1,4 @@
1
- # coder_eval — evaluate & benchmark AI coding agents
1
+ # coder_eval — evaluate AI coding agents & their skills
2
2
 
3
3
  [![PyPI](https://img.shields.io/pypi/v/coder-eval.svg)](https://pypi.org/project/coder-eval/)
4
4
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
@@ -6,6 +6,11 @@
6
6
  [![CI](https://github.com/UiPath/coder_eval/actions/workflows/pr-checks.yml/badge.svg)](https://github.com/UiPath/coder_eval/actions/workflows/pr-checks.yml)
7
7
  [![Code style: Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
8
8
 
9
+ A framework for evaluating AI coding agents **and their skills** — built for CLI
10
+ and skill builders — with sandboxing, reproducibility, and data-driven analysis.
11
+ Not an "agentic coding" benchmark: it measures how effective your CLI and skills
12
+ are when used by coding agents.
13
+
9
14
  <p align="center">
10
15
  <img src="docs/assets/hero.gif" alt="coder_eval running the hello_date task: a sandboxed agent writes and runs a script from a YAML task, then the scored result is browsed in evalboard" width="100%">
11
16
  </p>
@@ -17,6 +17,7 @@ to the orchestrator are involved.
17
17
  - [Recipe: A/B a Skill](#recipe-ab-a-skill)
18
18
  - [Recipe: A/B a Model](#recipe-ab-a-model)
19
19
  - [Recipe: A/B a Prompt](#recipe-ab-a-prompt)
20
+ - [Recipe: Smoke vs. e2e Flavors (Early Stop)](#recipe-smoke-vs-e2e-flavors-early-stop)
20
21
  - [Replicates (Statistical Power)](#replicates-statistical-power)
21
22
  - [Measuring the Difference](#measuring-the-difference)
22
23
  - [CLI Reference](#cli-reference)
@@ -222,6 +223,39 @@ variants:
222
223
  The full mutation catalog (prefix / suffix / replace / template / rephrase) is
223
224
  defined in `coder_eval/models/mutations.py`.
224
225
 
226
+ ## Recipe: Smoke vs. e2e Flavors (Early Stop)
227
+
228
+ Run the **same** task file as both a fast `smoke` flavor and a full `e2e` flavor
229
+ by flipping one boolean per variant — `run_limits.stop_early`. Arm the criteria
230
+ that define "the interesting thing happened" with `stop_when` in the task file;
231
+ the `smoke` variant cuts off as soon as they're decided, while `e2e` runs to
232
+ completion. Because the field merge is per-key, the variant sets only
233
+ `stop_early` without disturbing the task's `max_turns`.
234
+
235
+ ```yaml
236
+ experiment_id: early-stop-ab
237
+ description: "Smoke vs. e2e from one file via opt-in early stop"
238
+
239
+ variants:
240
+ - variant_id: e2e
241
+ run_limits:
242
+ stop_early: false # full run to completion (the reference flavor)
243
+ - variant_id: smoke
244
+ run_limits:
245
+ stop_early: true # cut off once the armed criteria are decided
246
+ ```
247
+
248
+ The task file supplies the arming (`stop_when` on the criteria that gate the
249
+ flavor) and a `max_turns` generous enough for `e2e`; see
250
+ [`stop_early`](TASK_DEFINITION_GUIDE.md#stop_early-opt-in-early-stop). This recipe
251
+ ships as `experiments/early-stop-ab.yaml`.
252
+
253
+ Expect **identical pass/fail verdicts** between the two variants — an
254
+ early-stopped run is gated on the armed subset only, and the non-armed criteria
255
+ become advisory (clearly marked in the report), so the `smoke` flavor can't
256
+ "pass for free" — with the `smoke` variant significantly lower on turns,
257
+ duration, and tokens.
258
+
225
259
  ## Replicates (Statistical Power)
226
260
 
227
261
  Agents are stochastic — a single run per arm is noise, not signal. Set `repeats`
@@ -192,6 +192,61 @@ budgets consistently across a suite — the headline % is only comparable when
192
192
  tasks are measured against realistic, like-for-like targets. Omit it (the
193
193
  default) to exclude a task from the metric entirely.
194
194
 
195
+ ### `stop_early` (opt-in early stop)
196
+
197
+ `run_limits.stop_early` (default `false`) ends a single-shot run **early** once
198
+ the run's **armed** criteria are decided — so you can raise `max_turns` for the
199
+ full-run flavor without paying for turns the smoke flavor doesn't need. A
200
+ criterion is *armed* by giving it a `stop_when` (see the criterion-fields table);
201
+ `stop_early` is the master switch that turns arming on for the run.
202
+
203
+ ```yaml
204
+ run_limits:
205
+ max_turns: 30
206
+ stop_early: true # opt in; default false leaves behavior unchanged
207
+ success_criteria:
208
+ - type: skill_triggered
209
+ skill_name: date-teller
210
+ expected_skill: date-teller
211
+ stop_when: decided # arm on pass OR definitive fail
212
+ - type: file_exists # not armed → advisory on an early-stopped run
213
+ path: report.md
214
+ ```
215
+
216
+ Semantics:
217
+
218
+ - **Opt-in, per run.** With `stop_early: false` (the default) the run behaves
219
+ exactly as before — `stop_when` is inert and every criterion gates normally.
220
+ - **Polarity.** `stop_when: pass` stops the moment all armed criteria are decided
221
+ in the pass direction; `stop_when: fail` stops on a definitive wrong-signal
222
+ fail; `stop_when: decided` stops on either. Only criteria that can decide from a
223
+ partial trajectory (currently `skill_triggered`, `command_executed`) may be
224
+ armed — arming any other criterion is a hard error at resolution (plan *and*
225
+ run), never a silent no-op. Decidability can also depend on a criterion's own
226
+ fields: `command_executed` can live-**pass** only with `max_count` unset and
227
+ `min_count > 0`, and live-**fail** only with `max_count` set (which includes
228
+ the `min_count: 0, max_count: 0` "must-NOT-run" form). Arming a polarity the
229
+ configured criterion can never reach (e.g. `stop_when: pass` alongside a
230
+ `max_count`) is likewise a hard error at resolution, not a silent full run.
231
+ - **Verdict.** An early-stopped run is gated on the **armed subset only**; the
232
+ non-armed criteria become **advisory** and are clearly marked (report badge +
233
+ per-criterion note + `stopped_early` row). A run that completes naturally is
234
+ gated on the **full** set, as always. This is what lets one file serve both a
235
+ `smoke` flavor (`stop_early: true`) and an `e2e` flavor (`stop_early: false`)
236
+ with identical verdicts — see [AB_EXPERIMENTS.md](AB_EXPERIMENTS.md).
237
+ - **Fail-safe.** A live-verdict bug **fails open** to a full run (logged loudly) —
238
+ it can never silently disable a criterion or cause a false early stop.
239
+
240
+ Observability (every early-stopped run is flagged everywhere so analysis never
241
+ compares a truncated run against a full one):
242
+
243
+ | Surface | Field / marker |
244
+ |---------|----------------|
245
+ | `run.json` row | `stopped_early`, `early_stop_reason`, `turns_remaining_at_stop` |
246
+ | `run.md` | `> **NOTE:** […] stopped early (<reason>); <= N turn(s) avoided …` |
247
+ | `task.html` | header badge `stopped early (<reason>)` + `advisory — not gated` markers |
248
+ | Telemetry | `EarlyStopped` / `EarlyStopReason` dimensions on `CoderEval.Task.End` |
249
+
195
250
  ## Sandbox Configuration
196
251
 
197
252
  The `sandbox` block is optional. When omitted, it defaults to `driver: "tempdir"` with standard Python environment.
@@ -319,6 +374,7 @@ All criteria share these fields:
319
374
  | `description` | — | Human-readable description (required) |
320
375
  | `weight` | 1.0 | Relative importance for weighted score |
321
376
  | `pass_threshold` | 0.9 | Minimum score (0.0–1.0) to pass |
377
+ | `stop_when` | `null` | Arms this criterion for early stop (`pass`/`fail`/`decided`); requires `run_limits.stop_early: true` and an observable criterion type (`skill_triggered`, `command_executed`). See [`stop_early`](#stop_early-opt-in-early-stop). |
322
378
 
323
379
  **Scoring types:**
324
380
  - **Binary** (1.0 or 0.0): `file_exists`, `run_command`, `file_matches_regex`
@@ -95,6 +95,7 @@ created are preserved under `runs/latest/<variant>/<task>/<NN>/` (`task.json`,
95
95
  ## Where to go deeper
96
96
 
97
97
  - **All 14 criterion types, weights, thresholds** → [Task Definition Guide](../TASK_DEFINITION_GUIDE.md)
98
+ - **Stop a run early once the key criteria are decided** (opt-in `run_limits.stop_early` + `stop_when` on a criterion) → [Task Definition Guide → `stop_early`](../TASK_DEFINITION_GUIDE.md#stop_early-opt-in-early-stop)
98
99
  - **Fan one task out over a dataset of rows** → [Bring Your Own Data](../BYOD.md)
99
100
  - **Full CLI & config reference** → [User Guide](../USER_GUIDE.md)
100
101
  - **Compare two configurations on this task** → [Tutorial 05](05-comparing-models.md)
@@ -0,0 +1,120 @@
1
+ import { describe, expect, test, vi, beforeEach, afterEach } from "vitest";
2
+ import { render, screen, act, fireEvent } from "@testing-library/react";
3
+
4
+ // vi.hoisted ensures these are initialized before vi.mock hoists its factory.
5
+ const { mockReplace, navState } = vi.hoisted(() => ({
6
+ mockReplace: vi.fn(),
7
+ navState: { q: "" as string },
8
+ }));
9
+
10
+ vi.mock("next/navigation", () => ({
11
+ useRouter: () => ({ replace: mockReplace }),
12
+ usePathname: () => "/",
13
+ useSearchParams: () => new URLSearchParams(navState.q ? `q=${navState.q}` : ""),
14
+ }));
15
+
16
+ const { SearchBox } = await import("../search-box");
17
+
18
+ describe("SearchBox — typing-ahead race condition", () => {
19
+ beforeEach(() => {
20
+ vi.useFakeTimers();
21
+ mockReplace.mockClear();
22
+ navState.q = "";
23
+ });
24
+ afterEach(() => {
25
+ vi.useRealTimers();
26
+ });
27
+
28
+ test("preserves in-progress input when a navigation resolves mid-typing", () => {
29
+ // Reproduces the race: user types "foo" → debounce fires → user types
30
+ // more → navigation for "foo" resolves → input must NOT reset to "foo".
31
+ const { rerender } = render(<SearchBox />);
32
+ const input = screen.getByRole("textbox");
33
+
34
+ fireEvent.change(input, { target: { value: "foo" } });
35
+
36
+ // Debounce fires; typingAhead becomes false.
37
+ act(() => { vi.advanceTimersByTime(300); });
38
+ expect(mockReplace).toHaveBeenCalledOnce();
39
+
40
+ // User types more before the navigation resolves.
41
+ fireEvent.change(input, { target: { value: "foobar" } });
42
+
43
+ // Navigation for "foo" resolves — URL now reports "foo".
44
+ navState.q = "foo";
45
+ rerender(<SearchBox />);
46
+
47
+ // typingAhead is true, so the sync effect must NOT overwrite the input.
48
+ expect(input).toHaveValue("foobar");
49
+ });
50
+
51
+ test("syncs from URL when the user is not typing (external navigation)", () => {
52
+ // Back/forward nav or a tag click should still update the input when the
53
+ // user hasn't typed anything since the last URL write.
54
+ const { rerender } = render(<SearchBox />);
55
+ const input = screen.getByRole("textbox");
56
+
57
+ navState.q = "tag:alpha";
58
+ rerender(<SearchBox />);
59
+
60
+ expect(input).toHaveValue("tag:alpha");
61
+ });
62
+
63
+ test("clears the input when the URL is cleared externally", () => {
64
+ navState.q = "foo";
65
+ const { rerender } = render(<SearchBox />);
66
+ const input = screen.getByRole("textbox");
67
+
68
+ expect(input).toHaveValue("foo");
69
+
70
+ navState.q = "";
71
+ rerender(<SearchBox />);
72
+
73
+ expect(input).toHaveValue("");
74
+ });
75
+
76
+ test("clear button does not get repopulated when a stale navigation resolves", () => {
77
+ // The PR's named fix: user clicks × to clear a settled search, then a
78
+ // navigation that had already resolved with the old value re-renders the
79
+ // component — the input must stay empty, not snap back to the old value.
80
+ navState.q = "foo";
81
+ const { rerender } = render(<SearchBox />);
82
+ const input = screen.getByRole("textbox");
83
+ expect(input).toHaveValue("foo");
84
+
85
+ // User clicks ×.
86
+ fireEvent.click(screen.getByRole("button", { name: /clear search/i }));
87
+ expect(input).toHaveValue("");
88
+
89
+ // A stale navigation reports q="foo" — must NOT repopulate the input.
90
+ navState.q = "foo";
91
+ rerender(<SearchBox />);
92
+
93
+ expect(input).toHaveValue("");
94
+ });
95
+
96
+ test("typingAhead latch releases after the debounce fires so later external nav syncs", () => {
97
+ // Guards against a stuck-true latch: after the debounce settles (user
98
+ // stops typing, timer fires, typingAhead → false), a subsequent genuine
99
+ // external navigation must still update the input.
100
+ const { rerender } = render(<SearchBox />);
101
+ const input = screen.getByRole("textbox");
102
+
103
+ fireEvent.change(input, { target: { value: "foo" } });
104
+
105
+ // Let the debounce fire — typingAhead resets to false.
106
+ act(() => { vi.advanceTimersByTime(300); });
107
+
108
+ // Simulate the navigation resolving (URL catches up).
109
+ navState.q = "foo";
110
+ rerender(<SearchBox />);
111
+ expect(input).toHaveValue("foo");
112
+
113
+ // Now a genuine external navigation changes q (e.g. browser Back).
114
+ navState.q = "bar";
115
+ rerender(<SearchBox />);
116
+
117
+ // typingAhead is false, so the sync must apply.
118
+ expect(input).toHaveValue("bar");
119
+ });
120
+ });
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { usePathname, useRouter, useSearchParams } from "next/navigation";
4
- import { useEffect, useState } from "react";
4
+ import { useEffect, useRef, useState } from "react";
5
5
 
6
6
  const Q_DEBOUNCE_MS = 300;
7
7
 
@@ -18,18 +18,31 @@ export function SearchBox({
18
18
 
19
19
  const urlQ = searchParams.get("q") ?? "";
20
20
  const [q, setQ] = useState(urlQ);
21
+ // Invariant: true iff local input is ahead of the last URL write.
22
+ // Written in three places by the debounce effect (cleared on catch-up at
23
+ // the early-return, set when a new timer arms, cleared when the timer
24
+ // fires). Read by the sync effect to decide whether to accept a URL change.
25
+ const typingAhead = useRef(false);
21
26
 
22
27
  // Sync local state when the URL changes externally (back/forward, link
23
- // clicks). The debounced write below early-returns when state and URL
24
- // agree, so this can't loop.
28
+ // clicks). Skipped while the user is ahead of the URL to avoid clobbering
29
+ // in-progress input with a stale value from a just-resolved navigation.
30
+ // Note: external q changes that arrive during an active debounce window are
31
+ // intentionally deferred — the user's in-progress typing takes priority.
25
32
  useEffect(() => {
33
+ if (typingAhead.current) return;
26
34
  setQ((prev) => (prev.trim() === urlQ ? prev : urlQ));
27
35
  }, [urlQ]);
28
36
 
29
37
  useEffect(() => {
30
38
  const trimmed = q.trim();
31
- if (trimmed === urlQ) return;
39
+ if (trimmed === urlQ) {
40
+ typingAhead.current = false;
41
+ return;
42
+ }
43
+ typingAhead.current = true;
32
44
  const timer = setTimeout(() => {
45
+ typingAhead.current = false;
33
46
  // Read the live URL at fire time so a concurrent write (e.g. a
34
47
  // tag click that landed during the debounce) isn't clobbered.
35
48
  const params = new URLSearchParams(window.location.search);
@@ -40,6 +53,9 @@ export function SearchBox({
40
53
  scroll: false,
41
54
  });
42
55
  }, Q_DEBOUNCE_MS);
56
+ // Don't reset typingAhead in cleanup — cleanup fires on any dep change
57
+ // (q, urlQ, pathname, router). The effect body re-run re-establishes
58
+ // the correct value: false on catch-up, true when a new timer arms.
43
59
  return () => clearTimeout(timer);
44
60
  }, [q, urlQ, pathname, router]);
45
61
 
@@ -0,0 +1,23 @@
1
+ experiment_id: early-stop-ab
2
+ description: |
3
+ Smoke vs. e2e flavors from ONE task file via opt-in early-stop. Both variants
4
+ share the same tasks, criteria, and max_turns; they differ only in the
5
+ run_limits.stop_early boolean (field-merged, so neither replaces the task's
6
+ run_limits block). The task's armed criteria (those carrying `stop_when`)
7
+ decide when the `smoke` variant cuts off — as soon as the designated criteria
8
+ are decided — while `e2e` runs every task to completion.
9
+
10
+ Expect identical pass/fail verdicts between the two variants (the armed subset
11
+ gates an early-stopped run; other criteria are advisory and clearly marked),
12
+ with the `smoke` variant significantly lower on turns, duration, and tokens.
13
+
14
+ variants:
15
+ - variant_id: e2e
16
+ description: "Full run to completion — no early stop (the reference flavor)."
17
+ run_limits:
18
+ stop_early: false
19
+
20
+ - variant_id: smoke
21
+ description: "Opt-in early stop — cut off once the armed criteria are decided."
22
+ run_limits:
23
+ stop_early: true
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "coder-eval"
3
- version = "0.8.3"
3
+ version = "0.8.4"
4
4
  description = "Evaluate, benchmark, and A/B-test AI coding agents (Claude Code, Codex, Gemini/Antigravity) with sandboxed, reproducible YAML task suites."
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -30,6 +30,7 @@ dependencies = [
30
30
  "pydantic-settings>=2.14.2",
31
31
  "pyyaml>=6.0.3",
32
32
  "typer>=0.24.1",
33
+ "click>=8.3.3",
33
34
  "rich>=14.3.3",
34
35
  "python-dotenv>=1.2.2",
35
36
  "anthropic>=0.86.0",
@@ -1,3 +1,3 @@
1
1
  """coder_eval - A framework for evaluating AI coding agents."""
2
2
 
3
- __version__ = "0.8.3"
3
+ __version__ = "0.8.4"
@@ -5,7 +5,8 @@
5
5
 
6
6
  import logging
7
7
  from abc import ABC, abstractmethod
8
- from typing import Any, NoReturn, Protocol
8
+ from collections.abc import Callable
9
+ from typing import Any, ClassVar, NoReturn, Protocol
9
10
 
10
11
  from .errors import AgentCrashError, TurnTimeoutError
11
12
  from .errors.agent import format_timeout_reason, truncate_crash_message
@@ -71,6 +72,13 @@ class Agent[ConfigT: BaseAgentConfig](ABC):
71
72
  _iteration: int = 0
72
73
  _iteration_was_incremented: bool = False
73
74
 
75
+ # Capability flag: whether this agent honors the cooperative ``should_stop``
76
+ # interrupt threaded through ``communicate()`` (early-stop-on-criterion).
77
+ # Default False — arming early-stop on an agent that does not set this True
78
+ # is rejected at resolution time. Concrete agents that check ``should_stop``
79
+ # between messages override it to True.
80
+ supports_cooperative_stop: ClassVar[bool] = False
81
+
74
82
  def _begin_turn(self) -> None:
75
83
  """Mark the start of a ``communicate()`` turn: reset the pending slot and
76
84
  bump the iteration counter so a mid-turn failure can be rolled back.
@@ -183,6 +191,7 @@ class Agent[ConfigT: BaseAgentConfig](ABC):
183
191
  stream_callback: StreamCallback | None = None,
184
192
  timeout: float | None = None,
185
193
  max_turns: int | None = None,
194
+ should_stop: Callable[[], bool] | None = None,
186
195
  ) -> TurnRecord:
187
196
  """Send a message to the agent and receive its response.
188
197
 
@@ -198,6 +207,15 @@ class Agent[ConfigT: BaseAgentConfig](ABC):
198
207
  ``communicate()`` call. When the agent would exceed it, the
199
208
  returned ``TurnRecord`` has ``max_turns_exhausted=True``.
200
209
  None defers to the underlying SDK default.
210
+ should_stop: Cooperative early-stop poll for early-stop-on-criterion.
211
+ When provided, an implementation that supports cooperative
212
+ stopping (``supports_cooperative_stop=True``) should call it at
213
+ each safe message boundary and, when it returns True, stop
214
+ pulling further work and finalize the turn cleanly
215
+ (``crashed=False``, no raise). ``None`` (default) preserves the
216
+ pre-existing behavior exactly. Agents that do not support it
217
+ accept the argument and ignore it (the orchestrator only passes
218
+ it to a capable agent).
201
219
 
202
220
  Returns:
203
221
  TurnRecord containing the complete interaction
@@ -23,7 +23,7 @@ import contextlib
23
23
  import logging
24
24
  import os
25
25
  import time
26
- from collections.abc import AsyncIterator
26
+ from collections.abc import AsyncIterator, Callable
27
27
  from contextlib import AsyncExitStack
28
28
  from datetime import datetime
29
29
  from pathlib import Path
@@ -409,9 +409,15 @@ class AntigravityAgent(Agent[AntigravityAgentConfig]):
409
409
  stream_callback: StreamCallback | None = None,
410
410
  timeout: float | None = None,
411
411
  max_turns: int | None = None,
412
+ should_stop: Callable[[], bool] | None = None,
412
413
  ) -> TurnRecord:
413
414
  """Send a message to the Antigravity agent and receive its response.
414
415
 
416
+ ``should_stop`` is accepted for ``Agent.communicate`` override
417
+ compatibility and ignored — Antigravity does not support cooperative
418
+ early-stop (``supports_cooperative_stop`` is False), so the orchestrator
419
+ never passes it.
420
+
415
421
  Drives one logical turn: ``conversation.send(prompt)`` then iterate
416
422
  ``receive_steps()`` until the turn goes idle, mapping the Gemini step
417
423
  stream onto the standardized event protocol.