auditable 0.2.1__tar.gz → 0.3.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 (134) hide show
  1. auditable-0.3.0/CHANGELOG.md +28 -0
  2. auditable-0.3.0/PKG-INFO +340 -0
  3. auditable-0.3.0/README.md +276 -0
  4. {auditable-0.2.1 → auditable-0.3.0}/examples/README.md +253 -228
  5. auditable-0.3.0/examples/example_agentpile.py +71 -0
  6. {auditable-0.2.1 → auditable-0.3.0}/examples/example_langchain_capture.py +96 -96
  7. {auditable-0.2.1 → auditable-0.3.0}/examples/example_langgraph_capture.py +101 -101
  8. {auditable-0.2.1 → auditable-0.3.0}/examples/example_mcp_capture.py +116 -116
  9. auditable-0.3.0/examples/example_methods.py +62 -0
  10. {auditable-0.2.1 → auditable-0.3.0}/examples/example_payment_audit.py +113 -113
  11. {auditable-0.2.1 → auditable-0.3.0}/examples/example_post_rank_run.py +80 -80
  12. {auditable-0.2.1 → auditable-0.3.0}/examples/example_state_anomaly.py +119 -119
  13. {auditable-0.2.1 → auditable-0.3.0}/pyproject.toml +99 -79
  14. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/__init__.py +96 -79
  15. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/analysis.py +615 -615
  16. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/audit_report.py +1055 -1055
  17. auditable-0.3.0/src/auditable/base.py +272 -0
  18. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/chain.py +1 -1
  19. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/data/__init__.py +260 -256
  20. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/data/inject.py +225 -225
  21. auditable-0.3.0/src/auditable/datasets.py +96 -0
  22. auditable-0.3.0/src/auditable/featurize/__init__.py +72 -0
  23. auditable-0.3.0/src/auditable/featurize/_grade_projection.py +307 -0
  24. auditable-0.3.0/src/auditable/featurize/agentpile.py +497 -0
  25. auditable-0.3.0/src/auditable/featurize/pyg.py +43 -0
  26. auditable-0.3.0/src/auditable/featurize/spec.py +372 -0
  27. auditable-0.3.0/src/auditable/featurize/step_deps.py +97 -0
  28. auditable-0.3.0/src/auditable/featurize/trace.py +163 -0
  29. auditable-0.3.0/src/auditable/featurize/who_when.py +71 -0
  30. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/graph/__init__.py +3 -0
  31. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/graph/adapters/__init__.py +44 -44
  32. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/graph/adapters/own_record.py +142 -142
  33. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/graph/adapters/protocol.py +64 -64
  34. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/graph/adapters/tau_bench.py +138 -138
  35. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/graph/features.py +56 -14
  36. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/graph/grounding.py +332 -332
  37. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/graph/loader.py +250 -250
  38. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/graph/risk.py +130 -128
  39. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/graph/session.py +292 -292
  40. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/harness/__init__.py +7 -0
  41. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/integrations/__init__.py +10 -10
  42. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/integrations/langchain.py +805 -805
  43. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/integrations/mcp.py +328 -328
  44. auditable-0.3.0/src/auditable/llm/__init__.py +7 -0
  45. auditable-0.3.0/src/auditable/llm/backend.py +87 -0
  46. auditable-0.3.0/src/auditable/llm/cache.py +63 -0
  47. auditable-0.3.0/src/auditable/llm/who_when.py +217 -0
  48. auditable-0.3.0/src/auditable/methods/__init__.py +134 -0
  49. auditable-0.3.0/src/auditable/methods/_pygod.py +101 -0
  50. auditable-0.3.0/src/auditable/methods/config/__init__.py +1 -0
  51. auditable-0.3.0/src/auditable/methods/config/llm.py +227 -0
  52. auditable-0.3.0/src/auditable/methods/config/rules.py +244 -0
  53. auditable-0.3.0/src/auditable/methods/online/__init__.py +1 -0
  54. auditable-0.3.0/src/auditable/methods/online/rules.py +112 -0
  55. auditable-0.3.0/src/auditable/methods/run/__init__.py +1 -0
  56. auditable-0.3.0/src/auditable/methods/run/baselines.py +64 -0
  57. auditable-0.3.0/src/auditable/methods/run/graph.py +410 -0
  58. auditable-0.3.0/src/auditable/methods/run/pyod.py +166 -0
  59. auditable-0.3.0/src/auditable/methods/run/supervised.py +126 -0
  60. auditable-0.3.0/src/auditable/methods/step/__init__.py +1 -0
  61. auditable-0.3.0/src/auditable/methods/step/graph.py +99 -0
  62. auditable-0.3.0/src/auditable/methods/step/llm.py +170 -0
  63. auditable-0.3.0/src/auditable/methods/step/rules.py +219 -0
  64. auditable-0.3.0/src/auditable/methods/step/supervised.py +139 -0
  65. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/record.py +5 -3
  66. auditable-0.3.0/tests/fixtures/agentpile_grade/README.md +3 -0
  67. auditable-0.3.0/tests/fixtures/agentpile_grade/agent_reward_bench_records.json +204 -0
  68. auditable-0.3.0/tests/fixtures/agentpile_grade/b_openhands_multi_call_turn.json +36 -0
  69. auditable-0.3.0/tests/fixtures/agentpile_grade/swe_agent_synthetic.json +376 -0
  70. auditable-0.3.0/tests/fixtures/grade_3839a57_features.json +1 -0
  71. {auditable-0.2.1 → auditable-0.3.0}/tests/test_adapters.py +352 -352
  72. auditable-0.3.0/tests/test_agentpile_adapter.py +540 -0
  73. {auditable-0.2.1 → auditable-0.3.0}/tests/test_analysis.py +188 -188
  74. {auditable-0.2.1 → auditable-0.3.0}/tests/test_data_inject.py +194 -194
  75. {auditable-0.2.1 → auditable-0.3.0}/tests/test_data_module.py +144 -144
  76. auditable-0.3.0/tests/test_datasets.py +48 -0
  77. auditable-0.3.0/tests/test_featurize.py +186 -0
  78. {auditable-0.2.1 → auditable-0.3.0}/tests/test_graph_features.py +3 -1
  79. {auditable-0.2.1 → auditable-0.3.0}/tests/test_graph_loader.py +293 -293
  80. {auditable-0.2.1 → auditable-0.3.0}/tests/test_graph_risk.py +134 -134
  81. {auditable-0.2.1 → auditable-0.3.0}/tests/test_grounding.py +249 -249
  82. {auditable-0.2.1 → auditable-0.3.0}/tests/test_langchain_integration.py +292 -292
  83. {auditable-0.2.1 → auditable-0.3.0}/tests/test_live_session.py +372 -372
  84. auditable-0.3.0/tests/test_llm.py +207 -0
  85. {auditable-0.2.1 → auditable-0.3.0}/tests/test_mcp_integration.py +264 -264
  86. auditable-0.3.0/tests/test_methods_config.py +527 -0
  87. auditable-0.3.0/tests/test_methods_graph.py +289 -0
  88. auditable-0.3.0/tests/test_methods_pygod_step.py +49 -0
  89. auditable-0.3.0/tests/test_methods_registry.py +234 -0
  90. auditable-0.3.0/tests/test_methods_run_tabular.py +285 -0
  91. auditable-0.3.0/tests/test_methods_slice.py +127 -0
  92. auditable-0.3.0/tests/test_methods_step_rules.py +327 -0
  93. auditable-0.3.0/tests/test_parity_consumption.py +66 -0
  94. {auditable-0.2.1 → auditable-0.3.0}/tests/test_public_api.py +143 -99
  95. {auditable-0.2.1 → auditable-0.3.0}/tests/test_session_graph.py +157 -157
  96. {auditable-0.2.1 → auditable-0.3.0}/tests/test_session_graph_projection.py +141 -141
  97. auditable-0.3.0/tests/test_version.py +11 -0
  98. auditable-0.2.1/PKG-INFO +0 -392
  99. auditable-0.2.1/README.md +0 -345
  100. {auditable-0.2.1 → auditable-0.3.0}/.gitignore +0 -0
  101. {auditable-0.2.1 → auditable-0.3.0}/LICENSE +0 -0
  102. {auditable-0.2.1 → auditable-0.3.0}/examples/example_audit_report.py +0 -0
  103. {auditable-0.2.1 → auditable-0.3.0}/examples/example_end_to_end.py +0 -0
  104. {auditable-0.2.1 → auditable-0.3.0}/examples/example_langgraph_live_replay.py +0 -0
  105. {auditable-0.2.1 → auditable-0.3.0}/examples/example_langgraph_llm_agent.py +0 -0
  106. {auditable-0.2.1 → auditable-0.3.0}/examples/example_live_monitor.py +0 -0
  107. {auditable-0.2.1 → auditable-0.3.0}/examples/example_live_replay.py +0 -0
  108. {auditable-0.2.1 → auditable-0.3.0}/examples/example_pre_lint_plan.py +0 -0
  109. {auditable-0.2.1 → auditable-0.3.0}/examples/example_standalone_report.py +0 -0
  110. {auditable-0.2.1 → auditable-0.3.0}/examples/example_touch_capture.py +0 -0
  111. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/_report_figures.py +0 -0
  112. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/compound.py +0 -0
  113. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/graph/adapters/declared_plan.py +0 -0
  114. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/graph/pre.py +0 -0
  115. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/graph/touch.py +0 -0
  116. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/integrations/langgraph.py +0 -0
  117. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/model/__init__.py +0 -0
  118. {auditable-0.2.1 → auditable-0.3.0}/src/auditable/report.py +0 -0
  119. {auditable-0.2.1 → auditable-0.3.0}/tests/test_audit_report.py +0 -0
  120. {auditable-0.2.1 → auditable-0.3.0}/tests/test_auditors.py +0 -0
  121. {auditable-0.2.1 → auditable-0.3.0}/tests/test_basic.py +0 -0
  122. {auditable-0.2.1 → auditable-0.3.0}/tests/test_compound.py +0 -0
  123. {auditable-0.2.1 → auditable-0.3.0}/tests/test_gate.py +0 -0
  124. {auditable-0.2.1 → auditable-0.3.0}/tests/test_graph.py +0 -0
  125. {auditable-0.2.1 → auditable-0.3.0}/tests/test_graph_execution_reach.py +0 -0
  126. {auditable-0.2.1 → auditable-0.3.0}/tests/test_langgraph_integration.py +0 -0
  127. {auditable-0.2.1 → auditable-0.3.0}/tests/test_langgraph_replay_bridge.py +0 -0
  128. {auditable-0.2.1 → auditable-0.3.0}/tests/test_pre.py +0 -0
  129. {auditable-0.2.1 → auditable-0.3.0}/tests/test_pre_coverage.py +0 -0
  130. {auditable-0.2.1 → auditable-0.3.0}/tests/test_replay.py +0 -0
  131. {auditable-0.2.1 → auditable-0.3.0}/tests/test_report.py +0 -0
  132. {auditable-0.2.1 → auditable-0.3.0}/tests/test_sink.py +0 -0
  133. {auditable-0.2.1 → auditable-0.3.0}/tests/test_touch.py +0 -0
  134. {auditable-0.2.1 → auditable-0.3.0}/tests/test_touch_replay_bridge.py +0 -0
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ ## 0.3.0 (2026-10-25)
4
+
5
+ 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.
6
+
7
+ ### Added
8
+
9
+ - `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.
10
+ - `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).
11
+ - `auditable.llm`: a `prompt -> reply` backend protocol, `FixedResponseBackend` for tests and replays, `OpenAICompatibleBackend` (standard library only), and a prediction cache.
12
+ - `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.
13
+ - Extras `tabular-ad`, `graph-ad` and `agentpile`; the core install still has no third-party dependency.
14
+ - `docs/methods-contract.md`, the contract a method follows and the behaviours a pinned consumer such as CatchBench relies on.
15
+
16
+ ### Behaviour of the Conversion
17
+
18
+ - 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.
19
+ - `convention="grade"` raises `ValueError` for a run from a dataset revision other than the one its projection was checked on.
20
+ - 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"`.
21
+
22
+ ### Deprecated
23
+
24
+ - `ActionGate`, `ReferenceLedger` and `DataAuditor` emit a `DeprecationWarning` when constructed and will be removed in a later release.
25
+
26
+ ## Earlier Releases
27
+
28
+ 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).
@@ -0,0 +1,340 @@
1
+ Metadata-Version: 2.5
2
+ Name: auditable
3
+ Version: 0.3.0
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
+ Project-URL: Homepage, https://github.com/yzhao062/auditable
6
+ Project-URL: Repository, https://github.com/yzhao062/auditable
7
+ Project-URL: Issues, https://github.com/yzhao062/auditable/issues
8
+ Project-URL: Documentation, https://auditable-ai.readthedocs.io/
9
+ Author-email: Yue Zhao <yzhao010@usc.edu>
10
+ License-Expression: Apache-2.0
11
+ License-File: LICENSE
12
+ Keywords: agent,agent-reliability,ai-agents,ai-safety,anomaly-detection,audit,auditing,benchmark,failure-attribution,failure-detection,fault-localization,graph-anomaly-detection,langgraph,llm,mcp,trustworthy-ai
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: Apache Software License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
+ Classifier: Topic :: Software Development :: Quality Assurance
24
+ Requires-Python: >=3.9
25
+ Provides-Extra: agentpile
26
+ Requires-Dist: agentpile[hf]<0.4,>=0.3; extra == 'agentpile'
27
+ Requires-Dist: numpy>=1.21; extra == 'agentpile'
28
+ Provides-Extra: anomaly
29
+ Requires-Dist: pyod>=1.1.0; extra == 'anomaly'
30
+ Provides-Extra: dev
31
+ Requires-Dist: build>=1.0; extra == 'dev'
32
+ Requires-Dist: pyod>=1.1.0; extra == 'dev'
33
+ Requires-Dist: pytest>=7.0; extra == 'dev'
34
+ Requires-Dist: twine>=5.0; extra == 'dev'
35
+ Provides-Extra: graph
36
+ Requires-Dist: networkx>=3.0; extra == 'graph'
37
+ Provides-Extra: graph-ad
38
+ Requires-Dist: networkx>=3.0; extra == 'graph-ad'
39
+ Requires-Dist: numpy>=1.21; extra == 'graph-ad'
40
+ Requires-Dist: pygod>=1.1.0; extra == 'graph-ad'
41
+ Requires-Dist: pyod>=1.1.0; extra == 'graph-ad'
42
+ Requires-Dist: scikit-learn>=1.0; extra == 'graph-ad'
43
+ Requires-Dist: torch-geometric>=2.3; extra == 'graph-ad'
44
+ Requires-Dist: torch>=2.0; extra == 'graph-ad'
45
+ Provides-Extra: langchain
46
+ Requires-Dist: langchain-core<2,>=0.3.0; extra == 'langchain'
47
+ Provides-Extra: langgraph
48
+ Requires-Dist: langgraph>=1.0; (python_version >= '3.10') and extra == 'langgraph'
49
+ Requires-Dist: networkx>=3.0; extra == 'langgraph'
50
+ Provides-Extra: llm
51
+ Requires-Dist: openai>=1.0; extra == 'llm'
52
+ Provides-Extra: mcp
53
+ Requires-Dist: mcp<2,>=1.28.1; (python_version >= '3.10') and extra == 'mcp'
54
+ Provides-Extra: report
55
+ Requires-Dist: fpdf2>=2.7; extra == 'report'
56
+ Requires-Dist: matplotlib>=3.5; extra == 'report'
57
+ Requires-Dist: networkx>=3.0; extra == 'report'
58
+ Provides-Extra: tabular-ad
59
+ Requires-Dist: networkx>=3.0; extra == 'tabular-ad'
60
+ Requires-Dist: numpy>=1.21; extra == 'tabular-ad'
61
+ Requires-Dist: pyod>=1.1.0; extra == 'tabular-ad'
62
+ Requires-Dist: scikit-learn>=1.0; extra == 'tabular-ad'
63
+ Description-Content-Type: text/markdown
64
+
65
+ <div align="center">
66
+
67
+ <!-- logo-family -->
68
+ <picture>
69
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/yzhao062/auditable/main/docs/assets/brand/logo-dark.svg">
70
+ <img src="https://raw.githubusercontent.com/yzhao062/auditable/main/docs/assets/brand/logo.svg" alt="auditable" width="350">
71
+ </picture>
72
+
73
+
74
+ # auditable
75
+
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.**
77
+
78
+ [![PyPI](https://img.shields.io/pypi/v/auditable.svg)](https://pypi.org/project/auditable/)
79
+ [![Python](https://img.shields.io/pypi/pyversions/auditable.svg)](https://pypi.org/project/auditable/)
80
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://github.com/yzhao062/auditable/blob/main/LICENSE)
81
+ [![CI](https://github.com/yzhao062/auditable/actions/workflows/ci.yml/badge.svg)](https://github.com/yzhao062/auditable/actions/workflows/ci.yml)
82
+
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)
84
+
85
+ </div>
86
+
87
+ `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
+
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)).
90
+
91
+ ## Quick Start
92
+
93
+ Install with `pip install "auditable[tabular-ad]"` (see [Install](#install)), then:
94
+
95
+ ```python
96
+ from sklearn.metrics import roc_auc_score
97
+
98
+ from auditable.datasets import make_traces
99
+ from auditable.methods import get_method
100
+
101
+ # 100 toy agent runs; each failed run holds one stale read (a step relying on old state)
102
+ traces, y, mistakes = make_traces(n_runs=100, contamination=0.5, random_state=0)
103
+ train, test = slice(0, 50), slice(50, 100)
104
+
105
+ # Did the run fail? Fit on labelled runs, then score new ones, as with a PyOD detector.
106
+ detector = get_method("run.lr_flatdep")()
107
+ detector.fit(traces[train], y[train])
108
+ scores = detector.decision_function(traces[test]) # one score per run, higher = more likely failed
109
+ print(f"run-level ROC-AUC: {roc_auc_score(y[test], scores):.3f}")
110
+
111
+ # Which step was the mistake? Rank the steps of each failed run, most suspected first.
112
+ locator = get_method("step.dep_anomaly")()
113
+ failed = [i for i in range(100) if y[i] == 1]
114
+ hits = sum(locator.rank(traces[i])[0] == mistakes[i] for i in failed)
115
+ print(f"mistake ranked first in {hits} of {len(failed)} failed runs")
116
+
117
+ # Can it be caught live? One causal alarm per arriving step (step t sees steps 0..t only).
118
+ monitor = get_method("online.span_z")()
119
+ alarms = monitor.step_alarm_scores(traces[failed[0]])
120
+ print(f"first alarm peak at step {alarms.argmax()}, mistake at step {mistakes[failed[0]]}")
121
+ ```
122
+
123
+ Every method is created from its ID with `get_method(id)()`, and the methods of one family share one interface, so trying another detector or locator changes one string. [`examples/example_methods.py`](https://github.com/yzhao062/auditable/blob/main/examples/example_methods.py) adds a configuration audit before the run.
124
+
125
+ ## Real Agent Traces
126
+
127
+ [agentpile](https://github.com/yzhao062/agentpile) loads public agent-trace datasets (Who&When, TRAIL, MAST, tau-bench, SWE-Gym and others), trace files (OpenAI-style messages, OTLP JSON, Claude Code sessions, MCP tool lists) and captured runs into one record. `from_agentpile` turns those records into the traces every method reads, and `configs_from_agentpile` turns them into the configurations the config methods read. `pip install "auditable[agentpile]"` installs the conversion; the example below also runs tabular methods, so it needs `pip install "auditable[agentpile,tabular-ad]"`.
128
+
129
+ ```python
130
+ import agentpile as ap
131
+ import auditable as au
132
+ from auditable.datasets import load_traces
133
+ from auditable.methods import get_method
134
+
135
+ # Any run: name the dependency rules, since agentpile infers none when it loads.
136
+ runs = list(ap.load("tau_bench", limit=100))
137
+ traces = au.from_agentpile(runs, deps=["tool_call_id_v1", "value_flow_v1"])
138
+ scores = get_method("run.pyod_ecod")().fit_score(traces) # one score per run
139
+ y = au.run_targets(traces) # 1 failed, 0 succeeded, -1 unknown
140
+
141
+ # The same shapes as make_traces, on a public dataset; mistakes holds the labeled step (-1 if none).
142
+ traces, y, mistakes = load_traces("who_and_when", deps="full_context", subset="Algorithm-Generated")
143
+ labeled = [t for t, m in zip(traces, mistakes) if m >= 0]
144
+ print(get_method("step.dep_anomaly")().rank(labeled[0])[:3])
145
+
146
+ # Before a run: an MCP tools/list result plus the task the agent will get.
147
+ configs = au.configs_from_agentpile(next(ap.load("tools.json")), task="Summarize the open issues.")
148
+ print(get_method("config.owasp_asi_combined")().audit(configs[0]))
149
+ ```
150
+
151
+ `deps` has no default. It is a list of agentpile rules, `"recorded"` for the dependencies the record already holds, or `"full_context"` for every earlier step, and each trace's `meta` keeps the rules that ran. The default `convention="generic"` makes one step per message and one per tool call with its result. `convention="grade"` with `deps="grade"` instead reproduces the steps, dependencies and graphs of the GRADE converters that CatchBench and the GRADE paper used, for the seven corpora below. [`benchmarks/agentpile_crosscheck`](https://github.com/yzhao062/auditable/tree/main/benchmarks/agentpile_crosscheck) compares that output with GRADE's run by run.
152
+
153
+ | Corpus | `load_traces` arguments | Runs in GRADE's output | Result |
154
+ |---|---|---|---|
155
+ | Who&When | `"who_and_when", convention="grade", deps="grade"` | 184 | equal; the 126 localization labels match |
156
+ | tau-bench | `"tau_bench", convention="grade", deps="grade", model=[...]` | 660 | equal |
157
+ | tau2-bench | `"tau2_bench", convention="grade", deps="grade", model=...` | 278 | equal to the frozen rule `tau2-frozen-v1`, since GRADE's own tau2 output changes with the hash seed |
158
+ | SWE-Gym | `"swe_gym_openhands", convention="grade", deps="grade"` | 376 | equal |
159
+ | AgentRewardBench | `"agent_reward_bench", convention="grade", deps="grade"` | 600 | equal on 3 runs; on the other 597, GRADE adds two steps for the page after the last action, which agentpile does not create, and the steps before them are equal |
160
+ | SWE-rebench OpenHands | `"swe_rebench_openhands", convention="grade", deps="grade"` | 600 | equal |
161
+ | SWE-agent | `"swe_agent_nebius", convention="grade", deps="grade"` | 600 | equal |
162
+
163
+ These results hold on the dataset revisions agentpile 0.3.0 loads by default. On any other revision, `convention="grade"` raises an error rather than return steps nobody has compared with GRADE's, and `convention="generic"` reads the run without that guarantee.
164
+
165
+ In the generic convention, a `user` step is a step the record attributes to the user role, which is not always text a person typed (a session's compact summary or a task notification has that role too). Content given as a list of parts (dicts with a string `type`, possibly mixed with bare strings) keeps its text; an image, a document or any other non-text part becomes a placeholder such as `[image]` and its other fields are dropped, while any other list stays JSON. `meta["report"]` counts the replaced parts and accounts for every step of the record.
166
+
167
+ A run with subagent trajectories (a Claude Code session with subagents, an Agents SDK handoff) raises an error, since this version does not flatten them into one trace. `from_agentpile(run.subagents, ...)` reads each subagent as a trace of its own, and `subagents="skip"` reads the top-level trajectory only; on the Claude Code sessions with subagents we measured, skipping left out about half of the steps.
168
+
169
+ ## Methods
170
+
171
+ Configuration rules and the step-by-step and binary-search LLM judges run on the core install, graph detectors need the `graph-ad` extra, and every other method needs `tabular-ad`. The tables are generated from the registry: `list_methods(family=...)` returns each method's card, and `method_table(detailed=True)` prints the fit scope, fidelity to the source, extras, and the CatchBench row each method reproduces. The [method contract](https://github.com/yzhao062/auditable/blob/main/docs/methods-contract.md) defines the four interfaces on one page.
172
+
173
+ ### Config: Is the Agent Over-Privileged Before It Runs?
174
+
175
+ `auditor.audit(config)` reads an `AgentConfig` (the declared capabilities and the task text) and returns a finding: `flag` (True, False, or None to abstain), the `excess` capabilities, and the `rules` that fired.
176
+
177
+ <!-- methods:config:start -->
178
+ | Type | Method | Algorithm | Reference |
179
+ |---|---|---|---|
180
+ | Rule | `config.flag_risky_perms` | Flag risky permission levels | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
181
+ | Rule | `config.owasp_asi_combined` | Combined OWASP and CWE scanner | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
182
+ | Rule | `config.owasp_excess_functionality` | Excess functionality | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
183
+ | Rule | `config.owasp_excess_permissions` | Excess permission level | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
184
+ | Rule | `config.owasp_privilege_escalation` | Unrequested privilege management | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
185
+ | Rule | `config.sensitive_access` | Unrequested sensitive access | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
186
+ | Rule | `config.unrequested_high_impact` | Unrequested high-impact action | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
187
+ | LLM judge | `config.llm_needed` | LLM judge, needed capabilities | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
188
+ <!-- methods:config:end -->
189
+
190
+ ### Online: Can the Failure Be Caught While the Run Streams?
191
+
192
+ `monitor.step_alarm_scores(trace)` returns one alarm per step, and the alarm at step t reads steps 0 to t only.
193
+
194
+ <!-- methods:online:start -->
195
+ | Type | Method | Algorithm | Reference |
196
+ |---|---|---|---|
197
+ | Rule | `online.dep_count_z` | Causal z-score of dependency count | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
198
+ | Rule | `online.dep_span` | Mean dependency span (running) | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
199
+ | Rule | `online.raw_span` | Raw dependency span | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
200
+ | Rule | `online.span_z` | Causal z-score of dependency span | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
201
+ | Baseline | `online.random` | Random alarm scores | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
202
+ <!-- methods:online:end -->
203
+
204
+ ### Run: Did the Run Fail?
205
+
206
+ `detector.fit(traces, y)`, then `detector.decision_function(traces)`: one score per run, higher meaning more likely failed. Unsupervised detectors ignore `y`. Transductive detectors (the PyGOD detectors and GUARDIAN-Lite) fit and score one batch together with `detector.fit_score(traces)`.
207
+
208
+ <!-- methods:run:start -->
209
+ | Type | Method | Algorithm | Reference |
210
+ |---|---|---|---|
211
+ | Supervised | `run.lr_flat` | Logistic regression on run size (GRADE flat) | [GRADE (Zhao, 2026)](https://arxiv.org/abs/2606.22741) |
212
+ | Supervised | `run.lr_flatdep` | Logistic regression on size and dependency (GRADE flatdep) | [GRADE (Zhao, 2026)](https://arxiv.org/abs/2606.22741) |
213
+ | Supervised | `run.lr_full` | Logistic regression on all raw layers (GRADE full) | [GRADE (Zhao, 2026)](https://arxiv.org/abs/2606.22741) |
214
+ | PyOD detector | `run.pyod_copod` | COPOD on run size | [COPOD (Li et al., 2020)](https://arxiv.org/abs/2009.09463) |
215
+ | PyOD detector | `run.pyod_ecod` | ECOD on run size | [ECOD (Li et al., 2022)](https://arxiv.org/abs/2201.00382) |
216
+ | PyOD detector | `run.pyod_hbos` | HBOS on run size | HBOS (Goldstein and Dengel, 2012) |
217
+ | PyOD detector | `run.pyod_iforest` | Isolation Forest on run size | [Isolation Forest (Liu et al., 2008)](https://doi.org/10.1109/ICDM.2008.17) |
218
+ | PyOD detector | `run.pyod_knn` | KNN distance on run size | KNN outlier score (Ramaswamy et al., 2000) |
219
+ | PyOD detector | `run.pyod_lof` | Local outlier factor on run size | [LOF (Breunig et al., 2000)](https://doi.org/10.1145/335191.335388) |
220
+ | Graph detector | `run.gsafeguard_lite` | G-Safeguard-Lite (supervised graph classifier) | [G-Safeguard (Wang et al., 2025)](https://arxiv.org/abs/2502.11127) |
221
+ | Graph detector | `run.guardian_lite` | GUARDIAN-Lite (attribute-reconstruction autoencoder) | [GUARDIAN (Zhou et al., 2025)](https://arxiv.org/abs/2505.19234) |
222
+ | Graph detector | `run.pygod_anomalydae` | AnomalyDAE dual autoencoder (PyGOD) | AnomalyDAE (Fan et al., 2020) |
223
+ | Graph detector | `run.pygod_conad` | CONAD contrastive graph autoencoder (PyGOD) | CONAD (Xu et al., 2022) |
224
+ | Graph detector | `run.pygod_dominant` | DOMINANT graph autoencoder (PyGOD) | [DOMINANT (Ding et al., 2019)](https://doi.org/10.1137/1.9781611975673.67) |
225
+ | Graph detector | `run.pygod_gaan` | GAAN adversarial detector (PyGOD) | GAAN (Chen et al., 2020) |
226
+ | Baseline | `run.random` | Random run scores | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
227
+ <!-- methods:run:end -->
228
+
229
+ ### Step: Which Step Was the Decisive Mistake?
230
+
231
+ `locator.rank(trace)` orders the steps of a failed run, most suspected first, and `locator.step_scores(trace)` gives their scores. Supervised locators are first fitted with `fit(traces, y)`, where `y` holds the `idx` of each run's mistake. The step-by-step and binary-search LLM judges name one step with `predict_step(trace)`.
232
+
233
+ <!-- methods:step:start -->
234
+ | Type | Method | Algorithm | Reference |
235
+ |---|---|---|---|
236
+ | Rule | `step.blast` | Blast radius (downstream reach) | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
237
+ | Rule | `step.degree` | Dependency degree | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
238
+ | Rule | `step.dep_anomaly` | Dependency anomaly (within-run z-score) | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
239
+ | Rule | `step.has_dep` | Has a dependency | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
240
+ | Rule | `step.max_span` | Maximum dependency span | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
241
+ | Rule | `step.position_early_rule` | Early-position prior | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
242
+ | Supervised | `step.exec_rank` | Execution-feature step ranker | [GRADE (Zhao, 2026)](https://arxiv.org/abs/2606.22741) |
243
+ | Supervised | `step.position_supervised` | Early-fault position prior | [GRADE (Zhao, 2026)](https://arxiv.org/abs/2606.22741) |
244
+ | Graph detector | `step.pygod_dominant_sg4` | DOMINANT on the step dependency graph | [DOMINANT (Ding et al., 2019)](https://doi.org/10.1137/1.9781611975673.67) |
245
+ | Graph detector | `step.pygod_dominant_ww8` | DOMINANT on the Who&When step matrix | [DOMINANT (Ding et al., 2019)](https://doi.org/10.1137/1.9781611975673.67) |
246
+ | LLM judge | `step.llm_all_at_once` | LLM judge, all-at-once | [Who&When (Zhang et al., 2025)](https://arxiv.org/abs/2505.00212) |
247
+ | LLM judge | `step.llm_binary_search` | LLM judge, binary-search | [Who&When (Zhang et al., 2025)](https://arxiv.org/abs/2505.00212) |
248
+ | LLM judge | `step.llm_step_by_step` | LLM judge, step-by-step | [Who&When (Zhang et al., 2025)](https://arxiv.org/abs/2505.00212) |
249
+ | Baseline | `step.random` | Random step scores | [CatchBench (2026)](https://arxiv.org/abs/2608.22808) |
250
+ <!-- methods:step:end -->
251
+
252
+ ## Install
253
+
254
+ ```bash
255
+ pip install auditable # core: the registry and the configuration rules, no third-party dependencies
256
+ pip install "auditable[tabular-ad]" # run, step, and online methods on trace features (NumPy, scikit-learn, PyOD, NetworkX)
257
+ pip install "auditable[agentpile]" # read public datasets, trace files and captured runs through agentpile
258
+ ```
259
+
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]"`.
261
+
262
+ The LLM judges take any `prompt -> reply` function as their backend; `OpenAICompatibleBackend` reaches an OpenAI-compatible endpoint with the standard library alone.
263
+
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:
265
+
266
+ ```bash
267
+ pip install "torch==2.12.1" --index-url https://download.pytorch.org/whl/cpu
268
+ pip install pyg_lib -f https://data.pyg.org/whl/torch-2.12.1+cpu.html
269
+ pip install "auditable[graph-ad]"
270
+ python -c "import torch_geometric.typing as t; assert t.WITH_PYG_LIB"
271
+ ```
272
+
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.
274
+
275
+ ## Traces and Inputs
276
+
277
+ Methods read traces through `auditable.featurize.normalize_trace`, which accepts a list of step dicts, a run dict (`{"steps": ..., "texts": ...}`), a typed NetworkX graph from `auditable.graph.build_graph`, a `SessionGraph`, or the `TraceView` that `from_agentpile` returns. Steps carry `idx`, `agent`, `kind` (`"decision"` or `"tool_call"`), and optionally `deps` and `text`; a `SessionGraph` also keeps parallel branches and merges of the execution order. A trace without dependency annotations can be read with `dependency="full_context"`, the assumption that each step relied on every earlier step. A method that needs a field the trace lacks (step text for an LLM judge, for example) raises an error naming it.
278
+
279
+ `auditable.featurize` exposes the features the methods compute, so they can be inspected or reused: the GRADE structural layers (`grade_layer`, `grade_layer_matrix`), the Who&When step matrix (`who_when_step_matrix`), the step dependency graph and its statistics (`step_graph`, `span_series`, `run_max_span`), and graph encodings for PyGOD (`to_pyg`).
280
+
281
+ ## Reproducing CatchBench
282
+
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.
284
+
285
+ ```bash
286
+ export GRADE_DIR=/path/to/grade # checked out at 3839a57
287
+ export PYTHONHASHSEED=0
288
+ python benchmarks/catchbench_parity/run_parity.py checks # per-sample comparisons
289
+ python benchmarks/catchbench_parity/run_parity.py board --out board.txt # the full board through the library
290
+ python benchmarks/catchbench_parity/run_parity.py board --perturb --out perturbed.txt
291
+ python benchmarks/catchbench_parity/run_parity.py consumption board.txt perturbed.txt
292
+ ```
293
+
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
+ ## Adding a Method
297
+
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.
299
+
300
+ ## Records and Graph Analysis
301
+
302
+ The package also contains the modules it was first built around. `audit` and `replay` capture an agent decision with the dependency state it relied on and re-decide it against later state; `analyze_run` ranks the steps of a finished run by structural blast share; `analyze_plan` lints a declared plan; `LiveSession` scores a growing run; and `auditable.integrations` captures observed dependency edges from LangGraph, LangChain, MCP servers, or any loop through `TouchRecorder`. See [`examples/README.md`](https://github.com/yzhao062/auditable/blob/main/examples/README.md) and the [documentation](https://auditable-ai.readthedocs.io/).
303
+
304
+ Records are content-addressed and hash-chained, and that property is limited. A signature or digest authenticates only the entries that were submitted, a hash chain exposes a later edit only when its head is anchored with an independent party, and neither reveals an event that was never written. The chain therefore does not establish that a log is complete.
305
+
306
+ ### Legacy
307
+
308
+ `ActionGate`, `ReferenceLedger` (the in-process reference rail), and `DataAuditor` are deprecated as of 0.3 and emit a `DeprecationWarning` when constructed. They remain importable and will be removed in a later release. Tabular anomaly detection on dependency snapshots belongs in [PyOD](https://github.com/yzhao062/pyod).
309
+
310
+ ## Related Projects
311
+
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.
314
+ - [GRADE](https://arxiv.org/abs/2606.22741): the typed two-layer graph of agent execution and dependency that the structural features read.
315
+ - [awesome-auditable-ai](https://github.com/yzhao062/awesome-auditable-ai): a reading list on AI agent reliability and auditing.
316
+
317
+ ## Citation
318
+
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:
320
+
321
+ ```bibtex
322
+ @article{zhao2026grade,
323
+ title = {GRADE: Graph Representation of LLM Agent Dependency and Execution},
324
+ author = {Zhao, Yue},
325
+ journal = {arXiv preprint arXiv:2606.22741},
326
+ year = {2026}
327
+ }
328
+
329
+ @misc{zhao2026catchbench,
330
+ title = {{CatchBench}: When Can an Agent Failure Be Caught?},
331
+ author = {Yue Zhao},
332
+ year = {2026},
333
+ eprint = {2608.22808},
334
+ archivePrefix = {arXiv}
335
+ }
336
+ ```
337
+
338
+ ## License
339
+
340
+ [Apache-2.0](https://github.com/yzhao062/auditable/blob/main/LICENSE). Ported code keeps the notice of its source (GRADE and CatchBench, both MIT License) at the top of each module.