Skip to content

fix(sdk): read a result whose numeric or boolean per-run params are echoed back - #8

Merged
mrmx merged 1 commit into
mainfrom
fix/scalar-param-coercion
Oct 25, 2026
Merged

mrmx merged 1 commit into
mainfrom
fix/scalar-param-coercion

Conversation

@mrmx

@mrmx mrmx commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

What

A backtest started with a numeric or boolean per-run params value could not be read back. The platform ran the job and echoed the parameters in the result, but deserializing it failed:

Failed deserialization for ScalarStrategyParamValue: 3 classes match result, expected 1

By the type of the value: an integer matched 3 members, a decimal or a boolean 2; only a string worked. Through the MCP server this showed up as a job that ended FAILED for every numeric parameter.

Cause

ScalarStrategyParamValue is oneOf: [number, string, boolean]. The generated client reads a oneOf by trying each member and requiring exactly one to accept the value, but Jackson's default scalar coercion also accepts a JSON number as a string and as a boolean (and, for the integer, as a decimal as well). With ALLOW_COERCION_OF_SCALARS off, 20, 20.5, true and "abc" each match exactly one member.

Fix

ApiClients.create() builds the generated client with that feature off, and QTSurfer.builder().build() and authenticate(...) use it. The mapper has to be installed with setObjectMapper(...): getObjectMapper() hands out a copy on each call, so configuring what it returns changes nothing, and the API classes take their mapper from the client when they are built.

Tests

  • ApiClientsTest: a whole number, a decimal, a boolean and a string (including strings that look like a number or a boolean), and a ResultMap echoing mixed params.
  • BacktestResultTest and AuthenticatedClientTest: a result with numeric, boolean and string params, read through QTSurfer and through the session authenticate(...) returns. The first run of these failed on the version of ApiClients that configured the mapper in place, which is what led to the setObjectMapper form.
  • mvn verify: 157 tests pass (2 skipped, as before).

Checked live

The built classes against the live API (OpenAPI 0.128.47): account and usage, exchanges (whose segments and liveSegments are sets), instruments, pools, datasets, a klines dataset, a finished dataset import, strategies, live runs, a backtest with cycle.seconds=20 (72 trades, the parameter echoed back), a backtest without params, and a four-point sweep. All read correctly; turning coercion off breaks none of them.

Not in this PR

No version bump or release: the changelog entry sits under [Unreleased]. The MCP server needs only a dependency bump once this is released.

…choed back

The generated client reads the number | string | boolean value of a strategy param by requiring exactly one member to accept the JSON scalar. Its mapper coerced scalars between JSON types, so every number matched two or three members and every boolean two: a backtest started with a numeric or boolean params value ran on the platform, but its result failed to deserialize with 'N classes match result, expected 1'. Only string values worked.

Scalar coercion is turned off in the client that QTSurfer and authenticate() build. The mapper is installed with setObjectMapper before any API class is built, because getObjectMapper() returns a copy and the API classes take theirs from the client at construction.
@mrmx
mrmx temporarily deployed to Preproduction October 25, 2026 14:33 — with GitHub Actions Inactive
@mrmx
mrmx marked this pull request as ready for review October 25, 2026 14:38
@mrmx
mrmx merged commit 66e7c43 into main Oct 25, 2026
6 checks passed
@mrmx
mrmx deleted the fix/scalar-param-coercion branch October 25, 2026 14:38

This branch was previously deployed

1 inactive deployment
Preproduction — fac3f424 Deployed Oct 25, 2026 by mrmx via integration #108
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