Skip to content

test(desktop): pin the RelayAgentInfo Tauri payload to snake_case - #6245

Open
rmichelena wants to merge 1 commit into
block:mainfrom
rmichelena:bumble/pin-relay-agent-info-payload-contract
Open

test(desktop): pin the RelayAgentInfo Tauri payload to snake_case#6245
rmichelena wants to merge 1 commit into
block:mainfrom
rmichelena:bumble/pin-relay-agent-info-payload-contract

Conversation

@rmichelena

Copy link
Copy Markdown

Summary

Add one regression test pinning that RelayAgentInfo crosses the Tauri boundary with
snake_case keys, and that the camelCase spellings never appear on the wire.

No behaviour change — this is a test-only PR closing a silent-failure hole.

Why

RelayAgentInfo is the payload of list_relay_agents and revalidate_relay_agents, and
the frontend maps it by hand. fromRawRelayAgent (desktop/src/shared/api/tauri.ts:655)
reads owner_pubkey, agent_type, channel_ids, respond_to and respond_to_allowlist
and rewrites them to camelCase for the RelayAgent type.

That contract rests entirely on the struct not carrying #[serde(rename_all = "camelCase")].
Adding it is the reflex when a Rust struct feeds a TypeScript client, and here it fails
silently in both directions:

  • RawRelayAgent (tauri.ts:101) marks all five fields optional, so the mapper does not
    throw — it produces null / [] / null.
  • Nothing in the repo asserts the wire shape, so no test goes red.

The runtime result is every relay agent arriving owner-less, typeless, channel-less and
with respondTo: null — which relayAgentIsSharedWithUser
(desktop/src/features/agents/lib/agentAutocompleteEligibility.ts:39) treats as deny.
The whole relay directory would quietly stop being mentionable, with a green build.

The blast radius grew recently: owner_pubkey and channel_ids were added to this struct
after the original mapper, so it is five hand-mapped fields now, not three.

Validation

just desktop-tauri-test runs this (.github/workflows/ci.yml:204
cd desktop/src-tauri && cargo test --workspace, path-filtered on desktop/src-tauri/**),
so the test actually executes in CI rather than only existing.

Acceptance criterion checked by breaking it, not just by watching it pass: adding
#[serde(rename_all = "camelCase")] to RelayAgentInfo makes the test fail on the first
assertion (owner_pubkey absent); removing it makes it pass again. A contract test that
does not go red when the contract breaks buys nothing.

  • cd desktop/src-tauri && cargo test --workspace relay_agent_info_wire_keys — 1 passed
  • cargo fmt clean

Notes

The test lives next to the existing serde-contract tests in the same file
(respond_to_serde_is_kebab_case, and the needs_restart / restart_diff snake_case
assertion at the end), so it follows the file's established shape rather than introducing
a new one.

Split out of #5483, which I closed as superseded by #6086 / #6182 / #6224 — those PRs
implemented the directory work it proposed, but nothing carried this contract test across.

RelayAgentInfo is the payload of list_relay_agents and
revalidate_relay_agents, and the frontend maps it by hand:
fromRawRelayAgent in desktop/src/shared/api/tauri.ts reads owner_pubkey,
agent_type, channel_ids, respond_to and respond_to_allowlist and rewrites
them to camelCase.

That contract rests entirely on this struct not carrying
#[serde(rename_all = "camelCase")]. Adding it is the reflex when a Rust
struct feeds a TypeScript client, and here it fails silently: RawRelayAgent
marks all five fields optional, so the mapper does not throw -- it yields
null / [] / null -- and nothing in the repo asserts the wire shape, so no
test goes red. Every relay agent would arrive owner-less, typeless,
channel-less and with respondTo null, which relayAgentIsSharedWithUser
treats as deny. The directory would stop being mentionable on a green build.

The blast radius grew recently: owner_pubkey and channel_ids joined this
struct after the mapper was written, so it is five hand-mapped fields now.

The test asserts both halves -- the snake_case keys are present with the
expected values, and the camelCase spellings are absent -- because only the
second half catches an added rename_all. Checked by breaking it, not by
watching it pass: with rename_all = "camelCase" the test fails on the
owner_pubkey assertion, and passes again once removed.

It sits with the existing serde-contract tests in the same file
(respond_to_serde_is_kebab_case, and the needs_restart / restart_diff
snake_case assertion), and runs in CI through just desktop-tauri-test.

Split out of block#5483, closed as superseded by block#6086, block#6182 and block#6224 -- those
implemented the directory work it proposed, but nothing carried this
contract across.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
@rmichelena
rmichelena requested a review from a team as a code owner August 18, 2026 17:27
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