auditable 0.3.0__tar.gz → 0.4.0__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 (207) hide show
  1. auditable-0.4.0/CHANGELOG.md +42 -0
  2. {auditable-0.3.0 → auditable-0.4.0}/PKG-INFO +126 -14
  3. {auditable-0.3.0 → auditable-0.4.0}/README.md +119 -13
  4. {auditable-0.3.0 → auditable-0.4.0}/examples/README.md +30 -0
  5. auditable-0.4.0/examples/example_add_your_method.py +68 -0
  6. auditable-0.4.0/examples/example_leaderboard.py +41 -0
  7. auditable-0.4.0/examples/leaderboard.ipynb +275 -0
  8. {auditable-0.3.0 → auditable-0.4.0}/pyproject.toml +5 -1
  9. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/__init__.py +1 -1
  10. auditable-0.4.0/src/auditable/bench/__init__.py +16 -0
  11. auditable-0.4.0/src/auditable/bench/__main__.py +66 -0
  12. auditable-0.4.0/src/auditable/bench/_core.py +417 -0
  13. auditable-0.4.0/src/auditable/bench/corpora/__init__.py +8 -0
  14. auditable-0.4.0/src/auditable/bench/corpora/pre.py +73 -0
  15. auditable-0.4.0/src/auditable/bench/corpora/swegym.py +55 -0
  16. auditable-0.4.0/src/auditable/bench/corpora/tau.py +92 -0
  17. auditable-0.4.0/src/auditable/bench/corpora/whoandwhen.py +94 -0
  18. auditable-0.4.0/src/auditable/bench/data/llm_judge/README.md +44 -0
  19. auditable-0.4.0/src/auditable/bench/data/llm_judge/legacy_run_keys.json +131 -0
  20. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__all_at_once__claude-opus-4.8.json +1869 -0
  21. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__all_at_once__deepseek-r1.json +1839 -0
  22. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__all_at_once__gemini.json +1723 -0
  23. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__all_at_once__gemma-3-12b.json +1758 -0
  24. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__all_at_once__gpt-5.4.json +1869 -0
  25. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__all_at_once__gpt-5.5.json +1869 -0
  26. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__all_at_once__gpt-oss-20b.json +1741 -0
  27. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__all_at_once__llama-3.3-70b.json +1869 -0
  28. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__all_at_once__mistral-small.json +1602 -0
  29. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__all_at_once__nova-micro.json +1439 -0
  30. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__all_at_once__qwen3-32b.json +1854 -0
  31. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__binary_search__claude-opus-4.8.json +896 -0
  32. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__binary_search__deepseek-r1.json +896 -0
  33. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__binary_search__gemini.json +896 -0
  34. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__binary_search__gemma-3-12b.json +896 -0
  35. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__binary_search__gpt-5.4.json +896 -0
  36. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__binary_search__gpt-5.5.json +896 -0
  37. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__binary_search__llama-3.3-70b.json +896 -0
  38. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__binary_search__mistral-small.json +896 -0
  39. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__binary_search__nova-micro.json +896 -0
  40. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__binary_search__qwen3-32b.json +896 -0
  41. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__step_by_step__claude-opus-4.8.json +896 -0
  42. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__step_by_step__deepseek-r1.json +896 -0
  43. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__step_by_step__gemini.json +896 -0
  44. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__step_by_step__gemma-3-12b.json +896 -0
  45. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__step_by_step__gpt-5.4.json +896 -0
  46. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__step_by_step__gpt-5.5.json +896 -0
  47. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__step_by_step__llama-3.3-70b.json +896 -0
  48. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__step_by_step__mistral-small.json +896 -0
  49. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__step_by_step__nova-micro.json +896 -0
  50. auditable-0.4.0/src/auditable/bench/data/llm_judge/whoandwhen__step_by_step__qwen3-32b.json +896 -0
  51. auditable-0.4.0/src/auditable/bench/data/pre/README.md +17 -0
  52. auditable-0.4.0/src/auditable/bench/data/pre/llm_judge_method/llama-3.3-70b.json +4757 -0
  53. auditable-0.4.0/src/auditable/bench/golden/detect__swegym.json +100 -0
  54. auditable-0.4.0/src/auditable/bench/golden/detect__tau.json +105 -0
  55. auditable-0.4.0/src/auditable/bench/golden/live__swegym.json +80 -0
  56. auditable-0.4.0/src/auditable/bench/golden/live__tau.json +80 -0
  57. auditable-0.4.0/src/auditable/bench/golden/localize__whoandwhen.json +42 -0
  58. auditable-0.4.0/src/auditable/bench/golden/localize__whoandwhen__llm.json +197 -0
  59. auditable-0.4.0/src/auditable/bench/golden/pre__over_privilege.json +157 -0
  60. auditable-0.4.0/src/auditable/bench/llm_rows.py +421 -0
  61. auditable-0.4.0/src/auditable/bench/protocols.py +118 -0
  62. auditable-0.4.0/src/auditable/bench/protocols_config.py +76 -0
  63. auditable-0.4.0/src/auditable/bench/protocols_live.py +109 -0
  64. auditable-0.4.0/src/auditable/bench/protocols_step.py +133 -0
  65. auditable-0.4.0/src/auditable/bench/tasks/__init__.py +5 -0
  66. auditable-0.4.0/src/auditable/bench/tasks/detect.py +64 -0
  67. auditable-0.4.0/src/auditable/bench/tasks/live.py +112 -0
  68. auditable-0.4.0/src/auditable/bench/tasks/localize.py +112 -0
  69. auditable-0.4.0/src/auditable/bench/tasks/pre.py +219 -0
  70. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/run/supervised.py +46 -0
  71. auditable-0.4.0/tests/test_bench_core.py +284 -0
  72. auditable-0.4.0/tests/test_bench_extras.py +25 -0
  73. auditable-0.4.0/tests/test_bench_golden_coverage.py +174 -0
  74. auditable-0.4.0/tests/test_bench_live.py +137 -0
  75. auditable-0.4.0/tests/test_bench_llm_rows.py +203 -0
  76. auditable-0.4.0/tests/test_bench_localize.py +185 -0
  77. auditable-0.4.0/tests/test_bench_pre.py +325 -0
  78. auditable-0.4.0/tests/test_bench_protocols.py +203 -0
  79. auditable-0.4.0/tests/test_bench_swegym_selection.py +132 -0
  80. auditable-0.4.0/tests/test_bench_tau.py +109 -0
  81. auditable-0.4.0/tests/test_methods_spline_size.py +46 -0
  82. auditable-0.3.0/CHANGELOG.md +0 -28
  83. {auditable-0.3.0 → auditable-0.4.0}/.gitignore +0 -0
  84. {auditable-0.3.0 → auditable-0.4.0}/LICENSE +0 -0
  85. {auditable-0.3.0 → auditable-0.4.0}/examples/example_agentpile.py +0 -0
  86. {auditable-0.3.0 → auditable-0.4.0}/examples/example_audit_report.py +0 -0
  87. {auditable-0.3.0 → auditable-0.4.0}/examples/example_end_to_end.py +0 -0
  88. {auditable-0.3.0 → auditable-0.4.0}/examples/example_langchain_capture.py +0 -0
  89. {auditable-0.3.0 → auditable-0.4.0}/examples/example_langgraph_capture.py +0 -0
  90. {auditable-0.3.0 → auditable-0.4.0}/examples/example_langgraph_live_replay.py +0 -0
  91. {auditable-0.3.0 → auditable-0.4.0}/examples/example_langgraph_llm_agent.py +0 -0
  92. {auditable-0.3.0 → auditable-0.4.0}/examples/example_live_monitor.py +0 -0
  93. {auditable-0.3.0 → auditable-0.4.0}/examples/example_live_replay.py +0 -0
  94. {auditable-0.3.0 → auditable-0.4.0}/examples/example_mcp_capture.py +0 -0
  95. {auditable-0.3.0 → auditable-0.4.0}/examples/example_methods.py +0 -0
  96. {auditable-0.3.0 → auditable-0.4.0}/examples/example_payment_audit.py +0 -0
  97. {auditable-0.3.0 → auditable-0.4.0}/examples/example_post_rank_run.py +0 -0
  98. {auditable-0.3.0 → auditable-0.4.0}/examples/example_pre_lint_plan.py +0 -0
  99. {auditable-0.3.0 → auditable-0.4.0}/examples/example_standalone_report.py +0 -0
  100. {auditable-0.3.0 → auditable-0.4.0}/examples/example_state_anomaly.py +0 -0
  101. {auditable-0.3.0 → auditable-0.4.0}/examples/example_touch_capture.py +0 -0
  102. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/_report_figures.py +0 -0
  103. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/analysis.py +0 -0
  104. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/audit_report.py +0 -0
  105. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/base.py +0 -0
  106. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/chain.py +0 -0
  107. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/compound.py +0 -0
  108. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/data/__init__.py +0 -0
  109. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/data/inject.py +0 -0
  110. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/datasets.py +0 -0
  111. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/featurize/__init__.py +0 -0
  112. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/featurize/_grade_projection.py +0 -0
  113. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/featurize/agentpile.py +0 -0
  114. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/featurize/pyg.py +0 -0
  115. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/featurize/spec.py +0 -0
  116. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/featurize/step_deps.py +0 -0
  117. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/featurize/trace.py +0 -0
  118. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/featurize/who_when.py +0 -0
  119. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/graph/__init__.py +0 -0
  120. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/graph/adapters/__init__.py +0 -0
  121. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/graph/adapters/declared_plan.py +0 -0
  122. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/graph/adapters/own_record.py +0 -0
  123. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/graph/adapters/protocol.py +0 -0
  124. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/graph/adapters/tau_bench.py +0 -0
  125. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/graph/features.py +0 -0
  126. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/graph/grounding.py +0 -0
  127. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/graph/loader.py +0 -0
  128. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/graph/pre.py +0 -0
  129. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/graph/risk.py +0 -0
  130. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/graph/session.py +0 -0
  131. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/graph/touch.py +0 -0
  132. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/harness/__init__.py +0 -0
  133. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/integrations/__init__.py +0 -0
  134. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/integrations/langchain.py +0 -0
  135. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/integrations/langgraph.py +0 -0
  136. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/integrations/mcp.py +0 -0
  137. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/llm/__init__.py +0 -0
  138. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/llm/backend.py +0 -0
  139. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/llm/cache.py +0 -0
  140. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/llm/who_when.py +0 -0
  141. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/__init__.py +0 -0
  142. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/_pygod.py +0 -0
  143. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/config/__init__.py +0 -0
  144. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/config/llm.py +0 -0
  145. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/config/rules.py +0 -0
  146. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/online/__init__.py +0 -0
  147. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/online/rules.py +0 -0
  148. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/run/__init__.py +0 -0
  149. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/run/baselines.py +0 -0
  150. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/run/graph.py +0 -0
  151. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/run/pyod.py +0 -0
  152. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/step/__init__.py +0 -0
  153. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/step/graph.py +0 -0
  154. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/step/llm.py +0 -0
  155. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/step/rules.py +0 -0
  156. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/methods/step/supervised.py +0 -0
  157. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/model/__init__.py +0 -0
  158. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/record.py +0 -0
  159. {auditable-0.3.0 → auditable-0.4.0}/src/auditable/report.py +0 -0
  160. {auditable-0.3.0 → auditable-0.4.0}/tests/fixtures/agentpile_grade/README.md +0 -0
  161. {auditable-0.3.0 → auditable-0.4.0}/tests/fixtures/agentpile_grade/agent_reward_bench_records.json +0 -0
  162. {auditable-0.3.0 → auditable-0.4.0}/tests/fixtures/agentpile_grade/b_openhands_multi_call_turn.json +0 -0
  163. {auditable-0.3.0 → auditable-0.4.0}/tests/fixtures/agentpile_grade/swe_agent_synthetic.json +0 -0
  164. {auditable-0.3.0 → auditable-0.4.0}/tests/fixtures/grade_3839a57_features.json +0 -0
  165. {auditable-0.3.0 → auditable-0.4.0}/tests/test_adapters.py +0 -0
  166. {auditable-0.3.0 → auditable-0.4.0}/tests/test_agentpile_adapter.py +0 -0
  167. {auditable-0.3.0 → auditable-0.4.0}/tests/test_analysis.py +0 -0
  168. {auditable-0.3.0 → auditable-0.4.0}/tests/test_audit_report.py +0 -0
  169. {auditable-0.3.0 → auditable-0.4.0}/tests/test_auditors.py +0 -0
  170. {auditable-0.3.0 → auditable-0.4.0}/tests/test_basic.py +0 -0
  171. {auditable-0.3.0 → auditable-0.4.0}/tests/test_compound.py +0 -0
  172. {auditable-0.3.0 → auditable-0.4.0}/tests/test_data_inject.py +0 -0
  173. {auditable-0.3.0 → auditable-0.4.0}/tests/test_data_module.py +0 -0
  174. {auditable-0.3.0 → auditable-0.4.0}/tests/test_datasets.py +0 -0
  175. {auditable-0.3.0 → auditable-0.4.0}/tests/test_featurize.py +0 -0
  176. {auditable-0.3.0 → auditable-0.4.0}/tests/test_gate.py +0 -0
  177. {auditable-0.3.0 → auditable-0.4.0}/tests/test_graph.py +0 -0
  178. {auditable-0.3.0 → auditable-0.4.0}/tests/test_graph_execution_reach.py +0 -0
  179. {auditable-0.3.0 → auditable-0.4.0}/tests/test_graph_features.py +0 -0
  180. {auditable-0.3.0 → auditable-0.4.0}/tests/test_graph_loader.py +0 -0
  181. {auditable-0.3.0 → auditable-0.4.0}/tests/test_graph_risk.py +0 -0
  182. {auditable-0.3.0 → auditable-0.4.0}/tests/test_grounding.py +0 -0
  183. {auditable-0.3.0 → auditable-0.4.0}/tests/test_langchain_integration.py +0 -0
  184. {auditable-0.3.0 → auditable-0.4.0}/tests/test_langgraph_integration.py +0 -0
  185. {auditable-0.3.0 → auditable-0.4.0}/tests/test_langgraph_replay_bridge.py +0 -0
  186. {auditable-0.3.0 → auditable-0.4.0}/tests/test_live_session.py +0 -0
  187. {auditable-0.3.0 → auditable-0.4.0}/tests/test_llm.py +0 -0
  188. {auditable-0.3.0 → auditable-0.4.0}/tests/test_mcp_integration.py +0 -0
  189. {auditable-0.3.0 → auditable-0.4.0}/tests/test_methods_config.py +0 -0
  190. {auditable-0.3.0 → auditable-0.4.0}/tests/test_methods_graph.py +0 -0
  191. {auditable-0.3.0 → auditable-0.4.0}/tests/test_methods_pygod_step.py +0 -0
  192. {auditable-0.3.0 → auditable-0.4.0}/tests/test_methods_registry.py +0 -0
  193. {auditable-0.3.0 → auditable-0.4.0}/tests/test_methods_run_tabular.py +0 -0
  194. {auditable-0.3.0 → auditable-0.4.0}/tests/test_methods_slice.py +0 -0
  195. {auditable-0.3.0 → auditable-0.4.0}/tests/test_methods_step_rules.py +0 -0
  196. {auditable-0.3.0 → auditable-0.4.0}/tests/test_parity_consumption.py +0 -0
  197. {auditable-0.3.0 → auditable-0.4.0}/tests/test_pre.py +0 -0
  198. {auditable-0.3.0 → auditable-0.4.0}/tests/test_pre_coverage.py +0 -0
  199. {auditable-0.3.0 → auditable-0.4.0}/tests/test_public_api.py +0 -0
  200. {auditable-0.3.0 → auditable-0.4.0}/tests/test_replay.py +0 -0
  201. {auditable-0.3.0 → auditable-0.4.0}/tests/test_report.py +0 -0
  202. {auditable-0.3.0 → auditable-0.4.0}/tests/test_session_graph.py +0 -0
  203. {auditable-0.3.0 → auditable-0.4.0}/tests/test_session_graph_projection.py +0 -0
  204. {auditable-0.3.0 → auditable-0.4.0}/tests/test_sink.py +0 -0
  205. {auditable-0.3.0 → auditable-0.4.0}/tests/test_touch.py +0 -0
  206. {auditable-0.3.0 → auditable-0.4.0}/tests/test_touch_replay_bridge.py +0 -0
  207. {auditable-0.3.0 → auditable-0.4.0}/tests/test_version.py +0 -0
