Skip to content

test: Assert genuine memory retrieval in the rehydration smoke - #622

Open
AlexanderZ-Band wants to merge 3 commits into
mainfrom
test/int-1226-memory-rehydration-tool-result
Open

test: Assert genuine memory retrieval in the rehydration smoke#622
AlexanderZ-Band wants to merge 3 commits into
mainfrom
test/int-1226-memory-rehydration-tool-result

Conversation

@AlexanderZ-Band

@AlexanderZ-Band AlexanderZ-Band commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • test_memory_survives_adapter_rehydration only checked that the reply echoed a marker string — a marker present in the test's own prompt, so it passes even if get_memory returns nothing or the wrong record. mem.calls proves only that tools fired; mem.stored queries the memory store directly, independent of the turn's tool_result. Neither proves what band_get_memory's tool_result actually carried.
  • Adds results.assert_succeeded(MemoryTool.GET.value, output_contains=marker) via capture.tool_results(), matching the existing FileTool.READ assertion pattern two tests below in the same file.
  • OpencodeAdapter._report_tool_result never included ToolEventKey.NAME or ToolEventKey.IS_ERROR in its tool_result payload. parse_tool_result requires name and silently drops any event missing it; is_error defaults to False when absent. Net effect: every OpenCode tool_result was unparseable, and a failed tool call was indistinguishable from a successful one. Fixed by threading tool_name and is_error through _report_tool_result, mirroring _report_tool_call's existing shape.

Closes INT-1226.

Verification

  • Fault-injection: output_contains=marker + "-WRONG" against anthropic fails with the real ToolResults.assert_succeeded error and the actual tool_result payload; reverted to the correct marker, passes.
  • Live: anthropic, opencode, gemini all pass against the real platform.
  • tests/adapters/opencode/ — 76 passed.
  • tests/ --ignore=tests/integration/ --ignore=tests/e2e/ — 5590 passed, 146 skipped, 0 failed.
  • ruff check / ruff format --check / pyrefly check — clean.

Not fixed here

  • ToolResults.assert_succeeded fails on any same-named tool_result with is_error=True in a turn, even if a different matching result succeeded and carried the expected content. Shared by every assert_succeeded caller — needs its own review, not a drive-by here.
  • Same missing-mandatory-field pattern in two other adapters, untouched by this PR: src/band/adapters/letta.py::_report_execution_event and src/band/integrations/crewai/reporting.py::EmitToolCallsReporter both omit ToolEventKey.TOOL_CALL_ID.

Test plan

  • Live E2E: test_memory_survives_adapter_rehydration[anthropic], [opencode], [gemini]
  • Fault-injection: assertion fails on wrong marker, passes on correct one
  • tests/adapters/opencode/ — 76 passed
  • Full offline suite — 5590 passed, 0 failed
  • Lint/format/type-check clean

🤖 Generated with Claude Code

AlexanderZ-Band and others added 2 commits September 8, 2026 03:39
_report_tool_result built its tool_result payload with only output and
tool_call_id, never name -- unlike _report_tool_call, which already
carries it. band.converters.parsing.parse_tool_result requires name and
silently drops (logs, doesn't raise) any event missing it, so every
OpenCode tool_result has been unparseable by the shared decoder since
day one, for every tool, not just one framework's memory calls.

This went unnoticed because nothing has asserted OpenCode tool_result
*content* until now: the sibling file-transfer test that also reads
tool_results is gated behind Capability.FILES/ff_file_transfer, which is
off on every SaaS/CI environment, so it never actually exercised this
path against real opencode either. Confirmed live: adding a tool_result
content assertion to the memory rehydration smoke (next commit) reproduced
the warning and zero matched results before this fix, and passed after it.

Thread tool_name through to _report_tool_result the same way
_report_tool_call already receives it, and lock the name into the
existing tool-events unit test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W8z6z1muD8yg9Y3pre92ec
… smoke

test_memory_survives_adapter_rehydration proved a rebooted adapter
recalled its stored memory only by checking the reply echoed a marker
string -- a marker baked into the test's own instruction, so a model
could satisfy this by restating its prompt without get_memory ever
returning the right record. mem.calls only proves the tools fired
(tool_call events, args only); mem.stored proves a record exists via a
direct memories-API query, independent of the turn's own tool_result.
Neither proves what band_get_memory's tool_result actually carried back
during the turn.

Assert on the tool result directly via capture.tool_results(), the same
mechanism (and pattern) already proven for FileTool.READ in the file/image
round-trip tests two tests below in this file.

Verified live end-to-end: a deliberately wrong expected string made the
assertion fail with the real ToolResults.assert_succeeded error and the
actual observed payload; reverting to the correct marker passed. Confirmed
against anthropic, opencode (see prior commit), and gemini.

INT-1226

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W8z6z1muD8yg9Y3pre92ec
@linear-code

linear-code Bot commented Sep 8, 2026

Copy link
Copy Markdown

INT-1226

@AlexanderZ-Band
AlexanderZ-Band requested a review from a team September 8, 2026 00:52
_report_tool_result wrapped a failed tool's error text inside output
(e.g. {"error": "..."}), but never set ToolEventKey.IS_ERROR itself --
parse_tool_result defaults is_error=False when the key is absent, so a
genuinely failed OpenCode tool call was indistinguishable from a
successful one to any consumer gating on that flag, including this
same diff's own ToolResults.assert_succeeded. Same root cause as the
prior commit's missing-name bug: a mandatory ToolEventKey field silently
absent from this one adapter's tool_result payload.

Found by /code-review while verifying the memory-rehydration fix; fixing
it here since it's the same function this branch already touches.

Extends event_tool_part (the shared test fixture) with an error status
branch instead of hand-rolling the raw event, and adds a regression test
plus a name assertion on the pre-existing MCP-prefix-canonicalization
test's tool_result (that test already drives a tool to completion,
exercising the exact method the prior commit changed, but never checked
its result's name).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W8z6z1muD8yg9Y3pre92ec
@AlexanderZ-Band AlexanderZ-Band changed the title test: assert genuine memory retrieval in the rehydration smoke test: Assert genuine memory retrieval in the rehydration smoke Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant