Skip to content

test(streaming): port 6 StreamingPlan option tests (#56)#74

Merged
patrick-chinchill merged 3 commits intomainfrom
feat/streaming-tests-56
Apr 24, 2026
Merged

test(streaming): port 6 StreamingPlan option tests (#56)#74
patrick-chinchill merged 3 commits intomainfrom
feat/streaming-tests-56

Conversation

@patrick-chinchill
Copy link
Copy Markdown
Collaborator

@patrick-chinchill patrick-chinchill commented Apr 24, 2026

Summary

  • Fixes Port 6 missing StreamingPlan option tests to test_thread_faithful.py #56. Wiring bug found and fixed: the Python port was missing the StreamingPlan PostableObject entirely, so thread.post(StreamingPlan(stream, options)) silently dropped group_tasks / end_with / update_interval_ms. There was no kind == "stream" branch in Thread.post() to map them onto StreamOptions before invoking adapter.stream(...) or the fallback post+edit path — a StreamingPlan-shaped object would have hit the generic post_postable_object helper, which calls adapter.post_message(..., obj.get_fallback_text()) and throws the stream + options away.
  • Added StreamingPlan + StreamingPlanOptions in chat_sdk.plan (mirrors upstream streaming-plan.ts), and a kind == "stream" branch in Thread.post() that maps group_tasks → task_display_mode, end_with → stop_blocks, update_interval_ms → update_interval_ms onto StreamOptions. Options now flow through both the native and fallback streaming paths.
  • Ported the 6 [Streaming] StreamingPlan option-variant tests faithfully from thread.test.ts.

Wiring verification outcome

Investigated before porting tests as required.

  • Upstream: thread.ts has the kind === "stream" branch (lines 417–439) that builds a StreamOptions from data.options.{updateIntervalMs, groupTasks, endWith} and calls handleStream(stream, options). The fallback path (fallbackStream) reads options?.updateIntervalMs so options propagate there too.
  • Python: StreamingPlan class did not exist. Thread.post() (thread.py:461) handled is_postable_object(...) but had no kind == "stream" special case. _handle_stream also did not accept caller-supplied options. → Options silently dropped.
  • Fix applied: new StreamingPlan + StreamingPlanOptions, new kind == "stream" branch in post, _handle_stream(..., extra_options=...); explicit fields win over message-context defaults.

Fidelity impact

  • Before: 548/588 matched, 40 missing (29 in thread.test.ts, including all 6 [Streaming] gaps).
  • After: 554/588 matched, 34 missing. All 6 [Streaming] StreamingPlan gaps closed; other pre-existing gaps (e.g. [post with Plan], [Options Load]) untouched — they belong to other issues.

Test plan

  • uv run ruff check src/ tests/ scripts/ — clean
  • uv run ruff format --check src/ tests/ scripts/ — 192 files already formatted
  • uv run pyrefly check — 0 errors
  • uv run python scripts/audit_test_quality.py — 0 hard failures (pre-existing warnings only)
  • TS_ROOT=/private/tmp/vercel-chat uv run python scripts/verify_test_fidelity.py — 6 [Streaming] StreamingPlan gaps closed
  • uv run pytest tests/ --tb=short -q — 3,551 passed, 2 skipped

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an issue where streaming options were lost when posting streams.
  • New Features

    • Introduced StreamingPlan and StreamingPlanOptions public APIs for enhanced streaming control.
    • Streaming configuration now properly propagates across all streaming implementation paths.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 24, 2026

Warning

Rate limit exceeded

@patrick-chinchill has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 48 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 5 minutes and 48 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f7a4bc91-2799-4420-a889-e92db4a0febd

📥 Commits

Reviewing files that changed from the base of the PR and between 452b0ac and 05095e6.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • docs/UPSTREAM_SYNC.md
  • src/chat_sdk/__init__.py
  • src/chat_sdk/plan.py
  • src/chat_sdk/thread.py
  • tests/test_thread_faithful.py
📝 Walkthrough

Walkthrough

This PR implements the StreamingPlan feature, a new PostableObject abstraction that wraps async iterables with streaming options. It updates Thread.post() to detect and route StreamingPlan instances through native streaming or fallback paths, ensuring upstream groupTasks, endWith, and updateIntervalMs options are preserved and propagated to the adapter.

Changes

Cohort / File(s) Summary
Public API & Exports
src/chat_sdk/__init__.py, CHANGELOG.md
Added top-level exports of StreamingPlan and StreamingPlanOptions; documented functional fix for streaming option fields being dropped in Thread.post().
StreamingPlan Abstraction
src/chat_sdk/plan.py
Introduced new StreamingPlan PostableObject with StreamingPlanOptions dataclass and _StreamingPlanData internal type; implements get_post_data(), get_fallback_text(), is_supported(), and on_posted() interface methods.
Thread Streaming Routing
src/chat_sdk/thread.py
Modified post() to detect kind == "stream" and route to _handle_stream(); added extra_options parameter to _handle_stream() to merge caller-supplied StreamingPlan options into native and fallback streaming paths.
Streaming Test Coverage
tests/test_thread_faithful.py
Added six tests verifying StreamingPlan option propagation (groupTasks, endWith, updateIntervalMs), field mapping translations, fallback routing, and backward compatibility with unadorned async iterables.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Thread
    participant PostRouter as Post Router
    participant StreamHandler as Stream Handler
    participant Adapter
    
    Caller->>Thread: post(StreamingPlan message)
    Thread->>PostRouter: detect kind == "stream"
    PostRouter->>StreamingPlan: get_post_data()
    StreamingPlan-->>PostRouter: stream + options
    PostRouter->>StreamHandler: _handle_stream(stream, extra_options)
    StreamHandler->>StreamHandler: merge options from<br/>message context +<br/>extra_options
    StreamHandler->>Adapter: stream(message, stream_options)
    Adapter-->>StreamHandler: streaming result
    StreamHandler-->>Thread: return message
    Thread-->>Caller: return message
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 A streaming plan, oh what delight!
Options now flow through day and night,
No fields are dropped, no mappings lost,
From upstream's TypeScript, faithfully crossed! ✨
Tests prove it works, both paths shine bright,
Native and fallback—all fits just right! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.91% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'test(streaming): port 6 StreamingPlan option tests (#56)' accurately describes the main change—porting 6 streaming tests and adding StreamingPlan support.
Linked Issues check ✅ Passed All objectives from linked issue #56 are met: StreamingPlan options propagate through native/fallback paths [#56], 6 tests are ported to test_thread_faithful.py [#56], and option mapping (groupTasks→task_display_mode, endWith→stop_blocks, updateIntervalMs→update_interval_ms) is implemented [#56].
Out of Scope Changes check ✅ Passed All changes are in-scope for issue #56: StreamingPlan/StreamingPlanOptions classes added, Thread.post() extended with kind=='stream' branch, _handle_stream() updated to accept extra_options, tests ported, and CHANGELOG/exports updated. No unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/streaming-tests-56

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the StreamingPlan and StreamingPlanOptions classes to the Python SDK, mirroring the upstream Vercel Chat SDK. These additions allow developers to pass platform-specific streaming options, such as task grouping and stop blocks, through the Thread.post() method. The changes include updates to the Thread class to route these options into the streaming handler and comprehensive tests to ensure fidelity with the upstream implementation. Feedback was provided to use explicit 'is not None' checks when mapping these options to ensure that valid falsy values, such as an update interval of zero or an empty list of blocks, are correctly propagated.

Comment thread src/chat_sdk/thread.py Outdated
Comment on lines +475 to +480
if group_tasks:
extra.task_display_mode = group_tasks
if end_with:
extra.stop_blocks = end_with
if update_interval_ms:
extra.update_interval_ms = update_interval_ms
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Use is not None checks when mapping StreamingPlanOptions to StreamOptions. This ensures that falsy but valid values, such as update_interval_ms=0 or an empty list for end_with, are correctly propagated to the stream handler instead of being silently ignored.

Suggested change
if group_tasks:
extra.task_display_mode = group_tasks
if end_with:
extra.stop_blocks = end_with
if update_interval_ms:
extra.update_interval_ms = update_interval_ms
if group_tasks is not None:
extra.task_display_mode = group_tasks
if end_with is not None:
extra.stop_blocks = end_with
if update_interval_ms is not None:
extra.update_interval_ms = update_interval_ms

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in ccb5fdeStreamingPlanOptions mapping uses is not None so update_interval_ms=0 and end_with=[] propagate correctly. Regression test added in 90c1339.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 452b0ac8ab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/chat_sdk/plan.py Outdated
Comment on lines +522 to +525
def get_fallback_text(self) -> str:
"""StreamingPlan has no static fallback text -- streaming is handled
by Thread.post() directly via the native-or-fallback streaming path."""
return ""
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve stream text in StreamingPlan fallback posting

StreamingPlan.get_fallback_text() returns an empty string, but non-thread posting paths still treat it as a generic PostableObject fallback payload. In practice, ChannelImpl.post will post blank content (or attempt post_object("stream", ...) on adapters with object posting) instead of consuming the wrapped async stream, so callers who reuse StreamingPlan outside Thread.post silently lose the message body.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in ccb5fde — Option 2 (fail loud). StreamingPlan.get_fallback_text() and is_supported() now raise RuntimeError to prevent silent blank-posting via non-stream-aware paths. post_postable_object has a kind == "stream" short-circuit guard. Divergence documented in docs/UPSTREAM_SYNC.md.

Comment thread src/chat_sdk/thread.py Outdated
Comment on lines +479 to +480
if update_interval_ms:
extra.update_interval_ms = update_interval_ms
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve explicit zero update interval in stream mapping

The StreamingPlanOptions.update_interval_ms mapping uses a truthy check, so an explicit value of 0 is dropped as if it were unset. That means thread.post(StreamingPlan(..., update_interval_ms=0)) cannot propagate zero to adapter.stream(...) or fallback mode, and the code falls back to the default interval instead of honoring the caller’s per-message override.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in ccb5fdeupdate_interval_ms=0 now propagates via is not None check (also fixed the parallel _fallback_stream interval guard at line 660 that had the same truthy-check bug).

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/chat_sdk/plan.py`:
- Around line 522-538: StreamingPlan should not advertise generic PostableObject
support; change get_fallback_text()/is_supported() so the shared post helper
doesn't try adapter.post_object with a stream. Specifically, update
StreamingPlan.is_supported to return False (or otherwise indicate unsupported by
adapters) and keep/get a clear fallback (e.g., empty or explicit sentinel) so
post_postable_object() will skip adapter.post_object(...) for kind == "stream"
and force callers to use Thread.post() for streaming; adjust the docstring on
get_fallback_text/is_supported to note Thread.post()‑only and reference
post_postable_object and Thread.post to ensure the shared helper special-cases
stream kinds or relies on is_supported == False.

In `@src/chat_sdk/thread.py`:
- Around line 471-480: The current truthiness checks on plan_options fields drop
explicit falsy values (e.g., end_with=[] or update_interval_ms=0); update the
conditional logic in the block handling plan_options so each field is checked
with "is not None" before assigning: check group_tasks is not None, end_with is
not None, and update_interval_ms is not None, and then assign to
extra.task_display_mode, extra.stop_blocks, and extra.update_interval_ms
respectively so explicit falsy choices are preserved.

In `@tests/test_thread_faithful.py`:
- Around line 943-973: Update the
test_should_route_streamingplan_through_fallback_when_adapter_has_no_native_streaming
to spy/mock the _fallback_stream function and assert that it is called with the
StreamingPlanOptions passed through the StreamingPlan; specifically capture the
options argument to _fallback_stream and assert its mapped fields
(task_display_mode, stop_blocks/stop_blocks flag or equivalent, and
update_interval_ms) match the values derived from
StreamingPlanOptions(group_tasks="plan", end_with=[{"type":"actions"}],
update_interval_ms=2000). Ensure you reference the actual symbols
_fallback_stream and StreamingPlanOptions and assert the mapped fields
(task_display_mode, stop_blocks, update_interval_ms) rather than just verifying
output edits so the test fails if options are dropped.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5e14e8b3-76e0-4366-b52a-262513c3884b

📥 Commits

Reviewing files that changed from the base of the PR and between d23b6d9 and 452b0ac.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • src/chat_sdk/__init__.py
  • src/chat_sdk/plan.py
  • src/chat_sdk/thread.py
  • tests/test_thread_faithful.py

Comment thread src/chat_sdk/plan.py
Comment thread src/chat_sdk/thread.py
Comment thread tests/test_thread_faithful.py
patrick-chinchill added a commit that referenced this pull request Apr 24, 2026
- StreamingPlanOptions mapping: replace truthy checks with `is not None`
  so update_interval_ms=0 and end_with=[] propagate correctly (thread.py
  post dispatcher and _fallback_stream interval guard). Per CLAUDE.md
  Port Rule #1; diverges from upstream thread.ts, which has the same
  latent bug.
- StreamingPlan: raise RuntimeError from is_supported() and
  get_fallback_text() so misroutes through post_postable_object /
  Channel.post fail loudly instead of posting "" or attempting a
  wrong-shape adapter.post_object("stream", ...). Also guard
  post_postable_object() with an early kind=="stream" check for a
  clearer error message. Diverges from upstream postable-object.ts,
  which silently posts the empty fallback string.
- Fallback test: spy on _fallback_stream to capture the StreamOptions
  actually reaching the fallback path and assert task_display_mode,
  stop_blocks, and update_interval_ms all propagate -- previous test
  passed even when options were silently dropped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@patrick-chinchill
Copy link
Copy Markdown
Collaborator Author

Review verdict: LGTM. Refreshed and reviewed latest head 90c1339 against main. No issues found in StreamingPlan option propagation to native stream and fallback stream paths. Verification: tests/test_thread_faithful.py passed (133 passed) and ruff passed on src plus test_thread_faithful.py. Residual risk: standalone fidelity script remains nonzero because other PR parity gaps are not in this branch. Formal GitHub approval is blocked because the authenticated account owns this PR.

patrick-chinchill and others added 3 commits April 24, 2026 02:52
Python port was missing the `StreamingPlan` PostableObject entirely, so
`thread.post(StreamingPlan(stream, options))` silently dropped the options
(`group_tasks`, `end_with`, `update_interval_ms`) -- there was no
`kind == "stream"` branch in `Thread.post()` to map them onto
`StreamOptions` before invoking `adapter.stream(...)` or the fallback
`post+edit` path.

Wiring fix:
- Add `StreamingPlan` + `StreamingPlanOptions` in `chat_sdk.plan`
  (mirrors upstream `streaming-plan.ts`).
- `Thread.post()` now detects `kind == "stream"` and maps
  `group_tasks -> task_display_mode`, `end_with -> stop_blocks`,
  `update_interval_ms -> update_interval_ms` onto `StreamOptions` before
  streaming. Works for both native (`adapter.stream`) and fallback paths.
- `_handle_stream` accepts `extra_options` so the mapped fields are
  merged on top of the message-context defaults.

Tests (6 new faithful translations from upstream `thread.test.ts`
`[Streaming]` block):
- should pass StreamingPlan PostableObject options to adapter.stream
- should pass StreamingPlan with only groupTasks
- should pass StreamingPlan with only endWith
- should pass StreamingPlan with only updateIntervalMs
- should route StreamingPlan through fallback when adapter has no native streaming
- should still work without options (backward compat)

Fidelity: 548 -> 554 matched (+6); 6 `[Streaming]` gaps closed. All 3,551
tests pass. Closes #56.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- StreamingPlanOptions mapping: replace truthy checks with `is not None`
  so update_interval_ms=0 and end_with=[] propagate correctly (thread.py
  post dispatcher and _fallback_stream interval guard). Per CLAUDE.md
  Port Rule #1; diverges from upstream thread.ts, which has the same
  latent bug.
- StreamingPlan: raise RuntimeError from is_supported() and
  get_fallback_text() so misroutes through post_postable_object /
  Channel.post fail loudly instead of posting "" or attempting a
  wrong-shape adapter.post_object("stream", ...). Also guard
  post_postable_object() with an early kind=="stream" check for a
  clearer error message. Diverges from upstream postable-object.ts,
  which silently posts the empty fallback string.
- Fallback test: spy on _fallback_stream to capture the StreamOptions
  actually reaching the fallback path and assert task_display_mode,
  stop_blocks, and update_interval_ms all propagate -- previous test
  passed even when options were silently dropped.

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

- Add non-parity row for StreamingPlan.is_supported/get_fallback_text
  raising vs upstream's silent true/"" return
- Extend fallback test to explicitly cover update_interval_ms=0 and
  end_with=[], locking in the truthiness fix against future regression

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@patrick-chinchill patrick-chinchill force-pushed the feat/streaming-tests-56 branch from 90c1339 to 05095e6 Compare April 24, 2026 09:53
@patrick-chinchill patrick-chinchill merged commit 2cb7544 into main Apr 24, 2026
10 checks passed
patrick-chinchill added a commit that referenced this pull request Apr 24, 2026
Parity catch-up release for upstream chat@4.26.0. Bundles 8 PRs (#64 #65 #66 #67 #73 #74 #75 #76) + small followup cleanups. See CHANGELOG.md for details.
patrick-chinchill added a commit that referenced this pull request Apr 24, 2026
…y baseline

Two infra-level changes to the fidelity check:

1. `.github/workflows/lint.yml` — the `Clone upstream vercel/chat at
   pinned parity tag` step no longer carries `continue-on-error: true`.
   The clone is infrastructure the fidelity check depends on; if it
   fails, the job should fail there rather than swallow the failure
   and hope a later step catches it. Combined with the script-level
   guard from the previous commit, this is defense in depth.

2. CI now runs `scripts/verify_test_fidelity.py --strict`. Every
   `[post with Plan]` test that was baselined is now ported (PR #75
   and PR #74 in the 0.4.26.2 bundle), so the repo ships at 0 missing.
   `scripts/fidelity_baseline.json` is reduced to `{"missing": {}}`
   (metadata retained so `--update-baseline` and the documented
   workflow still function for future upstream syncs).

Closes self-review gap #2 on #72.
patrick-chinchill pushed a commit that referenced this pull request May 7, 2026
Per gemini-code-assist review on PR #83. Without the repo prefix, GitHub
auto-links the upstream PR numbers to local PRs in chat-sdk-python, which
collides with the local refs (#64, #66, #67, #74, #82) elsewhere in the
file. Use vercel/chat#NNN so the upstream refs link correctly.

https://claude.ai/code/session_01FyMxQn2BEAzmwKS1GZczKj
patrick-chinchill pushed a commit that referenced this pull request May 10, 2026
Final upstream-coverage audit before merging the 7 sync PRs (#84-#90)
identified one undocumented N/A item:

vercel/chat#415 (Teams SDK 2.0.8 + User-Agent) is a JS-only botbuilder
dependency bump. The Python Teams adapter uses raw aiohttp (no
botbuilder), so there is no equivalent dependency to bump. The optional
User-Agent: Vercel.ChatSDK header on the ~9 outbound aiohttp call sites
is a defense-in-depth nice-to-have; deferred as a follow-up rather than
landed in this sync.

Updates:
- CHANGELOG.md: tick all completed items and link them to their PRs
  (#84, #85, #86, #87, #88, #89, #90, plus already-merged PR #74).
  Document #415 inline as N/A.
- docs/UPSTREAM_SYNC.md non-parity table: add row for Teams User-Agent
  header divergence so future syncers don't try to "port" the JS bump.

Item #6 (concurrency.maxConcurrent) is already implementation-covered
in the Python port (existing divergence row at L492). The 4 new TS
concurrency tests in chat.test.ts have Python-specific equivalents at
test_chat_faithful.py L2969-3055 that don't name-match — leaving as
deferred fidelity-baseline polish since the behavior is verified.

Verdict from the coverage audit: all 18 substantive ports across PRs
#84-#90 are upstream-verified. No commits in chat@4.26.0..f55378a were
missed. Ready to start merging.

https://claude.ai/code/session_01FyMxQn2BEAzmwKS1GZczKj
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.

Port 6 missing StreamingPlan option tests to test_thread_faithful.py

1 participant