From a57313ba9077a0904eaf38af066c19830bc726f9 Mon Sep 17 00:00:00 2001 From: Yev Meyer Date: Fri, 30 Oct 2026 19:17:57 -0400 Subject: [PATCH 1/6] docs(engine): list every probe hook and declaration, checked by a test architecture/probes.md lists every public method of BaseProbe, BankBackedProbe and the six mixins in its hook table, with where each is called, and every class attribute and classmethod in a new table, with its default and what reads it. tests/test_reference_docs.py fails when a public name on those classes has no row, when a row names nothing they define, when a method sits outside the hook table, or when a documented default value differs from the class. BaseProbe defines should_inline_judge_user_turn and should_inline_judge_assistant_turn, and AgenticMixin overrides the first, but nothing calls either. The tables, the authoring guide, the docstrings and the agentic template say so. Signed-off-by: Yev Meyer --- architecture/probes.md | 69 ++++++++++++++++-- docs/engine/AUTHORING_A_PROBE.md | 4 +- src/usersim/engine/core/probes.py | 24 +++--- templates/probe/generator_agentic.py | 4 +- tests/test_reference_docs.py | 105 +++++++++++++++++++++++++++ 5 files changed, 180 insertions(+), 26 deletions(-) create mode 100644 tests/test_reference_docs.py diff --git a/architecture/probes.md b/architecture/probes.md index 908dc9a..d402545 100644 --- a/architecture/probes.md +++ b/architecture/probes.md @@ -30,10 +30,13 @@ Shipped probes are listed by module in `BUILTIN_PROBE_MODULES` looked up, which is when their decorators run. Out-of-tree probes are imported through the `usersim.probes` entry-point group instead. -## Hooks the loop calls +## Hooks -`core/simulation.py` calls these on the probe. Only the first two are -required; the rest have working defaults on `BaseProbe`. +The conversation loop in `core/simulation.py` calls most of these on the probe; +the table says where the others are called from. Only the first two are +required, plus `derive_task` on a `BankBackedProbe` and `execute_tool_call` +with `ToolExecutionMixin`; the rest have working defaults on `BaseProbe` or the +mixin that adds them. | Hook | When | |---|---| @@ -45,6 +48,7 @@ required; the rest have working defaults on `BaseProbe`. | `format_followup_user_instructions` | turns after the first | | `on_followup_failure` | a follow-up turn fails its gate | | `get_tools_for_assistant` | tool-using probes | +| `transform_assistant_history` | every assistant call: the copy of the history the assistant sees, which may differ from the stored transcript | | `after_assistant_turn` | after each assistant reply; may execute tools | | `format_assistant_judge_prompt` | in-sim assessment of the assistant turn | | `is_capitulation_detected` | pressure probes checking for a flip | @@ -52,13 +56,32 @@ required; the rest have working defaults on `BaseProbe`. | `user_turn_policy` | once per trajectory: whether earlier replies may be summarized for context management, whether the last follow-ups may wrap up, which filter phrases the user may write, which names the script check skips, and a check each generated opening must pass before the gate | | `seed_state_metadata` | recording bank/seed provenance on the row | | `build_result_extras` | adding probe-specific columns to the trajectory, each declared in the class's `output_columns` | +| `should_succeed` | the end of the conversation: whether the probe completed its protocol; `False` fails the row | +| `derive_task` | constructing a `BankBackedProbe`: the bank entry the row runs on | +| `run_dispatch` | once per row, from the dispatcher: runs the conversation, by default through the loop | +| `execute_tool_call` | `ToolExecutionMixin`: each tool call the assistant makes | +| `parse_tool_call` | `ToolExecutionMixin`: reading a tool call's name and arguments | +| `on_tool_round_complete` | `ToolExecutionMixin`: after each round of tool calls | +| `on_tool_call_executed` | after each tool call runs: `ToolExecutionMixin` calls it, and a probe that runs tool calls itself must | +| `set_tool_call_observer` | an external host, to watch the tool calls the probe runs | +| `should_inline_judge_user_turn` | never (see below) | +| `should_inline_judge_assistant_turn` | never (see below) | + +`should_inline_judge_user_turn` and `should_inline_judge_assistant_turn` are +defined on `BaseProbe`, but nothing calls them: every generated user turn goes +through the gate and every assistant turn through the judge, whatever they +return. + +Two helpers are for the probe to call: + +| Helper | Gives | +|---|---| +| `theme` | the row's theme, one of those `themes` lists | +| `assets_dir` | the probe's asset folder, `/