@@ -0,0 +1,42 @@
1
+ # Changelog
2
+
3
+ ## 0.4.0 (2026-11-14)
4
+
5
+ 0.4.0 adds leaderboards: `auditable.bench` reruns the tables of the CatchBench board on the same populations and protocols, and places any new method on them.
6
+
7
+ ### Added
8
+
9
+ - `auditable.bench`: `leaderboard(task_id, methods=None, extra=())` scores methods on a task and returns a ranked `Board` (`print`, `to_markdown()`, `to_dict()`, `compare_golden()`, `rank_of()`); `extra=[MyMethod]` adds a method that is not in the registry. A method whose extra is missing is listed as skipped with the extra named, and a method that raises is listed as an error while the rest of the board is still scored. Oracle rows, which read the labels, are shown as references and never ranked; control rows are ranked and marked.
10
+ - Six tasks, each reproducing a table of the CatchBench 0.1.3 board row by row: `detect/swegym` (376 runs) and `detect/tau` (660 runs), run-level failure detection by ROC-AUC; `live/swegym` and `live/tau`, early warning on 25, 50, 75 and 100 percent prefixes; `localize/whoandwhen` (126 failed runs), decisive-step localization by top-1, top-3 and MRR, including 31 LLM-judge rows replayed from CatchBench's committed prediction caches without an API call; and `pre/over_privilege` (1,187 configurations), configuration audit by F1, precision and recall, overall and per source. The populations are read through agentpile at the dataset revisions CatchBench pins, with the selection rules of GRADE commit 3839a57; the protocols are ported from CatchBench's adapters.
11
+ - `run.lr_spline_flat`, the flexible size control: a cubic spline of the four GRADE `flat` counts, then the board's logistic regression, ported from the `size (spline)` arm of CatchBench's size audits. It joins the `detect` and `live` boards as a control. On `detect/swegym` it ranks second, above both GRADE dependency regressions; on `detect/tau` it ranks below `run.lr_flatdep`. The library now holds 44 methods.
12
+ - Golden files with the board values of every row and the SHA-256 of the board they come from; the spline control's value comes from CatchBench's committed size audits instead, with a 0.001 tolerance. `python -m auditable.bench <task> --golden` compares a run with them and fails on a mismatch, on an error row, on a golden row left unchecked (skipped, missing a metric, absent from the task's default rows, or in a golden file that is missing), and on a run that compared no golden value; `--allow-skipped` accepts rows skipped for a missing extra. Three rows differ on macOS arm64 by a known platform effect and are reported as platform values; `--exact` counts them as mismatches, and the weekly Linux run uses it.
13
+ - `python -m auditable.bench`, the command-line entry: lists the tasks, prints a board, or emits it as Markdown or JSON.
14
+ - The `bench` extra (`pyod`, `scikit-learn`, `numpy`, `networkx`, `agentpile[hf]`); the graph rows also need `graph-ad`.
15
+ - CI: a `bench-core` job runs the bench unit tests, which download nothing, a weekly `bench golden` workflow reruns every task on Linux against its golden file, and a weekly `bench platforms` workflow installs the package from a clean checkout on Linux, macOS, and Windows (Python 3.10 and 3.13) with the README's graph-ad steps and checks three tasks against their golden files.
16
+
17
+ ## 0.3.0 (2026-10-25)
18
+
19
+ 0.3.0 turns `auditable` into a library of auditing methods for AI agents, with one interface per family and the ability to read public agent traces through agentpile.
20
+
21
+ ### Added
22
+
23
+ - `auditable.methods`: 43 methods in four families, each with one interface. The `config` family (8 methods) audits an agent configuration before a run, `online` (5) raises causal alarms while a run streams, and `run` (16) and `step` (14) detect a failed run and localize its decisive step afterwards. A registry (`list_methods`, `get_method`) returns each method's `MethodCard`, which records its fit scope, fidelity to its source, required fields, extras and citations. The library holds baselines from the literature (PyOD and PyGOD detectors, GUARDIAN-Lite, G-Safeguard-Lite, the Who&When LLM-judge protocols, OWASP-style configuration rules) beside the methods introduced with GRADE and CatchBench; every method that reproduces a CatchBench 0.1.2 board row matches it sample by sample.
24
+ - `auditable.featurize`: trace normalization for step lists, run dicts, typed graphs, `SessionGraph` and `TraceView` inputs, and the features the methods compute (the GRADE structural layers, the Who&When step matrix, the step dependency graph, PyG encodings).
25
+ - `auditable.llm`: a `prompt -> reply` backend protocol, `FixedResponseBackend` for tests and replays, `OpenAICompatibleBackend` (standard library only), and a prediction cache.
26
+ - `auditable.from_agentpile`, `configs_from_agentpile`, `step_targets`, `run_targets` and `auditable.datasets.load_traces` read agentpile records (public datasets, trace files, captured runs) into the methods' inputs and labels. `convention="grade"` with `deps="grade"` reproduces the steps, dependencies and graphs of GRADE's converters (commit 3839a57) on seven corpora; `convention="generic"` (the default) makes one step per message and one per tool call.
27
+ - Extras `tabular-ad`, `graph-ad` and `agentpile`; the core install still has no third-party dependency.
28
+ - `docs/methods-contract.md`, the contract a method follows and the behaviours a pinned consumer such as CatchBench relies on.
29
+
30
+ ### Behaviour of the Conversion
31
+
32
+ - In `convention="generic"`, content given as a list of parts (dicts with a string `type`, possibly mixed with bare strings) keeps its text and writes every other part (an image, a document) as `[<type>]`, dropping that part's other fields; `meta["report"]` counts those parts and says how each step of the record maps into the trace.
33
+ - `convention="grade"` raises `ValueError` for a run from a dataset revision other than the one its projection was checked on.
34
+ - A run with subagent trajectories is refused by default; the error names the two ways to read it, `from_agentpile(run.subagents, ...)` and `subagents="skip"`.
35
+
36
+ ### Deprecated
37
+
38
+ - `ActionGate`, `ReferenceLedger` and `DataAuditor` emit a `DeprecationWarning` when constructed and will be removed in a later release.
39
+
40
+ ## Earlier Releases
41
+
42
+ Releases up to 0.2.1 are listed on [PyPI](https://pypi.org/project/auditable/#history) and as [GitHub tags](https://github.com/yzhao062/auditable/tags).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: auditable
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: A library of auditing methods for AI agents: configuration audits, run-level failure detection, step-level fault localization, and online monitors, behind one API per family.
5
5
  Project-URL: Homepage, https://github.com/yzhao062/auditable
6
6
  Project-URL: Repository, https://github.com/yzhao062/auditable
@@ -27,6 +27,12 @@ Requires-Dist: agentpile[hf]<0.4,>=0.3; extra == 'agentpile'
27
27
  Requires-Dist: numpy>=1.21; extra == 'agentpile'
28
28
  Provides-Extra: anomaly
29
29
  Requires-Dist: pyod>=1.1.0; extra == 'anomaly'
30
+ Provides-Extra: bench
31
+ Requires-Dist: agentpile[hf]<0.4,>=0.3; extra == 'bench'
32
+ Requires-Dist: networkx>=3.0; extra == 'bench'
33
+ Requires-Dist: numpy>=1.21; extra == 'bench'
34
+ Requires-Dist: pyod>=1.1.0; extra == 'bench'
35
+ Requires-Dist: scikit-learn>=1.0; extra == 'bench'
30
36
  Provides-Extra: dev
31
37
  Requires-Dist: build>=1.0; extra == 'dev'
32
38
  Requires-Dist: pyod>=1.1.0; extra == 'dev'
@@ -73,20 +79,114 @@ Description-Content-Type: text/markdown
73
79
 
74
80
  # auditable
75
81
 
76
- **A library of auditing methods for AI agents: configuration audits before a run, online monitors while it runs, and failure detection and fault localization after it, with one interface per family.**
82
+ **A library of auditing methods for AI agents, with a leaderboard for each task: configuration audits before a run, online monitors while it runs, and failure detection and fault localization after it.**
77
83
 
78
84
  [![PyPI](https://img.shields.io/pypi/v/auditable.svg)](https://pypi.org/project/auditable/)
79
85
  [![Python](https://img.shields.io/pypi/pyversions/auditable.svg)](https://pypi.org/project/auditable/)
80
86
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://github.com/yzhao062/auditable/blob/main/LICENSE)
81
87
  [![CI](https://github.com/yzhao062/auditable/actions/workflows/ci.yml/badge.svg)](https://github.com/yzhao062/auditable/actions/workflows/ci.yml)
88
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yzhao062/auditable/blob/main/examples/leaderboard.ipynb)
82
89
 
83
- [Quick Start](#quick-start) · [Real Agent Traces](#real-agent-traces) · [Methods](#methods) · [Install](#install) · [Reproducing CatchBench](#reproducing-catchbench) · [Adding a Method](#adding-a-method) · [Citation](#citation)
90
+ [Leaderboard](#leaderboard) · [Put Your Method on the Board](#put-your-method-on-the-board) · [Tasks](#tasks) · [Quick Start](#quick-start) · [Real Agent Traces](#real-agent-traces) · [Methods](#methods) · [Install](#install) · [Adding a Method](#adding-a-method) · [Citation](#citation)
84
91
 
85
92
  </div>
86
93
 
94
+ `auditable` is a library of auditing methods for AI agents with a leaderboard for each task: one command reruns the [CatchBench](https://github.com/yzhao062/catchbench) board on your machine, and a method you write gets a rank on the same population and protocol.
95
+
96
+ ## Leaderboard
97
+
98
+ Did the run fail? The board below ranks 17 methods by ROC-AUC on 376 SWE-Gym OpenHands runs, 188 of which failed. One command reruns it on the population and protocol of the CatchBench board:
99
+
100
+ ```bash
101
+ pip install "auditable[bench]"
102
+ python -m auditable.bench detect/swegym
103
+ ```
104
+
105
+ | Rank | Method | Algorithm | ROC-AUC |
106
+ |---|---|---|---|
107
+ | 1 | `run.pygod_gaan` | GAAN adversarial detector (PyGOD) | 0.850 |
108
+ | 2 | `run.lr_spline_flat` | Logistic regression on a cubic spline of run size, a control | 0.832 |
109
+ | 3 | `run.gsafeguard_lite` | G-Safeguard-Lite (supervised graph classifier) | 0.828 |
110
+ | 4 | `run.lr_full` | Logistic regression on all raw layers (GRADE full) | 0.819 |
111
+ | 5 | `run.lr_flatdep` | Logistic regression on size and dependency (GRADE flatdep) | 0.804 |
112
+ | 6 | `run.guardian_lite` | GUARDIAN-Lite (attribute-reconstruction autoencoder) | 0.767 |
113
+ | 7 | `run.pyod_ecod` | ECOD on run size | 0.765 |
114
+ | 8 | `run.pygod_conad` | CONAD contrastive graph autoencoder (PyGOD) | 0.750 |
115
+ | 9 | `run.lr_flat` | Logistic regression on run size (GRADE flat), the size baseline | 0.663 |
116
+ | 10 | `run.pyod_copod` | COPOD on run size | 0.625 |
117
+ | 11 | `run.pygod_anomalydae` | AnomalyDAE dual autoencoder (PyGOD) | 0.592 |
118
+ | 12 | `run.pyod_lof` | Local outlier factor on run size | 0.584 |
119
+ | 13 | `run.pyod_iforest` | Isolation Forest on run size | 0.571 |
120
+ | 14 | `run.pygod_dominant` | DOMINANT graph autoencoder (PyGOD) | 0.547 |
121
+ | 15 | `run.random` | Random run scores, a control | 0.483 |
122
+ | 16 | `run.pyod_knn` | KNN distance on run size | 0.446 |
123
+ | 17 | `run.pyod_hbos` | HBOS on run size | 0.319 |
124
+
125
+ PyGOD's GAAN, a literature baseline, leads this board at 0.850. Second, at 0.832, is the flexible size control `run.lr_spline_flat`: a cubic spline of the same four run-size counts the linear size baseline `run.lr_flat` reads (0.663). Run size alone, fitted without a linear restriction, ranks above G-Safeguard-Lite and above both GRADE dependency regressions (0.819 and 0.804), so this board does not show that dependency structure predicts failure beyond size, the reading GRADE retired on 2026-09-08. Read a new row against both size controls; on tau-bench the order changes, and `run.lr_flatdep` (0.665) ranks above the spline control (0.631).
126
+
127
+ The 16 CatchBench rows equal the CatchBench board, which was computed on Linux; the spline control is not a board row, and its reference value is the `size (spline)` arm of CatchBench's committed size audit. On macOS, `run.pyod_lof` prints 0.582 instead of 0.584, and `--golden` reports that as a platform value and not as a mismatch. The first run downloads the data through agentpile; later runs load SWE-Gym from the cache in about 3 seconds, and the full board takes about 70 seconds on a laptop CPU, of which PyGOD GAAN is the slowest row at about 37 seconds. The graph rows need `auditable[graph-ad]` and the PyG sampling backend ([Install](#install)); without them those rows are listed as skipped with the extra named, and the rest of the board is still scored.
128
+
129
+ ```bash
130
+ python -m auditable.bench # list the tasks
131
+ python -m auditable.bench detect/swegym --methods run.lr_flat run.pyod_ecod # score chosen rows only
132
+ python -m auditable.bench detect/swegym --golden # exit 1 if a row differs from the CatchBench board
133
+ python -m auditable.bench detect/swegym --markdown # a Markdown table; --json prints JSON
134
+ ```
135
+
136
+ ## Put Your Method on the Board
137
+
138
+ A method is a class with a `MethodCard`. Pass it as `extra=` and `leaderboard` scores it beside the default rows, under the protocol of its kind: a supervised detector gets the mean ROC-AUC over five seeds of stratified 5-fold cross-validation with a fresh estimator per fold, and an unsupervised one gets a single `fit_score` over the whole population. The snippet below adds a random forest on run size, a deliberately plain method:
139
+
140
+ ```python
141
+ from sklearn.ensemble import RandomForestClassifier
142
+
143
+ from auditable.base import BaseRunDetector, MethodCard
144
+ from auditable.bench import leaderboard
145
+ from auditable.featurize import grade_layer_matrix
146
+
147
+
148
+ class ForestOnSize(BaseRunDetector):
149
+ card = MethodCard(method_id="run.forest_flat", name="Random forest on run size", family="run",
150
+ fit_scope="inductive", supervised=True, output_kind="score", fidelity="original")
151
+
152
+ def fit(self, runs, y=None):
153
+ self.model_ = RandomForestClassifier(200, random_state=0)
154
+ self.model_.fit(grade_layer_matrix(list(runs), "flat"), y)
155
+ self.decision_scores_ = self.decision_function(runs)
156
+ return self
157
+
158
+ def decision_function(self, runs):
159
+ return self.model_.predict_proba(grade_layer_matrix(list(runs), "flat"))[:, 1]
160
+
161
+
162
+ board = leaderboard("detect/swegym", extra=[ForestOnSize])
163
+ print(board.rank_of("run.forest_flat"), board["run.forest_flat"].scores)
164
+ ```
165
+
166
+ The last line prints the rank of the new row among all rows and its scores. `print(board)` shows the full table, with the CatchBench value in brackets beside each row that has one, and `board.to_markdown()`, `board.to_dict()` and `board.compare_golden()` export it. `methods=[...]` scores only the rows you name, which is quick while you iterate (`leaderboard("detect/swegym", methods=["run.lr_flat", ForestOnSize])`), and `Entry(method, kwargs={...}, label="...", key="...")` adds a row for a variant with constructor arguments (give each variant its own key, because a row that keeps the method id is compared with that method's CatchBench value). A method that raises is listed as an error and the rest of the board is still scored. The [method contract](https://github.com/yzhao062/auditable/blob/main/docs/methods-contract.md) lists the conventions for the four families.
167
+
168
+ ## Tasks
169
+
170
+ Six tasks ship with 0.4.0. Each fixes a population and a protocol, so every method on a board is scored on the same data in the same way. `detect` scores the run detectors, `localize` the step locators, `live` the online monitors (run detectors also take part, scored on prefixes of the run), and `pre` the configuration auditors.
171
+
172
+ | Task | Question | Population | Metric |
173
+ |---|---|---|---|
174
+ | `detect/swegym` | Did the run fail? | SWE-Gym OpenHands trajectories, one scaffold: 376 runs, 188 failed | ROC-AUC |
175
+ | `detect/tau` | Did the run fail? | tau-bench: 660 runs, 363 failed | ROC-AUC |
176
+ | `localize/whoandwhen` | Which step was the decisive mistake? | Who&When: 126 failed multi-agent runs with a human mistake step | top-1, top-3, MRR (mean reciprocal rank) |
177
+ | `live/swegym` | Can the failure be caught early? | SWE-Gym runs, read as prefixes of 25, 50, 75 and 100 percent of their steps | mean prefix ROC-AUC |
178
+ | `live/tau` | Can the failure be caught early? | tau-bench runs, read as prefixes of 25, 50, 75 and 100 percent of their steps | mean prefix ROC-AUC |
179
+ | `pre/over_privilege` | Is the agent configuration over-privileged before it runs? | 1,187 configurations from six sources | F1, precision, recall |
180
+
181
+ Every task id works with the commands above: `python -m auditable.bench <task>` reruns the board, and `leaderboard("<task>", extra=[...])` places a method on it. The LLM judges on `localize/whoandwhen` and `pre/over_privilege` are replayed from committed caches, so those boards need no API call.
182
+
183
+ The CatchBench board shows how the other tasks read. On Who&When localization, the best LLM judges (all-at-once) reach top-1 of about 0.42 to 0.45 against 0.119 for random, and the structural blast rule ties the position prior at 0.159 top-1. The tau-bench detection board is led by `run.lr_flatdep` and `run.lr_full`, tied at 0.665, against 0.619 for the size baseline. For over-privilege, the best rule scanner `config.owasp_asi_combined` reaches F1 0.654, flagging every configuration reaches 0.601, and an LLM judge reaches 0.695.
184
+
185
+ ## What Is in the Library
186
+
87
187
  `auditable` collects methods that audit LLM agents at three points: an agent configuration before it runs (PRE), a run while it streams (LIVE), and a finished run (POST). Methods are grouped into four families, and each family has one interface, in the way PyOD gives outlier detectors one interface. The library holds baselines from the literature (PyOD and PyGOD detectors, GUARDIAN, G-Safeguard, the Who&When LLM-judge protocols, OWASP-style configuration rules) beside the methods introduced with GRADE and CatchBench.
88
188
 
89
- [CatchBench](https://github.com/yzhao062/catchbench) is the benchmark for these methods: the tasks, corpora, evaluation protocols, and metrics live there. Every method here that appears on the CatchBench board reproduces its row sample by sample, and the full board reruns byte-identical with those rows computed by this library ([Reproducing CatchBench](#reproducing-catchbench)).
189
+ [CatchBench](https://github.com/yzhao062/catchbench) is the paper and benchmark whose board the leaderboards reproduce: `auditable.bench` carries its populations and evaluation protocols, and every method here that appears on its board reproduces its row sample by sample ([Reproducing CatchBench](#reproducing-catchbench)). [agentpile](https://github.com/yzhao062/agentpile) is the converter that reads public agent-trace datasets into the one record the methods consume ([Real Agent Traces](#real-agent-traces)).
90
190
 
91
191
  ## Quick Start
92
192
 
@@ -211,6 +311,7 @@ Configuration rules and the step-by-step and binary-search LLM judges run on the
211
311
  | Supervised | `run.lr_flat` | Logistic regression on run size (GRADE flat) | [GRADE (Zhao, 2026)](https://arxiv.org/abs/2606.22741) |
212
312
  | Supervised | `run.lr_flatdep` | Logistic regression on size and dependency (GRADE flatdep) | [GRADE (Zhao, 2026)](https://arxiv.org/abs/2606.22741) |
213
313
  | Supervised | `run.lr_full` | Logistic regression on all raw layers (GRADE full) | [GRADE (Zhao, 2026)](https://arxiv.org/abs/2606.22741) |
314
+ | Supervised | `run.lr_spline_flat` | Logistic regression on a cubic spline of run size (flexible size control) | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
214
315
  | PyOD detector | `run.pyod_copod` | COPOD on run size | [COPOD (Li et al., 2020)](https://arxiv.org/abs/2009.09463) |
215
316
  | PyOD detector | `run.pyod_ecod` | ECOD on run size | [ECOD (Li et al., 2022)](https://arxiv.org/abs/2201.00382) |
216
317
  | PyOD detector | `run.pyod_hbos` | HBOS on run size | HBOS (Goldstein and Dengel, 2012) |
@@ -253,15 +354,16 @@ Configuration rules and the step-by-step and binary-search LLM judges run on the
253
354
 
254
355
  ```bash
255
356
  pip install auditable # core: the registry and the configuration rules, no third-party dependencies
357
+ pip install "auditable[bench]" # the leaderboards: PyOD, scikit-learn, NumPy, NetworkX, and agentpile with its Hugging Face loaders
256
358
  pip install "auditable[tabular-ad]" # run, step, and online methods on trace features (NumPy, scikit-learn, PyOD, NetworkX)
257
359
  pip install "auditable[agentpile]" # read public datasets, trace files and captured runs through agentpile
258
360
  ```
259
361
 
260
- The examples, tests and benchmark harnesses are in the repository, not the wheel; to run them, install from a clone with `pip install -e ".[dev,tabular-ad]"`.
362
+ The examples, tests and benchmark harnesses are in the repository, not the wheel; to run them, install from a clone with `pip install -e ".[dev,tabular-ad,bench]"`.
261
363
 
262
364
  The LLM judges take any `prompt -> reply` function as their backend; `OpenAICompatibleBackend` reaches an OpenAI-compatible endpoint with the standard library alone.
263
365
 
264
- The graph methods (PyGOD detectors, GUARDIAN-Lite, G-Safeguard-Lite) need torch, PyTorch Geometric, PyGOD, and a sampling backend built for the installed torch, which pip cannot resolve from the extra. Install torch and the matching `pyg-lib` wheel first:
366
+ The graph methods (PyGOD detectors, GUARDIAN-Lite, G-Safeguard-Lite), and so the graph rows of the leaderboards, need torch, PyTorch Geometric, PyGOD, and a sampling backend built for the installed torch, which pip cannot resolve from the extra; they need Python 3.10 or newer, since torch 2.12.1 and `pyg-lib` publish no wheels for 3.9. Install torch and the matching `pyg-lib` wheel first (the same steps on Linux, macOS on Apple silicon, and Windows):
265
367
 
266
368
  ```bash
267
369
  pip install "torch==2.12.1" --index-url https://download.pytorch.org/whl/cpu
@@ -270,7 +372,7 @@ pip install "auditable[graph-ad]"
270
372
  python -c "import torch_geometric.typing as t; assert t.WITH_PYG_LIB"
271
373
  ```
272
374
 
273
- Where torch is already installed, as on Colab, keep it: skip the first line, and in the `pyg-lib` URL replace `2.12.1+cpu` with the installed version, which `python -c "import torch; print(torch.__version__)"` prints (for example `2.11.0+cu130`); the pinned CPU build would replace Colab's torch and break its preinstalled torchvision. The graph-ad install was checked on Colab CPU and T4 runtimes with Colab's torch, and on Linux aarch64 (DGX Spark) with the pinned one. The PyGOD methods run on the CPU (`gpu=-1`) even when a GPU is present.
375
+ Where torch is already installed, as on Colab, keep it: skip the first line, and in the `pyg-lib` URL replace `2.12.1+cpu` with the installed version, which `python -c "import torch; print(torch.__version__)"` prints; the pinned CPU build would replace Colab's torch and break its preinstalled torchvision. PyG does not publish wheels for every patch release, so when pip finds no `pyg_lib` at that URL, use the `.0` release with the same CUDA tag: Colab's torch `2.14.1+cu130` takes `https://data.pyg.org/whl/torch-2.14.0+cu130.html`. The graph-ad install was checked for 0.4.0 on a Colab T4 runtime with its torch 2.14.1+cu130, and for 0.3.0 on Colab CPU and T4 runtimes with Colab's torch and on Linux aarch64 (DGX Spark) with the pinned one; a weekly workflow (`bench-platforms.yml`) repeats the pinned steps from a clean install on Linux, macOS, and Windows and checks three boards against their golden files. The PyGOD methods run on the CPU (`gpu=-1`) even when a GPU is present.
274
376
 
275
377
  ## Traces and Inputs
276
378
 
@@ -280,7 +382,7 @@ Methods read traces through `auditable.featurize.normalize_trace`, which accepts
280
382
 
281
383
  ## Reproducing CatchBench
282
384
 
283
- [`benchmarks/catchbench_parity`](https://github.com/yzhao062/auditable/tree/main/benchmarks/catchbench_parity) checks the library against CatchBench 0.1.2 and GRADE at commit `3839a57`, the versions the CatchBench board pins. It is a development harness and is not part of the wheel.
385
+ `python -m auditable.bench <task> --golden` reruns a CatchBench board with the methods of this library and exits 1 if a row differs from the board ([Leaderboard](#leaderboard)). The parity harness [`benchmarks/catchbench_parity`](https://github.com/yzhao062/auditable/tree/main/benchmarks/catchbench_parity) remains for development and is not part of the wheel. It compares every migrated method with its CatchBench or GRADE original sample by sample, at CatchBench 0.1.2 and GRADE commit `3839a57`, the last versions whose board computes those entries with its own code.
284
386
 
285
387
  ```bash
286
388
  export GRADE_DIR=/path/to/grade # checked out at 3839a57
@@ -291,11 +393,9 @@ python benchmarks/catchbench_parity/run_parity.py board --perturb --out perturbe
291
393
  python benchmarks/catchbench_parity/run_parity.py consumption board.txt perturbed.txt
292
394
  ```
293
395
 
294
- The checks compare every migrated method with its CatchBench or GRADE original on the real corpora, sample by sample and bit for bit: per-run scores, per-step scores, out-of-fold predictions, configuration findings, and the features underneath them. The board run replaces CatchBench's method factories with library adapters, so the main tables and every breakdown and robustness table are computed by the library, while the original scoring functions of migrated methods are replaced by functions that raise. Its output must match the board computed before migration byte for byte. The consumption run perturbs every library output and confirms that each migrated row changes and no other row does.
295
-
296
396
  ## Adding a Method
297
397
 
298
- Subclass the family base class in `auditable.base`, give it a `MethodCard`, and register it with `@register`. The [method contract](https://github.com/yzhao062/auditable/blob/main/docs/methods-contract.md) lists the conventions: input forms, label alignment for supervised step methods, output order, optional dependencies, the tests a method needs, and how to add a parity check when the method reproduces a CatchBench row.
398
+ Subclass the family base class in `auditable.base`, give it a `MethodCard`, and register it with `@register`, which makes it reachable by id (`get_method`, `--methods`) and adds it to the default rows of the detect and pre boards. To try a method first, pass it to `leaderboard(task, extra=[...])` without registering ([Put Your Method on the Board](#put-your-method-on-the-board)). The [method contract](https://github.com/yzhao062/auditable/blob/main/docs/methods-contract.md) lists the conventions: input forms, label alignment for supervised step methods, output order, optional dependencies, the tests a method needs, and how to add a parity check when the method reproduces a CatchBench row.
299
399
 
300
400
  ## Records and Graph Analysis
301
401
 
@@ -309,14 +409,26 @@ Records are content-addressed and hash-chained, and that property is limited. A
309
409
 
310
410
  ## Related Projects
311
411
 
312
- - [CatchBench](https://github.com/yzhao062/catchbench): the benchmark for these methods (arXiv:2608.22808).
313
- - [agentpile](https://github.com/yzhao062/agentpile): loads public agent-trace datasets, trace files and captured runs into one record, which `from_agentpile` reads.
412
+ - [CatchBench](https://github.com/yzhao062/catchbench): the paper and benchmark whose board the leaderboards reproduce (arXiv:2608.22808).
413
+ - [agentpile](https://github.com/yzhao062/agentpile): the converter that loads public agent-trace datasets, trace files and captured runs into one record, which `from_agentpile` reads.
314
414
  - [GRADE](https://arxiv.org/abs/2606.22741): the typed two-layer graph of agent execution and dependency that the structural features read.
315
415
  - [awesome-auditable-ai](https://github.com/yzhao062/awesome-auditable-ai): a reading list on AI agent reliability and auditing.
316
416
 
317
417
  ## Citation
318
418
 
319
- If you use `auditable`, please cite the work behind the methods you use (each `MethodCard.cite`) and, for the structural features and the benchmark, GRADE and CatchBench:
419
+ If you use `auditable`, please cite Auditable Agents:
420
+
421
+ ```bibtex
422
+ @misc{nian2026auditable,
423
+ title = {Auditable Agents},
424
+ author = {Nian, Yi and Yuan, Aojie and Zhang, Haiyue and Li, Jiate and Li, Li and Hu, Xiyang and Wei, Hua and Xiao, Xiongye and Xiao, Chaowei and Zhao, Yue},
425
+ year = {2026},
426
+ eprint = {2604.05485},
427
+ archivePrefix = {arXiv}
428
+ }
429
+ ```
430
+
431
+ If you use the structural features or the benchmark, please also cite GRADE and CatchBench, and for each method, the work behind it (its `MethodCard.cite`):
320
432
 
321
433
  ```bibtex
322
434
  @article{zhao2026grade,
@@ -9,20 +9,114 @@
9
9
 
10
10
  # auditable
11
11
 
12
- **A library of auditing methods for AI agents: configuration audits before a run, online monitors while it runs, and failure detection and fault localization after it, with one interface per family.**
12
+ **A library of auditing methods for AI agents, with a leaderboard for each task: configuration audits before a run, online monitors while it runs, and failure detection and fault localization after it.**
13
13
 
14
14
  [![PyPI](https://img.shields.io/pypi/v/auditable.svg)](https://pypi.org/project/auditable/)
15
15
  [![Python](https://img.shields.io/pypi/pyversions/auditable.svg)](https://pypi.org/project/auditable/)
16
16
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://github.com/yzhao062/auditable/blob/main/LICENSE)
17
17
  [![CI](https://github.com/yzhao062/auditable/actions/workflows/ci.yml/badge.svg)](https://github.com/yzhao062/auditable/actions/workflows/ci.yml)
18
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yzhao062/auditable/blob/main/examples/leaderboard.ipynb)
18
19
 
19
- [Quick Start](#quick-start) · [Real Agent Traces](#real-agent-traces) · [Methods](#methods) · [Install](#install) · [Reproducing CatchBench](#reproducing-catchbench) · [Adding a Method](#adding-a-method) · [Citation](#citation)
20
+ [Leaderboard](#leaderboard) · [Put Your Method on the Board](#put-your-method-on-the-board) · [Tasks](#tasks) · [Quick Start](#quick-start) · [Real Agent Traces](#real-agent-traces) · [Methods](#methods) · [Install](#install) · [Adding a Method](#adding-a-method) · [Citation](#citation)
20
21
 
21
22
  </div>
22
23
 
24
+ `auditable` is a library of auditing methods for AI agents with a leaderboard for each task: one command reruns the [CatchBench](https://github.com/yzhao062/catchbench) board on your machine, and a method you write gets a rank on the same population and protocol.
25
+
26
+ ## Leaderboard
27
+
28
+ Did the run fail? The board below ranks 17 methods by ROC-AUC on 376 SWE-Gym OpenHands runs, 188 of which failed. One command reruns it on the population and protocol of the CatchBench board:
29
+
30
+ ```bash
31
+ pip install "auditable[bench]"
32
+ python -m auditable.bench detect/swegym
33
+ ```
34
+
35
+ | Rank | Method | Algorithm | ROC-AUC |
36
+ |---|---|---|---|
37
+ | 1 | `run.pygod_gaan` | GAAN adversarial detector (PyGOD) | 0.850 |
38
+ | 2 | `run.lr_spline_flat` | Logistic regression on a cubic spline of run size, a control | 0.832 |
39
+ | 3 | `run.gsafeguard_lite` | G-Safeguard-Lite (supervised graph classifier) | 0.828 |
40
+ | 4 | `run.lr_full` | Logistic regression on all raw layers (GRADE full) | 0.819 |
41
+ | 5 | `run.lr_flatdep` | Logistic regression on size and dependency (GRADE flatdep) | 0.804 |
42
+ | 6 | `run.guardian_lite` | GUARDIAN-Lite (attribute-reconstruction autoencoder) | 0.767 |
43
+ | 7 | `run.pyod_ecod` | ECOD on run size | 0.765 |
44
+ | 8 | `run.pygod_conad` | CONAD contrastive graph autoencoder (PyGOD) | 0.750 |
45
+ | 9 | `run.lr_flat` | Logistic regression on run size (GRADE flat), the size baseline | 0.663 |
46
+ | 10 | `run.pyod_copod` | COPOD on run size | 0.625 |
47
+ | 11 | `run.pygod_anomalydae` | AnomalyDAE dual autoencoder (PyGOD) | 0.592 |
48
+ | 12 | `run.pyod_lof` | Local outlier factor on run size | 0.584 |
49
+ | 13 | `run.pyod_iforest` | Isolation Forest on run size | 0.571 |
50
+ | 14 | `run.pygod_dominant` | DOMINANT graph autoencoder (PyGOD) | 0.547 |
51
+ | 15 | `run.random` | Random run scores, a control | 0.483 |
52
+ | 16 | `run.pyod_knn` | KNN distance on run size | 0.446 |
53
+ | 17 | `run.pyod_hbos` | HBOS on run size | 0.319 |
54
+
55
+ PyGOD's GAAN, a literature baseline, leads this board at 0.850. Second, at 0.832, is the flexible size control `run.lr_spline_flat`: a cubic spline of the same four run-size counts the linear size baseline `run.lr_flat` reads (0.663). Run size alone, fitted without a linear restriction, ranks above G-Safeguard-Lite and above both GRADE dependency regressions (0.819 and 0.804), so this board does not show that dependency structure predicts failure beyond size, the reading GRADE retired on 2026-09-08. Read a new row against both size controls; on tau-bench the order changes, and `run.lr_flatdep` (0.665) ranks above the spline control (0.631).
56
+
57
+ The 16 CatchBench rows equal the CatchBench board, which was computed on Linux; the spline control is not a board row, and its reference value is the `size (spline)` arm of CatchBench's committed size audit. On macOS, `run.pyod_lof` prints 0.582 instead of 0.584, and `--golden` reports that as a platform value and not as a mismatch. The first run downloads the data through agentpile; later runs load SWE-Gym from the cache in about 3 seconds, and the full board takes about 70 seconds on a laptop CPU, of which PyGOD GAAN is the slowest row at about 37 seconds. The graph rows need `auditable[graph-ad]` and the PyG sampling backend ([Install](#install)); without them those rows are listed as skipped with the extra named, and the rest of the board is still scored.
58
+
59
+ ```bash
60
+ python -m auditable.bench # list the tasks
61
+ python -m auditable.bench detect/swegym --methods run.lr_flat run.pyod_ecod # score chosen rows only
62
+ python -m auditable.bench detect/swegym --golden # exit 1 if a row differs from the CatchBench board
63
+ python -m auditable.bench detect/swegym --markdown # a Markdown table; --json prints JSON
64
+ ```
65
+
66
+ ## Put Your Method on the Board
67
+
68
+ A method is a class with a `MethodCard`. Pass it as `extra=` and `leaderboard` scores it beside the default rows, under the protocol of its kind: a supervised detector gets the mean ROC-AUC over five seeds of stratified 5-fold cross-validation with a fresh estimator per fold, and an unsupervised one gets a single `fit_score` over the whole population. The snippet below adds a random forest on run size, a deliberately plain method:
69
+
70
+ ```python
71
+ from sklearn.ensemble import RandomForestClassifier
72
+
73
+ from auditable.base import BaseRunDetector, MethodCard
74
+ from auditable.bench import leaderboard
75
+ from auditable.featurize import grade_layer_matrix
76
+
77
+
78
+ class ForestOnSize(BaseRunDetector):
79
+ card = MethodCard(method_id="run.forest_flat", name="Random forest on run size", family="run",
80
+ fit_scope="inductive", supervised=True, output_kind="score", fidelity="original")
81
+
82
+ def fit(self, runs, y=None):
83
+ self.model_ = RandomForestClassifier(200, random_state=0)
84
+ self.model_.fit(grade_layer_matrix(list(runs), "flat"), y)
85
+ self.decision_scores_ = self.decision_function(runs)
86
+ return self
87
+
88
+ def decision_function(self, runs):
89
+ return self.model_.predict_proba(grade_layer_matrix(list(runs), "flat"))[:, 1]
90
+
91
+
92
+ board = leaderboard("detect/swegym", extra=[ForestOnSize])
93
+ print(board.rank_of("run.forest_flat"), board["run.forest_flat"].scores)
94
+ ```
95
+
96
+ The last line prints the rank of the new row among all rows and its scores. `print(board)` shows the full table, with the CatchBench value in brackets beside each row that has one, and `board.to_markdown()`, `board.to_dict()` and `board.compare_golden()` export it. `methods=[...]` scores only the rows you name, which is quick while you iterate (`leaderboard("detect/swegym", methods=["run.lr_flat", ForestOnSize])`), and `Entry(method, kwargs={...}, label="...", key="...")` adds a row for a variant with constructor arguments (give each variant its own key, because a row that keeps the method id is compared with that method's CatchBench value). A method that raises is listed as an error and the rest of the board is still scored. The [method contract](https://github.com/yzhao062/auditable/blob/main/docs/methods-contract.md) lists the conventions for the four families.
97
+
98
+ ## Tasks
99
+
100
+ Six tasks ship with 0.4.0. Each fixes a population and a protocol, so every method on a board is scored on the same data in the same way. `detect` scores the run detectors, `localize` the step locators, `live` the online monitors (run detectors also take part, scored on prefixes of the run), and `pre` the configuration auditors.
101
+
102
+ | Task | Question | Population | Metric |
103
+ |---|---|---|---|
104
+ | `detect/swegym` | Did the run fail? | SWE-Gym OpenHands trajectories, one scaffold: 376 runs, 188 failed | ROC-AUC |
105
+ | `detect/tau` | Did the run fail? | tau-bench: 660 runs, 363 failed | ROC-AUC |
106
+ | `localize/whoandwhen` | Which step was the decisive mistake? | Who&When: 126 failed multi-agent runs with a human mistake step | top-1, top-3, MRR (mean reciprocal rank) |
107
+ | `live/swegym` | Can the failure be caught early? | SWE-Gym runs, read as prefixes of 25, 50, 75 and 100 percent of their steps | mean prefix ROC-AUC |
108
+ | `live/tau` | Can the failure be caught early? | tau-bench runs, read as prefixes of 25, 50, 75 and 100 percent of their steps | mean prefix ROC-AUC |
109
+ | `pre/over_privilege` | Is the agent configuration over-privileged before it runs? | 1,187 configurations from six sources | F1, precision, recall |
110
+
111
+ Every task id works with the commands above: `python -m auditable.bench <task>` reruns the board, and `leaderboard("<task>", extra=[...])` places a method on it. The LLM judges on `localize/whoandwhen` and `pre/over_privilege` are replayed from committed caches, so those boards need no API call.
112
+
113
+ The CatchBench board shows how the other tasks read. On Who&When localization, the best LLM judges (all-at-once) reach top-1 of about 0.42 to 0.45 against 0.119 for random, and the structural blast rule ties the position prior at 0.159 top-1. The tau-bench detection board is led by `run.lr_flatdep` and `run.lr_full`, tied at 0.665, against 0.619 for the size baseline. For over-privilege, the best rule scanner `config.owasp_asi_combined` reaches F1 0.654, flagging every configuration reaches 0.601, and an LLM judge reaches 0.695.
114
+
115
+ ## What Is in the Library
116
+
23
117
  `auditable` collects methods that audit LLM agents at three points: an agent configuration before it runs (PRE), a run while it streams (LIVE), and a finished run (POST). Methods are grouped into four families, and each family has one interface, in the way PyOD gives outlier detectors one interface. The library holds baselines from the literature (PyOD and PyGOD detectors, GUARDIAN, G-Safeguard, the Who&When LLM-judge protocols, OWASP-style configuration rules) beside the methods introduced with GRADE and CatchBench.
24
118
 
25
- [CatchBench](https://github.com/yzhao062/catchbench) is the benchmark for these methods: the tasks, corpora, evaluation protocols, and metrics live there. Every method here that appears on the CatchBench board reproduces its row sample by sample, and the full board reruns byte-identical with those rows computed by this library ([Reproducing CatchBench](#reproducing-catchbench)).
119
+ [CatchBench](https://github.com/yzhao062/catchbench) is the paper and benchmark whose board the leaderboards reproduce: `auditable.bench` carries its populations and evaluation protocols, and every method here that appears on its board reproduces its row sample by sample ([Reproducing CatchBench](#reproducing-catchbench)). [agentpile](https://github.com/yzhao062/agentpile) is the converter that reads public agent-trace datasets into the one record the methods consume ([Real Agent Traces](#real-agent-traces)).
26
120
 
27
121
  ## Quick Start
28
122
 
@@ -147,6 +241,7 @@ Configuration rules and the step-by-step and binary-search LLM judges run on the
147
241
  | Supervised | `run.lr_flat` | Logistic regression on run size (GRADE flat) | [GRADE (Zhao, 2026)](https://arxiv.org/abs/2606.22741) |
148
242
  | Supervised | `run.lr_flatdep` | Logistic regression on size and dependency (GRADE flatdep) | [GRADE (Zhao, 2026)](https://arxiv.org/abs/2606.22741) |
149
243
  | Supervised | `run.lr_full` | Logistic regression on all raw layers (GRADE full) | [GRADE (Zhao, 2026)](https://arxiv.org/abs/2606.22741) |
244
+ | Supervised | `run.lr_spline_flat` | Logistic regression on a cubic spline of run size (flexible size control) | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
150
245
  | PyOD detector | `run.pyod_copod` | COPOD on run size | [COPOD (Li et al., 2020)](https://arxiv.org/abs/2009.09463) |
151
246
  | PyOD detector | `run.pyod_ecod` | ECOD on run size | [ECOD (Li et al., 2022)](https://arxiv.org/abs/2201.00382) |
152
247
  | PyOD detector | `run.pyod_hbos` | HBOS on run size | HBOS (Goldstein and Dengel, 2012) |
@@ -189,15 +284,16 @@ Configuration rules and the step-by-step and binary-search LLM judges run on the
189
284
 
190
285
  ```bash
191
286
  pip install auditable # core: the registry and the configuration rules, no third-party dependencies
287
+ pip install "auditable[bench]" # the leaderboards: PyOD, scikit-learn, NumPy, NetworkX, and agentpile with its Hugging Face loaders
192
288
  pip install "auditable[tabular-ad]" # run, step, and online methods on trace features (NumPy, scikit-learn, PyOD, NetworkX)
193
289
  pip install "auditable[agentpile]" # read public datasets, trace files and captured runs through agentpile
194
290
  ```
195
291
 
196
- The examples, tests and benchmark harnesses are in the repository, not the wheel; to run them, install from a clone with `pip install -e ".[dev,tabular-ad]"`.
292
+ The examples, tests and benchmark harnesses are in the repository, not the wheel; to run them, install from a clone with `pip install -e ".[dev,tabular-ad,bench]"`.
197
293
 
198
294
  The LLM judges take any `prompt -> reply` function as their backend; `OpenAICompatibleBackend` reaches an OpenAI-compatible endpoint with the standard library alone.
199
295
 
200
- The graph methods (PyGOD detectors, GUARDIAN-Lite, G-Safeguard-Lite) need torch, PyTorch Geometric, PyGOD, and a sampling backend built for the installed torch, which pip cannot resolve from the extra. Install torch and the matching `pyg-lib` wheel first:
296
+ The graph methods (PyGOD detectors, GUARDIAN-Lite, G-Safeguard-Lite), and so the graph rows of the leaderboards, need torch, PyTorch Geometric, PyGOD, and a sampling backend built for the installed torch, which pip cannot resolve from the extra; they need Python 3.10 or newer, since torch 2.12.1 and `pyg-lib` publish no wheels for 3.9. Install torch and the matching `pyg-lib` wheel first (the same steps on Linux, macOS on Apple silicon, and Windows):
201
297
 
202
298
  ```bash
203
299
  pip install "torch==2.12.1" --index-url https://download.pytorch.org/whl/cpu
@@ -206,7 +302,7 @@ pip install "auditable[graph-ad]"
206
302
  python -c "import torch_geometric.typing as t; assert t.WITH_PYG_LIB"
207
303
  ```
208
304
 
209
- Where torch is already installed, as on Colab, keep it: skip the first line, and in the `pyg-lib` URL replace `2.12.1+cpu` with the installed version, which `python -c "import torch; print(torch.__version__)"` prints (for example `2.11.0+cu130`); the pinned CPU build would replace Colab's torch and break its preinstalled torchvision. The graph-ad install was checked on Colab CPU and T4 runtimes with Colab's torch, and on Linux aarch64 (DGX Spark) with the pinned one. The PyGOD methods run on the CPU (`gpu=-1`) even when a GPU is present.
305
+ Where torch is already installed, as on Colab, keep it: skip the first line, and in the `pyg-lib` URL replace `2.12.1+cpu` with the installed version, which `python -c "import torch; print(torch.__version__)"` prints; the pinned CPU build would replace Colab's torch and break its preinstalled torchvision. PyG does not publish wheels for every patch release, so when pip finds no `pyg_lib` at that URL, use the `.0` release with the same CUDA tag: Colab's torch `2.14.1+cu130` takes `https://data.pyg.org/whl/torch-2.14.0+cu130.html`. The graph-ad install was checked for 0.4.0 on a Colab T4 runtime with its torch 2.14.1+cu130, and for 0.3.0 on Colab CPU and T4 runtimes with Colab's torch and on Linux aarch64 (DGX Spark) with the pinned one; a weekly workflow (`bench-platforms.yml`) repeats the pinned steps from a clean install on Linux, macOS, and Windows and checks three boards against their golden files. The PyGOD methods run on the CPU (`gpu=-1`) even when a GPU is present.
210
306
 
211
307
  ## Traces and Inputs
212
308
 
@@ -216,7 +312,7 @@ Methods read traces through `auditable.featurize.normalize_trace`, which accepts
216
312
 
217
313
  ## Reproducing CatchBench
218
314
 
219
- [`benchmarks/catchbench_parity`](https://github.com/yzhao062/auditable/tree/main/benchmarks/catchbench_parity) checks the library against CatchBench 0.1.2 and GRADE at commit `3839a57`, the versions the CatchBench board pins. It is a development harness and is not part of the wheel.
315
+ `python -m auditable.bench <task> --golden` reruns a CatchBench board with the methods of this library and exits 1 if a row differs from the board ([Leaderboard](#leaderboard)). The parity harness [`benchmarks/catchbench_parity`](https://github.com/yzhao062/auditable/tree/main/benchmarks/catchbench_parity) remains for development and is not part of the wheel. It compares every migrated method with its CatchBench or GRADE original sample by sample, at CatchBench 0.1.2 and GRADE commit `3839a57`, the last versions whose board computes those entries with its own code.
220
316
 
221
317
  ```bash
222
318
  export GRADE_DIR=/path/to/grade # checked out at 3839a57
@@ -227,11 +323,9 @@ python benchmarks/catchbench_parity/run_parity.py board --perturb --out perturbe
227
323
  python benchmarks/catchbench_parity/run_parity.py consumption board.txt perturbed.txt
228
324
  ```
229
325
 
230
- The checks compare every migrated method with its CatchBench or GRADE original on the real corpora, sample by sample and bit for bit: per-run scores, per-step scores, out-of-fold predictions, configuration findings, and the features underneath them. The board run replaces CatchBench's method factories with library adapters, so the main tables and every breakdown and robustness table are computed by the library, while the original scoring functions of migrated methods are replaced by functions that raise. Its output must match the board computed before migration byte for byte. The consumption run perturbs every library output and confirms that each migrated row changes and no other row does.
231
-
232
326
  ## Adding a Method
233
327
 
234
- Subclass the family base class in `auditable.base`, give it a `MethodCard`, and register it with `@register`. The [method contract](https://github.com/yzhao062/auditable/blob/main/docs/methods-contract.md) lists the conventions: input forms, label alignment for supervised step methods, output order, optional dependencies, the tests a method needs, and how to add a parity check when the method reproduces a CatchBench row.
328
+ Subclass the family base class in `auditable.base`, give it a `MethodCard`, and register it with `@register`, which makes it reachable by id (`get_method`, `--methods`) and adds it to the default rows of the detect and pre boards. To try a method first, pass it to `leaderboard(task, extra=[...])` without registering ([Put Your Method on the Board](#put-your-method-on-the-board)). The [method contract](https://github.com/yzhao062/auditable/blob/main/docs/methods-contract.md) lists the conventions: input forms, label alignment for supervised step methods, output order, optional dependencies, the tests a method needs, and how to add a parity check when the method reproduces a CatchBench row.
235
329
 
236
330
  ## Records and Graph Analysis
237
331
 
@@ -245,14 +339,26 @@ Records are content-addressed and hash-chained, and that property is limited. A
245
339
 
246
340
  ## Related Projects
247
341
 
248
- - [CatchBench](https://github.com/yzhao062/catchbench): the benchmark for these methods (arXiv:2608.22808).
249
- - [agentpile](https://github.com/yzhao062/agentpile): loads public agent-trace datasets, trace files and captured runs into one record, which `from_agentpile` reads.
342
+ - [CatchBench](https://github.com/yzhao062/catchbench): the paper and benchmark whose board the leaderboards reproduce (arXiv:2608.22808).
343
+ - [agentpile](https://github.com/yzhao062/agentpile): the converter that loads public agent-trace datasets, trace files and captured runs into one record, which `from_agentpile` reads.
250
344
  - [GRADE](https://arxiv.org/abs/2606.22741): the typed two-layer graph of agent execution and dependency that the structural features read.
251
345
  - [awesome-auditable-ai](https://github.com/yzhao062/awesome-auditable-ai): a reading list on AI agent reliability and auditing.
252
346
 
253
347
  ## Citation
254
348
 
255
- If you use `auditable`, please cite the work behind the methods you use (each `MethodCard.cite`) and, for the structural features and the benchmark, GRADE and CatchBench:
349
+ If you use `auditable`, please cite Auditable Agents:
350
+
351
+ ```bibtex
352
+ @misc{nian2026auditable,
353
+ title = {Auditable Agents},
354
+ author = {Nian, Yi and Yuan, Aojie and Zhang, Haiyue and Li, Jiate and Li, Li and Hu, Xiyang and Wei, Hua and Xiao, Xiongye and Xiao, Chaowei and Zhao, Yue},
355
+ year = {2026},
356
+ eprint = {2604.05485},
357
+ archivePrefix = {arXiv}
358
+ }
359
+ ```
360
+
361
+ If you use the structural features or the benchmark, please also cite GRADE and CatchBench, and for each method, the work behind it (its `MethodCard.cite`):
256
362
 
257
363
  ```bibtex
258
364
  @article{zhao2026grade,
@@ -1,5 +1,35 @@
1
1
  # auditable Examples
2
2
 
3
+ ## Leaderboards: Rerun the Board and Add Your Method
4
+
5
+ `auditable.bench` scores auditing methods on frozen populations with frozen protocols, ported from [CatchBench](https://github.com/yzhao062/catchbench), the paper and benchmark whose board these leaderboards reproduce. One call reruns a board on your machine, and a method you write gets a rank on the same population and protocol as every other row. The data come through [agentpile](https://github.com/yzhao062/agentpile), which reads public agent-trace datasets into one record.
6
+
7
+ ```
8
+ pip install "auditable[bench]"
9
+ python examples/example_leaderboard.py
10
+ python examples/example_add_your_method.py
11
+ ```
12
+
13
+ `example_leaderboard.py` prints the `detect/swegym` board: did the run fail, on 376 SWE-Gym OpenHands runs (188 failed), scored by ROC-AUC. It then restricts the board to three tabular rows (`run.lr_flat`, `run.lr_flatdep`, `run.pyod_ecod`) with `methods=[...]` and prints the full board as a Markdown table. The first call loads the runs through agentpile, and the full 17-row board takes about 70 seconds on a laptop CPU. A row whose pip extra is missing is listed as skipped with the extra named, and a row that raises is listed as an error, while the rest of the board is still scored. The graph rows (PyGOD, GUARDIAN-Lite, G-Safeguard-Lite) need `auditable[graph-ad]` plus the PyG sampling backend described in the Install section of the main README.
14
+
15
+ `example_add_your_method.py` defines one new run detector in about 20 lines: a logistic regression on the number of steps and the longest dependency span, written as a `BaseRunDetector` subclass with a full `MethodCard`. The script passes the class to `leaderboard(..., extra=[StepsAndSpan])` next to the size baseline `run.lr_flat`, `run.lr_flatdep`, `run.pyod_ecod`, and the random control, then prints the board and the rank of the new row. Copy the class, change `features` and the estimator, and the board scores your idea under the same cross-validation as every supervised row.
16
+
17
+ The same boards run from a shell:
18
+
19
+ ```
20
+ python -m auditable.bench # list the tasks
21
+ python -m auditable.bench detect/swegym --methods run.lr_flat run.pyod_ecod
22
+ python -m auditable.bench detect/swegym --golden # exit 1 if a row differs from the CatchBench board
23
+ ```
24
+
25
+ `--golden` compares each row with the CatchBench board and prints a known platform difference without failing: on macOS `run.pyod_lof` scores 0.582 where the Linux board prints 0.584. Pass another task id to score another task, and name only methods of the task's family (the live tasks take `run` and `online` methods), because a method of another family is listed as skipped.
26
+
27
+ Read a board with its baselines in view. The top row of `detect/swegym` is PyGOD's GAAN detector, a literature baseline, and `run.lr_flat` is the size baseline that belongs beside every dependency method. A linear size baseline cannot separate dependency shape from a nonlinear function of size, and GRADE retired the reading that the dependency layers predict failure beyond run size on 2026-09-08. A rank is one measurement on one population and protocol.
28
+
29
+ `leaderboard.ipynb` runs the same two steps in a notebook, with the board, the golden check, and a template detector, and it opens in Colab.
30
+
31
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yzhao062/auditable/blob/main/examples/leaderboard.ipynb)
32
+
3
33
  ## The Method Library
4
34
 
5
35
  `example_methods.py` runs one method from each family of `auditable.methods` (a
@@ -0,0 +1,68 @@
1
+ """Add your own method to a board: score a new run detector on SWE-Gym next to the paper's rows.
2
+
3
+ Run from a checkout after installing the bench extra:
4
+
5
+ pip install "auditable[bench]"
6
+ python examples/example_add_your_method.py
7
+
8
+ The detector is a logistic regression on two hand-made features of the typed run graph: the
9
+ number of steps and the longest dependency span (how far back any step reaches). The board
10
+ scores it as it scores every supervised method, by mean ROC-AUC over five seeds of
11
+ stratified 5-fold cross-validation with a fresh estimator per fold.
12
+
13
+ The script prints the small board (the size baseline ``run.lr_flat``, the dependency
14
+ regression ``run.lr_flatdep``, ``run.pyod_ecod``, the random control, and the new row) and
15
+ the rank and score of the new row beside the size baseline. Read any gain over
16
+ ``run.lr_flat`` with care. The longest span grows with run length, and GRADE retired on
17
+ 2026-09-08 the reading that dependency structure predicts failure beyond run size, so a
18
+ claim for a new method needs a comparison with a size-only model fitted as flexibly as
19
+ yours. A rank describes a method on one population and protocol; it does not explain why
20
+ the method works.
21
+ """
22
+ import numpy as np
23
+ from sklearn.linear_model import LogisticRegression
24
+ from sklearn.pipeline import make_pipeline
25
+ from sklearn.preprocessing import StandardScaler
26
+
27
+ from auditable.base import BaseRunDetector, MethodCard
28
+ from auditable.bench import leaderboard
29
+ from auditable.featurize import normalize_trace, run_max_span
30
+
31
+
32
+ class StepsAndSpan(BaseRunDetector):
33
+ """Run length and the longest dependency span, weighed jointly by a linear model."""
34
+
35
+ card = MethodCard(
36
+ method_id="run.lr_steps_span", name="Logistic regression on step count and longest span",
37
+ family="run", fit_scope="inductive", supervised=True, output_kind="score", fidelity="original",
38
+ requires=frozenset({"deps"}), extras=("tabular-ad",),
39
+ summary="Balanced logistic regression on the log step count and the longest dependency span.")
40
+
41
+ def features(self, runs):
42
+ # log1p tames the long tail of run length; the board calls this once and indexes the matrix per fold.
43
+ return np.array([[np.log1p(len(normalize_trace(g))), run_max_span(g)] for g in runs])
44
+
45
+ def fit(self, X, y=None):
46
+ X = X if getattr(X, "ndim", 0) == 2 else self.features(X)
47
+ self.pipeline_ = make_pipeline(StandardScaler(), LogisticRegression(class_weight="balanced")).fit(X, y)
48
+ self.decision_scores_ = self.pipeline_.decision_function(X)
49
+ return self
50
+
51
+ def decision_function(self, X):
52
+ return self.pipeline_.decision_function(X if getattr(X, "ndim", 0) == 2 else self.features(X))
53
+
54
+
55
+ def main():
56
+ # The size baseline and the paper's dependency and unsupervised rows stay on the board so the
57
+ # new row is read against them; extra= adds the new row to those named in methods=.
58
+ board = leaderboard("detect/swegym", methods=["run.lr_flat", "run.lr_flatdep", "run.pyod_ecod", "run.random"],
59
+ extra=[StepsAndSpan])
60
+ print(board)
61
+ key = StepsAndSpan.card.method_id
62
+ print(f"\n{key} ranks {board.rank_of(key)} of {len(board.ranked())}, "
63
+ f"ROC-AUC {board[key].scores['roc_auc']:.3f} against {board['run.lr_flat'].scores['roc_auc']:.3f} "
64
+ f"for the size baseline")
65
+
66
+
67
+ if __name__ == "__main__":
68
+ main()