Skip to content

fix(core): point misplaced run kwargs at the call site that works (P1-03) - #260

Open
migarci2 wants to merge 1 commit into
backblaze-labs:mainfrom
migarci2:fix/pipeline-misplaced-run-kwargs
Open

fix(core): point misplaced run kwargs at the call site that works (P1-03)#260
migarci2 wants to merge 1 commit into
backblaze-labs:mainfrom
migarci2:fix/pipeline-misplaced-run-kwargs

Conversation

@migarci2

@migarci2 migarci2 commented Aug 2, 2026

Copy link
Copy Markdown

Summary

Pipeline options live in three places — the constructor, the fluent builders,
and the run entry points — and there is no rule a caller can guess about which
is which. timeout is a run() kwarg; cache is a builder. Both read as "how
this run behaves".

When you guess wrong, the error is a dead end:

$ python -c "
from genblaze_core import Pipeline
from genblaze_core.testing import MockProvider
Pipeline('t').step(MockProvider(), model='m', prompt='x').run(cache='...')"
TypeError: Pipeline.run() got an unexpected keyword argument 'cache'

Correct, but it names neither where caching is configured nor how to spell it
there, so the loop is guess → TypeError → grep the source. After this PR:

TypeError: Pipeline.run() got an unexpected keyword argument 'cache' — caching
is configured on the pipeline: .cache(StepCache(...)).

Changes

  • libs/core/genblaze_core/pipeline/pipeline.py
    • _MISPLACED_RUN_KWARGS — a module-level table mapping a misplaced option
      to the call site that works. Covers cache, config, metadata,
      tracer, preflight, tenant_id, project_id, chain, moderation,
      structured_log, max_concurrency.
    • Pipeline._reject_unsupported_run_kwargs() — a static helper in the same
      shape as the existing _reject_config_tenant() (fail loudly, point at the
      supported path).
    • run, arun, batch_run, abatch_run take **unsupported and reject it
      on the first line.

The signatures are not actually widened at runtime: every unknown keyword
still raises TypeError. Names not in the table keep CPython's exact wording
(Pipeline.run() got an unexpected keyword argument 'typo'), with no trailing
hint, so anything matching on that string still matches. There is a test
pinning that.

max_concurrency deserves a note. It is a real parameter of arun(),
batch_run() and abatch_run(), so Python binds it normally there and it
never reaches the table. It only fires on run() — the one entry point that
does not take it — where the hint points at the async/batch entry points. A
test pins that batch_run(..., max_concurrency=1) still works, so the table
cannot shadow a genuine parameter.

stream() / astream() forward **run_kwargs to run() / arun(), so they
inherit the redirect for free.

  • libs/core/tests/unit/test_pipeline_misplaced_kwargs.py — 20 tests: each
    redirect message, the max_concurrency asymmetry both ways, CPython wording
    preserved for unknown names, all four entry points plus stream(), and two
    happy-path tests asserting every documented run() kwarg still binds. 12
    fail on main.
  • docs/features/pipeline.md — a "Where each option goes" table, including the
    three run kwargs that are not universal (progress and on_retry are
    run()/arun() only; max_concurrency is everywhere except run()).
    Verified against the live signatures rather than written from memory.
  • CHANGELOG.md[Unreleased] entry under genblaze-core.

Notes for reviewers

This is the "better error" half of docs/exec-plans/feedback.md row P1-03,
deliberately not the alias half. Making run(cache=...) actually work is an
API-surface decision the plan already scopes for Wave 3B, and it would make the
three-places problem worse rather than better. This PR only makes the wrong
guess self-correcting. If you'd rather land the alias instead, or keep the
docs table without the **unsupported catch, say so and I'll rework or close
it — the table alone is still worth having.

Test plan

  • make test passes
  • make typecheck passes (mypy, 92 source files)
  • ruff check libs/ cli/ examples/ clean; ruff format --check clean on
    the changed files
  • make lint — the ruff format --check step reports 17 pre-existing
    README/CHANGELOG code-block findings already present on a clean
    af84f8b; the count is unchanged by this branch and none are in files it
    touches
  • New tests fail on main (12 of 20), pass with the change

Related

  • docs/exec-plans/feedback.md row P1-03 (partial — error message only)
  • Row P3-15, the docs/runtime alignment sweep, for the pipeline.md table

…-03)

Pipeline options live in three places — the constructor, the fluent builders,
and the run entry points — with no rule a caller can guess. `timeout` is a
`run()` kwarg; `cache` is a builder. Guessing wrong produced a dead end:

    TypeError: Pipeline.run() got an unexpected keyword argument 'cache'

which names neither where caching is configured nor how to spell it, so the
only way out was to read the source. It now reads:

    TypeError: Pipeline.run() got an unexpected keyword argument 'cache' —
    caching is configured on the pipeline: .cache(StepCache(...)).

`run`, `arun`, `batch_run` and `abatch_run` take `**unsupported` and reject it
immediately, so the signatures are not widened at runtime: every unknown
keyword still raises TypeError, and names outside the redirect table keep
CPython's exact wording so existing string matches still hold.

`max_concurrency` is a real parameter of arun/batch_run/abatch_run, so Python
binds it there and it never reaches the table; the redirect only fires on
run(), the one entry point that does not take it.

This is the error-message half of feedback.md row P1-03, not the alias half —
accepting `run(cache=...)` is an API-surface decision scoped for Wave 3B and
would widen the three-places problem rather than narrow it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 2, 2026 21:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Improves developer ergonomics in genblaze-core by turning “misplaced kwarg” TypeErrors on pipeline run entry points into actionable messages that point callers at the correct constructor/builder API, and documents where pipeline options belong.

Changes:

  • Add a mapping of commonly-misplaced run-entry-point kwargs to “where this option actually lives” hints, and reject unsupported kwargs early in run/arun/batch_run/abatch_run.
  • Add unit tests pinning redirect messages while preserving CPython’s exact wording for genuinely unknown kwargs.
  • Document option placement in docs/features/pipeline.md and record the behavior change in CHANGELOG.md.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
libs/core/genblaze_core/pipeline/pipeline.py Adds misplaced-kwarg hint table + a shared rejection helper; updates run entry points to collect and reject unsupported kwargs.
libs/core/tests/unit/test_pipeline_misplaced_kwargs.py Adds regression tests for redirect messaging, CPython wording preservation, and max_concurrency asymmetry behavior.
docs/features/pipeline.md Documents where options belong (constructor vs builders vs run entry points).
CHANGELOG.md Notes the improved TypeError messaging behavior under [Unreleased] for genblaze-core.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 1964 to 1968
on_retry: Any = None,
_config_override: RunnableConfig | None = None,
_owns_sink: bool = True,
**unsupported: Any,
) -> PipelineResult:
Comment thread CHANGELOG.md
constructor- or builder-level option is passed to them. `run(cache=...)`
previously produced a bare `got an unexpected keyword argument 'cache'`,
which named neither where caching is configured nor how to spell it;
it now adds `— caching is configured on the pipeline:
Comment on lines 2200 to 2204
on_retry: Any = None,
_config_override: RunnableConfig | None = None,
_owns_sink: bool = True,
**unsupported: Any,
) -> PipelineResult:
Comment on lines 2884 to 2888
on_progress: Any = None,
pipeline_timeout: float | None = None,
on_step_complete: Any = None,
**unsupported: Any,
) -> list[PipelineResult]:
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