Skip to content

fix: Validate the wait_for_action_attempt option - #637

Open
razor-x wants to merge 2 commits into
claude/python-sdk-audit-o2iid9-03-poll-queryfrom
claude/python-sdk-audit-o2iid9-04-wait-option
Open

fix: Validate the wait_for_action_attempt option#637
razor-x wants to merge 2 commits into
claude/python-sdk-audit-o2iid9-03-poll-queryfrom
claude/python-sdk-audit-o2iid9-04-wait-option

Conversation

@razor-x

@razor-x razor-x commented Aug 27, 2026

Copy link
Copy Markdown
Member

What

wait_for_action_attempt was dispatched with an is True identity check, so any truthy non-True value — 1, "true" (an env string), a numpy bool — silently fell through to no waiting and no failure raising: the caller got back a pending attempt and believed the door unlocked (SDK audit finding M2). Dict options were equally silent: unknown keys were ignored, so the docstring's own poll_interval typo polled at the default rate without complaint.

This PR makes the option strict, in both sync and async variants:

  • A new validate_wait_for_action_attempt raises SeamInvalidOptionsError for anything that is not a bool or an options dict, for unknown dict keys (naming the key — this makes the poll_interval typo fail loudly), and for non-numeric dict values.
  • Constructor None now means "use the default" (wait), matching what per-request None already meant. Previously Seam(wait_for_action_attempt=None) silently behaved as False while per-request None meant "use the client default" — the same annotation with opposite meanings. ⚠️ Behavior change for anyone passing None explicitly to disable waiting; pass False for that.
  • The documented-but-dead seam.wait_for_action_attempt instance attribute is now a real property backed by defaults, on all four clients (Seam, AsyncSeam, SeamWithoutWorkspace, AsyncSeamWithoutWorkspace). It previously did nothing after construction — routes read defaults, which the attribute never touched. Reading it reflects the live default; assigning it validates and takes effect. SeamWithoutWorkspace also gains the same public defaults dict the other clients had.
  • Fixed the 'poll_interval''polling_interval' typo in ten constructor/factory docstrings (the code always read polling_interval; the README was already correct).

Depends on #636 (stacked; diff shrinks once it merges).

Testing

New test/wait_for_action_attempt_option_test.py (sync + async): junk values raise at construction, at route call, and at property assignment with pinned messages; unknown dict key and non-numeric value raise naming the problem; constructor None waits; the property reflects and updates route behavior.

Revert check: with the source reverted, the junk-value test fails with DID NOT RAISE (the silent-pending audit symptom) and the ctor-None test shows defaults holding None (behaving as False).

Full suite: 203 passed; mypy, pylint (10.00), black clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Y1RzepycXEYA3LStfjt8cY


Generated by Claude Code

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y1RzepycXEYA3LStfjt8cY
@razor-x
razor-x requested a review from a team as a code owner August 27, 2026 21:16
@razor-x
razor-x changed the base branch from main to claude/python-sdk-audit-o2iid9-03-poll-query August 28, 2026 00:15
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.

2 participants