Skip to content

fix: correct Prompt serialization, Test.metadata alias, and multi-turn NPE#5

Merged
harry-rhesis merged 1 commit into
mainfrom
fix/test-metadata
Apr 20, 2026
Merged

fix: correct Prompt serialization, Test.metadata alias, and multi-turn NPE#5
harry-rhesis merged 1 commit into
mainfrom
fix/test-metadata

Conversation

@harry-rhesis
Copy link
Copy Markdown
Contributor

Summary

Fixes #3 and two additional bugs discovered during the audit.

  • Prompt.expectedResponse / languageCode now serialize at the top level — previously they were nested under prompt.metadata, causing the backend to silently drop them. Generated tests had no expected response on the platform.
  • Prompt.role removed — was never part of the backend API or Python SDK.
  • Test.metadata deserializes from the backend's test_metadata key — the backend renames metadatatest_metadata in GET responses to avoid a SQLAlchemy naming conflict. @JsonAlias("test_metadata") is now added so test.metadata() is no longer always null after a round-trip.
  • MultiTurnSynthesizer no longer NPEs on missing min_turns/max_turns — an LLM can omit these fields even when the schema marks them required. Values are now treated as optional, matching the Python SDK.

Test plan

All 55 unit tests + 5 live-backend integration tests pass.

Fixes #3 and two related bugs
discovered during the audit.

- Prompt: add `expectedResponse` and `languageCode` as direct top-level fields
  (JSON: `expected_response`, `language_code`) so they are sent to the backend
  as siblings of `content` rather than nested under `metadata`. Previously the
  backend silently dropped them, leaving no expected response on the platform.
- Prompt: remove `role` field — it was never part of the backend API or Python SDK.
- Prompt: annotate with `@JsonInclude(NON_NULL)` so unset fields are omitted.
- Test: add `@JsonAlias("test_metadata")` on `metadata` so it deserialises from
  the backend's GET response key (`test_metadata`) that differs from the POST key
  (`metadata`). Previously `test.metadata()` was always null after a round-trip.
- MultiTurnSynthesizer: null-guard `min_turns`/`max_turns` before casting to int.
  An LLM can omit these fields even when the schema marks them required, causing
  a NullPointerException. Values are now treated as optional, matching the Python
  SDK.

Tests added:
- BaseSynthesizerTest: null-turns NPE regression + numeric-turns positive case
- ClientWiremockTest: WireMock guard asserting `expected_response`/`language_code`
  appear at `$.tests[0].prompt.*` in outbound POST /test_sets/bulk requests
- EntityTest: JSON-tree regression guard for top-level Prompt fields; alias tests
  for both `metadata` and `test_metadata` deserialization paths
- PromptRoundTripIntegrationTest: live backend round-trip for `expected_response`
- TestSetRoundTripIntegrationTest: live backend round-trips for multi-turn
  `test_configuration` fields and `test_metadata` → `metadata` alias
@harry-rhesis harry-rhesis merged commit 3379b7b into main Apr 20, 2026
2 checks passed
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.

expected_response nested under prompt.metadata instead of directly on prompt, causing test evaluation to fail

1 participant