Repository navigation
test(agent): golden-trace regression harness - #69
Merged
Merged
Conversation
A persisted, reviewed corpus of four agent sessions (read-only chain, confirm-then-apply proposal, verbatim gate refusal, budget exhaustion) replayed offline in CI — no API key, no anthropic SDK — at both levels: agent.turn directly and POST /agent/chat through parse_sse. - agent_fakes.RecordingClient: the capture half; wraps a real client, serializes each round into the fixture format via to_trace(). CI only replays. - Each replay asserts ordered tool sequences, argument shapes against the LIVE registry schemas, allowlist enforcement by name (never counts), fixed event ordering, the 6-round budget, the truncation marker, confirm-then-apply invariants (proposal reaches the sink; the model context carries "nothing is applied yet", never the apply payload), and honesty wording in the final text. Fixes #47 Co-authored-by: Tapan Ganatma Nakkina <[email protected]>
The registry holds nine tools; the loop tests already assert by name, so the docstring now says so instead of naming a count that drifts. Co-authored-by: Tapan Ganatma Nakkina <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The agent's ~930 lines of existing tests all hand-write their model scripts inline: loop behavior, argument shapes, and refusal wording are pinned per-test, but no persisted corpus of full sessions exists. A registry rename, a schema drift, or a gate-wording change that slips between the cracks of unit tests has nothing to catch it. This is deliverable BACKLOG-4 of the backlog program (issue #47).
What
A persisted, reviewed corpus of four full agent sessions in
tests/fixtures/golden/, replayed offline in CI bytests/test_agent_golden.py— no API key, no anthropic SDK, no new dependency:01-read-only-chain.jsonsearch_shots→load_shot→limit_distances, ends in a prose answer02-run-whatif-proposal.jsonrun_whatifproposes, the model asks, the loop ends before apply03-gate-refusal.jsonrun_whatifthe gate refuses 422; the model explains the refusal verbatim and never retries04-budget-exhaustion.jsonEvery trace replays at both levels — the loop (
agent.turn) and the HTTP surface (POST /agent/chatthroughparse_sse) — and the sharedassert_goldenchecks: ordered tool sequences with the recorded args; argument keys ⊆ the live tool'sinput_schema.propertieswith required keys present; no name outsideagent_tools.TOOLSdispatched, withrun_tool's unknown-tool text pinned against the live name list (names, never counts — a hardcoded count already drifted once); fixed event ordering (tool_call → tool_resultpairs, exactly one terminal event); the 6-round budget and theTOOL_RESULT_MAX_CHARStruncation marker; confirm-then-apply invariants (the proposal reaches the sink and theaction_proposedevent; the model context carries "nothing is applied yet" and never the apply payload); streamed text reproduces the corpus exactly; honesty wording in every prose-final turn.The corpus is hand-authored reviewed exemplars — that is the recording path:
agent_fakes.RecordingClientexists for one-time key-bearing capture, and its serialization round-trip is itself tested — while CI only replays. The "model" in a golden trace is the fixture, so this pins loop + registry + gates, never model quality. Hermetic throughout: the suite runs with the key deleted, and the pristine-interpreter "app import never loads the anthropic SDK" check is extended to the new module. Also fixes the stale "eight allowlisted definitions" docstring intests/test_agent_loop.py(the registry holds nine — the exact drift this harness's name-based assertions prevent).How to Review
tests/test_agent_golden.py— the harness;assert_goldenis the contract, the per-trace tests below it are specifics.tests/fixtures/golden/*.json— the corpus; reviewed exemplars, not generated output.tests/agent_fakes.py—RecordingClient+to_trace()(the capture half, never constructed in CI).Test Evidence
Backend-only change (test layer): rendered UI surface unchanged, so visual dogfood evidence is not applicable.
make test: 497 passed, 1 skipped (93 s) against the fresh pre-change baseline of 476 passed, 1 skipped — the +21 are the new golden tests.uv run ruff checkclean;uv run mypy fusionlabclean (33 files).load_shot: argument key(s) ['shot_ids'] not in the live input_schema— and the restored fixture replays green; the same three corruptions (wrong arg key, out-of-allowlist name, dropped proposal round) are pinned permanently bytest_the_harness_fails_loudly_on_a_mutated_trace.Fixes #47
Human author: Tapan Ganatma Nakkina ([email protected])
🔗 Obvious Project · 🧵 Obvious Thread · 🔀 Obvious PR Artifact