Skip to content

0.6.1: parse production error bodies, sync OpenAPI 3.30.0, fail on malformed WS frames - #13

Merged
UTXOnly merged 5 commits into
mainfrom
fix/0.6.1-review
Sep 12, 2026
Merged

0.6.1: parse production error bodies, sync OpenAPI 3.30.0, fail on malformed WS frames#13
UTXOnly merged 5 commits into
mainfrom
fix/0.6.1-review

Conversation

@UTXOnly

@UTXOnly UTXOnly commented Sep 12, 2026

Copy link
Copy Markdown
Owner

Follow-up to the 0.6.0 accuracy review. Patch release: every change is an addition or a bug fix, and gorelease -base=v0.6.0 reports only compatible changes.

Merging this tags and publishes v0.6.1. The release job runs on push to main.

Fixes

  • APIError.Code/Message empty against production: error body is nested under "error" #7APIError.Code / Message were empty for every production error. types.ErrorResponse follows the spec's flat {"code","message","details"}, but production returns {"error":{"code":...,"message":...}} for most errors and {"msg":"..."} for parameter-binding 400s, so Error() printed only api error 404. newAPIError now decodes all three shapes (flat wins when both are present). Tests use the bodies observed from the live API.
  • WebSocket: unparseable frames are skipped silently instead of failing the connection #10 — WebSocket text frames that were not valid JSON were skipped silently. The read loop now fails the connection with an error wrapping the new ErrWSMalformedFrame, closes Messages(), and returns that error from pending commands — same path as ErrWSSlowConsumer. Frames received before the bad one are still delivered.

Additions

Docs

  • README corrections from the review: the CreateV2 example was missing the required self_trade_prevention_type; the not-implemented list omitted several paths; retry section states the Retry-After cap and the 409-on-replay behavior for client_order_id; WebSocket section covers private channels, subscription-scoped error frames (terminal codes 10/25), the AsyncAPI host, and server pings.
  • CHANGELOG 0.6.0 "never dropped silently" heading narrowed to what that change guaranteed.
  • cmd/example/README.md no longer claims LIVE=1 forces production.
  • New AGENTS.md: tool-neutral contributor guide — layout, spec-sync workflow, conventions, the mandatory-test matrix, CI version-job rules, and the spec-vs-production differences above.

Not in this PR

#11 (remove dead legacy V1 order types) is API-incompatible and needs a 0.7.0 with a ### Breaking section; left open.

Verification

gofmt clean · go mod tidy no-op · go vet · staticcheck clean · go test -race -count=1 -shuffle=on ./... passes · version.go / CHANGELOG / README pin agree on 0.6.1 · gorelease -base=v0.6.0 -version=v0.6.1: "v0.6.1 is a valid semantic version for this release" (only compatible additions).

Fixes #7
Fixes #8
Fixes #9
Fixes #10
Fixes #12

🤖 Generated with Claude Code

UTXOnly and others added 5 commits September 12, 2026 13:12
…; add AGENTS.md

README: CreateV2 example was missing the required self_trade_prevention_type;
APIError description overstated what decodes from production bodies; the
not-implemented list omitted several paths and four optional filters; retry
section now states the Retry-After cap and the 409-on-replay behavior; WS
section covers private channels, subscription-scoped error frames, the
AsyncAPI host, and server pings. CHANGELOG 0.6.0 heading narrowed to what the
change actually guarantees. Example README no longer claims LIVE=1 forces
production.

AGENTS.md is the committed, tool-neutral contributor guide: layout, spec sync,
conventions, mandatory tests, CI version rules, spec-vs-production notes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
types.ErrorResponse follows the spec's flat {"code","message","details"},
but production wraps most errors as {"error":{"code":...,"message":...}}
and parameter-binding 400s as {"msg":"..."}. Every *APIError from the live
API therefore had empty Code/Message and Error() printed only the status.

newAPIError now decodes all three shapes; the flat form wins when present.
RawBody is unchanged. Tests use the bodies observed from production.

Fixes #7

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ilters

Vendored specs refreshed from docs.kalshi.com. 3.30.0 adds Series.categories
(the full discovery list the category filter matches against) and
GetTargetBalanceAllocationResponse.resting_margin_reservation; both added
with unmarshal tests. The AsyncAPI content change is documentation only.

GetOrdersOpts, GetFillsOpts, and GetPositionsOpts gain ExchangeIndex, and
GetHistoricalPositionsOpts gains Subaccount, matching the optional query
parameters the spec already documents on those endpoints. Tests cover the
parameter being sent and being omitted when nil.

Fixes #8
Fixes #9

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… ListSubscriptions

readLoop skipped a text frame that did not decode as JSON with no signal,
leaving a corrupt stream looking healthy. It now records an error wrapping
the new ErrWSMalformedFrame, closes the socket, and exits — the same path as
ErrWSSlowConsumer. Frames received before the bad one are still delivered.

Adds the missing success-path tests: Unsubscribe waits for one
"unsubscribed" reply per sid, and ListSubscriptions decodes the "ok" reply
whose msg is an array, both using the AsyncAPI example payloads.

Fixes #10
Fixes #12

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@UTXOnly
UTXOnly merged commit 748b4ad into main Sep 12, 2026
7 checks passed
@UTXOnly
UTXOnly deleted the fix/0.6.1-review branch September 12, 2026 17:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment