Skip to content

release: v2.0.0#144

Merged
TexasCoding merged 2 commits into
mainfrom
release/v2.0.0
May 17, 2026
Merged

release: v2.0.0#144
TexasCoding merged 2 commits into
mainfrom
release/v2.0.0

Conversation

@TexasCoding

Copy link
Copy Markdown
Owner

Summary

Cuts the v2.0.0 release. This packages the full audit-driven hardening wave (30 audit findings closed across 5 parallel waves + integration cleanup + #114 follow-up) plus the 3 deliberate breaking changes that drove the major version bump.

Release contents

See CHANGELOG.md for the full list. Major beats:

Breaking (3)

  • Order.typeOrder.order_type (wire format unchanged via validation_alias).
  • AccountApiLimits.read_limit / .write_limit removed; replaced by .read / .write of type RateLimit. New kalshi.RateLimit model exposed.
  • Count/size/volume response fields retyped DollarDecimalFixedPointCount (runtime values still Decimal).

Addedmax_pages kwarg on every public *_all() method (sync + async, 38 signatures). KalshiConfig.http2 + KalshiConfig.limits. 23 model re-exports. ConnectionManager.mark_streaming() public API.

Changed*_all() is now truly unbounded by default (removed silent 1000-page cap). Uniform extra="allow" policy on every response model. WS callbacks no longer suppress queue delivery (fan-out + WARNING at register-time).

Fixed/account/limits + /search/tags_by_categories now parse against the live server. WS recv-loop: 5 reconnect races, narrowed exception ladder, sentinel-broadcast on backpressure / unexpected exception. WS seq-watermark rolls back on backpressure (no silent desync). Multi-ticker gap clears every ticker. Retry-After rejects negative/NaN/infinite and honors Retry-After: 0. Single parse path on WS hot side (~0.9 µs + ~3 µs / msg saved).

Security — Spec-sync supply-chain hardening (per-fingerprint drift issues, no auto-PRs, contents:read). URL leakage scrubbed from KalshiError.__str__. Trade-data leakage scrubbed from WS dispatch log. Claude actions SHA-pinned + Dependabot + nightly pip-audit + sigstore attestations + integration-nightly PEM shred. pytest bumped to clear CVE-2025-71176.

PerformanceMessageQueue.qsize() O(n) → O(1). AWS Full Jitter REST backoff. RecordingTransport O(N²) → O(1) amortized. OrderbookManager.apply_delta O(n) → O(1) via price-indexed dict.

Test plan

  • uv run pytest tests/ --ignore=tests/integration -q1808 passed, 52 warnings
  • uv run pytest tests/integration/ --tb=no -q (against demo with secrets configured) → 215 passed, 30 skipped, 0 failed
  • uv run ruff check . clean
  • uv run mypy kalshi/ clean (strict, 76 source files)
  • Tag v2.0.0 after merge — triggers PyPI release workflow with sigstore attestations

Migration

See docs/migration.md for the focused v1.x → v2.0 guide.

Closes #11

Cuts the v2.0.0 release. Captures the full audit-driven hardening wave
(30 audit findings closed across 5 parallel waves + cleanup) and the
3 deliberate breaking changes: Order.type rename, AccountApiLimits
restructure, count/size/volume type retype.

Changes:
- CHANGELOG.md: finalize [Unreleased] → ## 2.0.0 — 2026-05-17 with a
  full release summary (Breaking, Added, Changed, Fixed, Security,
  Performance, Internal).
- ROADMAP.md: rewrite around Shipped / Open trackers / Next milestone /
  Execution conventions. The wave-by-wave v1.2 plan is captured under
  Shipped as v2.0.0; CHANGELOG carries the detail.
- README.md: document max_pages in the Pagination section, surface
  http2/limits/extra_headers in the KalshiConfig example.
- docs/migration.md: new v1.x → v2.0 section at the top covering the 3
  breaking changes + the non-breaking behavior shifts (unbounded
  *_all() by default, uniform extra="allow", WS callback fan-out).
- pyproject.toml + kalshi/__init__.py: 1.1.0 → 2.0.0.
- CLAUDE.md: active milestone → post-v2.0.
- tests/integration/helpers.py: add wait_until_not_found inverse poller.
- tests/integration/test_order_groups.py::test_delete: use
  wait_until_not_found so the demo's query-exchange propagation lag
  after DELETE doesn't make the test flap.
- AGENTS.md: GitNexus stat refresh after Wave 5 + #142 + #143 merges.

Verify:
- uv run pytest tests/ --ignore=tests/integration -q → 1808 passed
- uv run pytest tests/integration/ → 215 passed, 30 skipped
- uv run ruff check . → clean
- uv run mypy kalshi/ --strict → clean (76 source files)

Closes #11 (release-cut milestone tracker).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented May 17, 2026

Copy link
Copy Markdown

Code Review — v2.0.0 Release Cut (PR #144)

This PR is a release packaging commit — it finalizes the v2.0.0 version bump, promotes CHANGELOG entries from [Unreleased] to 2.0.0, collapses the ROADMAP, and ships a migration guide. There is no new logic here; all the substantive work landed in the preceding wave PRs (#108#141). The review below is scoped to this diff accordingly.


Overview

The diff touches:

  • pyproject.toml + kalshi/__init__.py — version 1.1.0 → 2.0.0
  • CHANGELOG.md[Unreleased] promoted to 2.0.0 — 2026-05-17
  • ROADMAP.md — wave-execution plan replaced with a shipped summary + post-v2 candidates
  • docs/migration.md — v1.x → v2.0 migration section prepended
  • README.mdmax_pages + http2/limits example snippets added
  • CLAUDE.md / AGENTS.md — milestone pointer updated, GitNexus index counts refreshed
  • tests/integration/helpers.pywait_until_not_found helper added
  • tests/integration/test_order_groups.py — flaky DELETE test fixed with that helper

What Looks Good

Version bump is consistent. Both pyproject.toml and kalshi/__init__.py are bumped in lockstep — no drift.

CHANGELOG is complete and well-structured. Breaking changes are at the top with before/after code snippets. Security, performance, and fixed sections are all present and reference issue numbers. This is the right format for a major release entry.

wait_until_not_found is a clean addition. The implementation mirrors the existing wait_for_resource pattern correctly: monotonic-clock deadline, configurable timeout/interval, AssertionError with a diagnostic message on timeout. No issues.

Migration guide is thorough. The three breaking changes each have a Python snippet showing the before/after. The mypy --strict callout for the FixedPointCount retype is the right level of detail.

ROADMAP collapse is appropriate. Replacing the exhaustive wave-by-wave plan with a short shipped summary + next-milestone candidates is the right post-release shape. The execution conventions section is kept, which is useful for future contributors.

Security items are documented. URL leakage, trade-data log scrub, SHA-pinned CI actions, pip-audit, sigstore attestations, and PEM shredding are all called out explicitly in the changelog. Good transparency for a public SDK.


Issues and Suggestions

Minor: CHANGELOG intro paragraph is ambiguous about what shipped vs. what's in the PR.
The new intro block says "30 audit-findings landed across five parallel waves…" but this PR itself only merges docs/version bump. A reader skimming git log --follow CHANGELOG.md will have context; a reader hitting the tag on PyPI may not. Consider one sentence linking to the individual wave PRs or just to the GitHub milestone — the PR description body already does this well, it just isn't replicated in the CHANGELOG.

Minor: docs/migration.md isinstance(x, Decimal) note could be more precise.

`isinstance(x, Decimal)` checks remain valid.

True, but both DollarDecimal and FixedPointCount resolve to Decimal at runtime, so this is only relevant if a user is annotating with the type alias names rather than Decimal. The sentence is accurate but slightly misleading — it implies there's a runtime change, when the only impact is on mypy --strict narrow typing. Suggested rewrite: "Runtime values are still Decimal; only mypy --strict code that uses the specific type alias in annotations will need updating."

Minor: README.md comment style differs from project convention.
The project convention (per CLAUDE.md) is no comments unless the WHY is non-obvious. The added snippet has an inline comment # Connection pool / HTTP-2 tuning (opt-in; defaults preserve v1 behavior) on a KalshiConfig block. This is arguably fine for documentation-facing README prose, but contrast it with limits=None, # httpx.Limits(...) — the latter is genuinely useful as a type hint shorthand for readers who don't know the class name. The first comment is just restating what the section header already says. Up to you, but worth a pass for tightening.

Non-issue observation: wait_until_not_found is sync-only.
The async counterpart (await_until_not_found) isn't added here. That's fine if there's no async DELETE test that needs it today, but worth a GitHub issue to track parity if the integration suite gains async DELETE coverage later. Not a blocker.

Verify: test count in CHANGELOG matches actual suite.
The CHANGELOG entry states "Test count delta: 1407 → 1808 (+401)." The PR description says 1808 passed, 52 warnings. Spot-checking these numbers is trivially done by running uv run pytest tests/ --ignore=tests/integration -q --co | tail -1 on the branch — the PR test plan checks this, so this is already verified, just noting it as a thing to confirm before tagging.


Security Check

  • No new code paths, no new user-facing inputs, no new HTTP calls.
  • The wait_until_not_found helper calls fetch() in a polling loop on integration test infra only — no production surface.
  • kalshi/__init__.py and pyproject.toml changes are version strings only.

No security concerns.


Test Coverage

  • No new unit tests added (appropriate — this is a release packaging commit).
  • The wait_until_not_found addition has corresponding usage in test_order_groups.py, which validates the happy path.
  • The PR description includes a passing integration run (215 passed, 30 skipped, 0 failed).

Verdict

Ready to merge. The issues above are all documentation-level nits; none are blockers. The version bump is consistent, the CHANGELOG is complete, the migration guide covers all three breaking changes, and the one functional addition (wait_until_not_found) is clean and well-integrated.

Tag v2.0.0 after merge as noted in the PR description.

The release commit replaced `with pytest.raises(KalshiNotFoundError):` in
test_order_groups.py::test_delete with the new wait_until_not_found
helper, but left the import behind. CI's ruff caught F401.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented May 17, 2026

Copy link
Copy Markdown

Code Review — PR #144: release: v2.0.0

This is a clean, well-organized release PR. Almost all of the diff is documentation; the only executable changes are a version bump and one integration-test helper addition. Comments below are organized by section.


Overview

What this PR does: Promotes all audit-wave work already merged into main into a tagged v2.0.0 release. The PR itself adds:

  • CHANGELOG.md[Unreleased] promoted to 2.0.0 — 2026-05-17 with a full Breaking/Added/Changed/Fixed/Security/Performance/Internal structure.
  • ROADMAP.md — Simplified from the detailed wave-tracking table to a historical summary and a short forward-looking candidate list.
  • docs/migration.md — New v1.x → v2.0 section covering all three breaking changes.
  • README.md — New max_pages example + config knobs (http2, limits, extra_headers).
  • Version bumps in kalshi/__init__.py and pyproject.toml.
  • tests/integration/helpers.py — New wait_until_not_found polling helper.
  • tests/integration/test_order_groups.py — Uses the new helper; removes the now-unused KalshiNotFoundError import.

Code quality

tests/integration/helpers.pywait_until_not_found

def wait_until_not_found(
    fetch: Callable[[], object],
    *,
    timeout: float = 15.0,
    interval: float = 0.5,
) -> None:
  • Signature is clean. Callable[[], object] is appropriate — the return value is irrelevant; only the exception matters.
  • Uses time.monotonic() correctly (not time.time()).
  • Sync polling with time.sleep(interval) matches wait_for_resource's sync counterpart. There is no async twin, which is fine — the only caller is a sync test.
  • Non-KalshiNotFoundError exceptions correctly propagate (fail-fast is right for tests).
  • Minor: The function is appended before the logger = logging.getLogger(__name__) line. The function doesn't use logger, so there's no functional issue, but the logger definition ends up sandwiched between two functions, which is a minor style inconsistency with the rest of the file. Low priority.

tests/integration/test_order_groups.py

The swap from an immediate pytest.raises(KalshiNotFoundError) to wait_until_not_found(...) is correct — demo's query-exchange replica lags deletes, and flaky 404-not-yet-propagated failures are worse than a 15 s poll. The unused KalshiNotFoundError import is properly removed.


Documentation

CHANGELOG.md

  • All three breaking changes have working before/after code examples that are consistent with docs/migration.md.
  • The ### Internal section honestly surfaces the test-count delta (+401) and the ast-serialize dependency pin — both useful for users maintaining forks or internal packages.
  • One very minor style note: the ## 2.0.0 header drops the [] brackets that Keep a Changelog convention uses (## [2.0.0]), but the existing ## 1.1.0 entries also dropped them, so this is consistent with this project's convention.

docs/migration.md

  • Well-targeted at the three actionable breaks. The DollarDecimal → FixedPointCount section correctly notes that isinstance(x, Decimal) is still valid, which covers the most common user pattern.
  • "Non-breaking but worth knowing" section is a thoughtful addition for the WS callback behavior change, which is technically not a break but is a semantic change that could surprise users.

README.md

  • The max_pages=5 example is concrete and immediately useful.
  • The note "*_all() iterates until the server returns no cursor by default. Pass max_pages=N for an explicit bound; passing 0 raises ValueError." is good — the ValueError on 0 edge case is documented where users look first.

ROADMAP.md

  • The simplification from a 150-line detailed wave tracker to a 70-line post-release forward-look is appropriate.
  • Minor concern: The Active milestone in CLAUDE.md is now post-v2.0 (after the audit-driven hardening wave...) — this is a narrative description rather than a link to an actual GitHub milestone. If there's a v2.1 or similar milestone open on GitHub, pointing to it would give future agents a better anchor. Not a blocker.

Version consistency

Both kalshi/__init__.py (__version__ = "2.0.0") and pyproject.toml (version = "2.0.0") are bumped in sync. No other version strings are visible in the diff, and per CLAUDE.md the __init__.py is the canonical location. ✓


Potential issues / risks

  1. wait_until_not_found has no async twin. If an async integration test ever needs the same poll-until-404 pattern, it would need await_until_not_found. Not a blocker for this PR — there are no async callers — but worth tracking in #106 as a candidate addition.

  2. *_all() now unbounded by default. This is documented as a behavioral change, and the cursor-repeat guard is described as the safety net. Worth confirming in the PR's test suite that the cursor-repeat guard test was strengthened as part of #98 work (the PR claims 1808 tests pass, so this is likely covered, but it's the highest-blast-radius behavioral change in the release).

  3. WS callback fan-out to maxsize=1000 queue for callback-only users. Users who registered a callback and never consumed the iterator queue will now accumulate up to 1000 messages before DROP_OLDEST kicks in. The WARNING at register-time is the right signal, but users who miss the log line during an upgrade could see memory growth in long-running processes. The migration guide mentions this under "Non-breaking but worth knowing." Consider whether the WARNING message includes enough context to diagnose unexpected memory growth after the fact.


Summary

Approve. The release PR is well-structured. Documentation is thorough and internally consistent. The only functional code addition (wait_until_not_found) is correct and appropriately scoped. The version bump is properly synchronized across both canonical locations. The three breaking changes are clearly documented with migration examples in both CHANGELOG.md and docs/migration.md.

The minor issues (logger placement, milestone label specificity) are polish-level and not release blockers.

@TexasCoding
TexasCoding merged commit ed785f7 into main May 17, 2026
4 checks passed
@TexasCoding
TexasCoding deleted the release/v2.0.0 branch May 17, 2026 19:29
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.

v0.4: CLI tool (kalshi markets list, kalshi order create)

1 participant