Make the Kotlin retry cap a ceiling on the operation budget and expose it in the builder
The gap
FizzyHttpClient.requestWithRetry sized its budget as opRetry?.maxRetries ?: config.maxRetries. Every operation in behavior-model.json carries a retry block (112 of 112), so the ?: fallback never ran and config.maxRetries was dead for governed traffic: a client built with maxRetries = 1 still made three attempts on GetBoard. The builder DSL did not expose the knob either — FizzyConfig has it, FizzyClientBuilder dropped it — so the only way to set it was the constructor the DSL hides.
Found while adding configOverrides.maxRetries to the conformance suite (the follow-up to #180 and #181): the Kotlin runner had no way to pass a cap, and the SDK would have ignored it if it could.
The fix
The cap is now what the Go, Ruby and Rust SDKs make of it: a total attempt count, floored at one so 0 means "no retries" rather than "no request", and a ceiling on the operation's modelled budget rather than a value the model replaces — min(cap.coerceAtLeast(1), opMax), the same shape as basecamp-sdk's computeMaxAttempts. The builder passes maxRetries through. enableRetry is untouched.
The default stays 3, which is also every governed operation's modelled maximum, so a client that never set the cap behaves exactly as before.
Tests
-
computeMaxAttemptsfloors at one and ceilings the operation budget. -
maxRetries = 0onGetBoardagainst an always-503 engine sends exactly one request and surfaces the 503. -
maxRetries = 2onGetBoard(budget 3) sends exactly two. -
Follow-up pages keep the operation budget:
requestPaginatedandrequestPaginatedAsFlownow passinfo.operationon every page aLinkheader leads to, so a cap raised above the model (5) yields 1 + 3 requests when page two keeps answering 503, not 1 + 5.
make kt-check green locally.
Conformance coverage
The shared case — configOverrides.maxRetries, the retry.json fixture and the override plumbing in all five runners — is #183, stacked directly on this branch. Merged together, the behavioral change does not ship on unit tests alone (AGENTS.md rule 3); Kotlin conformance on #183's head reports 128 passed, 0 failed.