Context
When a call assertion fails, the output shows only the expected value and the one
call it happened to compare against:
✗ Failed: Called with only checks last call
Expected 'first'
but got 'second'
The full call log is already on disk in the spy's params file, one line per
call. Nothing surfaces it. Same for assert_have_been_called_times, which prints
the counts but not what those calls were.
Proposal
On failure, append the recorded calls to the failure block:
✗ Failed: Called with only checks last call
Expected 'first'
but got 'second'
Recorded calls to 'touch' (2):
1: first
2: second
Applies to assert_have_been_called, assert_have_been_called_with,
assert_have_been_called_nth_with, assert_have_been_called_times and
assert_not_called.
Cap the dump (e.g. first 10 + a … and N more line) so a spy on a command called
hundreds of times does not flood the report.
Cost is paid only on the failure path, so the per-test fork budget in
.claude/rules/perf-fork-budget.md is unaffected — but read the params file with
$(<file) / while read, not cat, to keep the failure path cheap too.
Why this matters for agentic coding
An agent debugging a failed call assertion currently has to guess: was the
command called with different arguments, called in a different order, or called
more times than expected? Each guess costs a full edit-run-read cycle. The
information needed to fix it in one pass already exists on disk — printing it
turns a multi-turn debug loop into a single read.
This is the same reasoning behind the existing Source: block in failure
output: put what the reader needs to act in the failure itself.
Acceptance criteria
Context
When a call assertion fails, the output shows only the expected value and the one
call it happened to compare against:
The full call log is already on disk in the spy's params file, one line per
call. Nothing surfaces it. Same for
assert_have_been_called_times, which printsthe counts but not what those calls were.
Proposal
On failure, append the recorded calls to the failure block:
Applies to
assert_have_been_called,assert_have_been_called_with,assert_have_been_called_nth_with,assert_have_been_called_timesandassert_not_called.Cap the dump (e.g. first 10 + a
… and N moreline) so a spy on a command calledhundreds of times does not flood the report.
Cost is paid only on the failure path, so the per-test fork budget in
.claude/rules/perf-fork-budget.mdis unaffected — but read the params file with$(<file)/while read, notcat, to keep the failure path cheap too.Why this matters for agentic coding
An agent debugging a failed call assertion currently has to guess: was the
command called with different arguments, called in a different order, or called
more times than expected? Each guess costs a full edit-run-read cycle. The
information needed to fix it in one pass already exists on disk — printing it
turns a multi-turn debug loop into a single read.
This is the same reasoning behind the existing
Source:block in failureoutput: put what the reader needs to act in the failure itself.
Acceptance criteria
… and N moremarker (no silent truncation)--simpleoutput mode (assert on the helper, not onprint_linestdout — see
.claude/skills/gh-issues/SKILL.md)make sa+make lintgreen