Skip to content

Release v0.6.0 - #15

Merged
lchoquel merged 23 commits into
mainfrom
release/v0.6.0
Aug 25, 2026
Merged

Release v0.6.0#15
lchoquel merged 23 commits into
mainfrom
release/v0.6.0

Conversation

@lchoquel

@lchoquel lchoquel commented Aug 25, 2026

Copy link
Copy Markdown
Member

Release v0.6.0

Bumps version from 0.5.0 to 0.6.0 — a minor bump, per the repo's pre-1.0 rule that breaking changes move the minor segment.

Changelog

[v0.6.0] - 2026-08-25

Added

  • Paginated catalog surface: Introduced iterate_methods and iterate_runs async generators that follow pagination cursors to fetch entire catalogs without silent truncation, backed by new product models (MethodPage, MethodSummary, RunPage, RunDetail, RunErrorReport, MethodFile). A runaway page backstop raises the new PagingNotTerminatingError instead of looping forever on a cursor that cycles across non-empty pages.
  • Run details: Added get_run_detail(run_id) to fetch a single run's execution details, including mthds_contents and inputs, which are excluded from list views for performance.
  • Validation views & typed reports: Added a views parameter to validate and validate_files for opt-in structured views (e.g. VALIDATION_VIEW_INPUT_FORM), and extended PipelexValidationReport with typed warnings, liftable_pipes, and input_form fields.
  • Structured repair proposals: Added SuggestedFix and a fix-operation vocabulary (FixOpKind, FixSafety, etc.) to ValidationErrorItem, along with a new missing_pipe_code field.
  • Method file parsers: Added parse_method_files and serialize_method_files to convert custom Python source files to and from the platform's at-rest catalog string format.
  • Typed method_id: execute, start, and start_and_wait now accept method_id as a first-class, typed keyword parameter.

Changed

  • list_methods and list_runs now return page envelopes (MethodPage and RunPage) instead of bare arrays, with q, limit, and cursor query parameters forwarded based on presence rather than truthiness. (Breaking)
  • PipelineRun.method_id and pipe_code are now nullable to accurately reflect platform behavior for ad-hoc runs and dynamic pipes. (Breaking)
  • MethodData.python is now a typed list[MethodFile] instead of a raw string, converted automatically at the client boundary. (Breaking)
  • delete_method now returns a MethodDeletionAccepted object instead of None, reflecting that deletion is an asynchronous cascade rather than an immediate synchronous action. (Breaking)
  • The extra parameter on run methods now rejects method_id; it must be passed via the dedicated named parameter, and passing a non-string method_id raises a PipelineRequestError at the client boundary rather than delegating the failure to the server. (Breaking)
  • Bumped the mthds dependency floor from >=0.8.1 to >=0.8.2.
  • Linting & tooling: Bumped the ruff dev dependency to 0.16.4 to match the version the VS Code extension bundles, converted pyproject.toml selector lists to rule names instead of codes, and explicitly ignored too-many-statements-in-try-clause.

Fixed

  • Pagination crash: Fixed a critical bug where list_methods and list_runs crashed against the deployed platform after the API shifted to {items, next_cursor} envelope responses; tests were updated to mock the correct paginated shape.
  • Docs – parity claims: Updated docs/architecture.md to honestly reflect the parity gaps with the TypeScript @pipelex/sdk (e.g. deferring lint, format, codegen) instead of claiming a surface-complete client.
  • Docs – import paths: Fixed a broken import path in the README.md quickstart (PipelexValidationResult is owned by this package, not mthds).
  • Docs – brand attribution: Corrected docstrings and architecture docs to attribute TokensUsageRecord as a Pipelex runtime extension rather than an MTHDS protocol specification.
  • Docs – dead links: Replaced unopenable internal repository citations in docstrings and comments with explicit, readable rule descriptions.

Summary by cubic

Aligns the SDK with the platform’s paginated list APIs and the updated validate contract, adds first-class run/catalog features, and clarifies doc titles/status with no behavior changes. Previously list_methods/list_runs returned arrays and crashed against {items, next_cursor}; they now return page envelopes with async iterators and raise PagingNotTerminatingError on runaway cursors.

  • New Features - New features added

    • iterate_methods and iterate_runs follow next_cursor across pages with a capped backstop.
    • get_run_detail(run_id) returns a run’s inputs and method contents.
    • validate/validate_files accept views; reports type warnings, liftable_pipes, and input_form.
    • ValidationErrorItem adds missing_pipe_code and a structured SuggestedFix (fix-op union).
    • parse_method_files/serialize_method_files convert custom Python sources to the catalog form.
    • execute/start/start_and_wait accept a typed method_id; iterators may raise PagingNotTerminatingError.
  • Migration - Steps needed for adoption (if applicable)

    • Update callers to consume MethodPage/RunPage; use iterate_* to traverse all items.
    • Handle PipelineRun.method_id and pipe_code being null.
    • Treat MethodData.python as list[MethodFile]; use the parse/serialize helpers when reading/writing.
    • Update delete_method call sites to handle MethodDeletionAccepted (async cascade).
    • Pass method_id via the named parameter; remove it from extra, and expect a client PipelineRequestError for non-strings.
    • Pin dependencies to mthds>=0.8.2 and, for dev, ruff==0.16.4.

Written for commit eaf4132. Summary will update on new commits.

Review in cubic

lchoquel and others added 22 commits August 21, 2026 10:59
Matches the version the Ruff VS Code extension bundles, so the editor's
language server and the CLI run the same binary. The fallout is auto-fix
output that make lint would re-apply anyway: selector lists now name rules
instead of coding them, and noqa suppressions moved to the new
ruff: ignore[...] directive. float-equality-comparison, new under preview,
joins the existing tests/ relaxations in per-file-ignores.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The extension has moved on since this sweep was planned: 2026.74.0 bundles
0.16.4, so pinning 0.16.2 would have reopened the editor-versus-CLI gap
the bump exists to close. 0.16.4 reports nothing new here and reformats
nothing, so this is the pin and the lock only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Move ruff to 0.16.4 and take the lint fallout
…eded

Every repo in the workspace running select = ["ALL"] with preview has
settled on ignoring too-many-statements-in-try-clause: shrinking a try
clause changes which statements its handlers cover, which makes satisfying
the rule an error-handling refactor rather than lint cleanup.

This repo has no findings for it, so the decision was never written down
here. That is fine until someone writes the first long try clause, at which
point they hit a rule the workspace has already ruled on and have to reach
the same conclusion alone — or reach a different one. Recording the ignore
now, with the reasoning inline, costs nothing and removes that.

A survey across the five select=ALL repos found their ignore lists share 76
of 99 rules, and that every divergence is inert: each rule a repo lacks
fires zero times there. This entry and its counterpart in conformance close
the only two gaps that encode a policy rather than local circumstance.

No code changes; the rule fires nowhere today. agent-check and agent-test
both pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Record the too-many-statements-in-try-clause decision before it is needed
Promote the hosted platform's `method_id` from the untyped `extra` bag to a
first-class keyword parameter on `execute` / `start` / `start_and_wait`. It
reaches the wire through the base client's generic extension passthrough,
which merges it into the body without knowing what it means — the protocol
client stays catalog-agnostic while this client owns the concept. The
argument is now documented, validated, and impossible to smuggle:
`method_id` inside `extra` raises, which is breaking for the previously
undocumented `extra={"method_id": ...}` path.

Because the merged extension mapping is non-empty, a by-id run with no
inline source still satisfies the base client's "something to run"
precondition; the selector also rides the blocking `execute` fallback, so a
bare runner can answer the 422 that names it.

The reserved-keys guard stays per layer: `method_id` must never become
reserved in `mthds`, which has no business rejecting another vendor's
arguments. Doctrine: the workspace spec `docs/specs/pipelex-platform-api.md`
-> "Layered extension policy".

Also fixes `delete_method`, which was annotated `-> None` and promised an
empty synchronous delete. The route answers 202 and the erasure continues
asynchronously, so it now returns the new `MethodDeletionAccepted` — a
misleading contract around a destructive operation is worth the break.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
TODOS.md breaks the design in wip/updates.md into phases with checkboxes,
records the decisions that were open as settled, and states the gates each
phase has to pass before it counts as done.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre
…t-in

The `/v1/validate` surface moved in pipelex-api 0.17.0 and 0.18.0 and this SDK
had not followed. Nothing crashed — every affected model is `extra="allow"`, so
the new keys rode `model_extra` — but nothing was typed either, and there was no
way to ask for the `input_form` view at all.

`validate` and `validate_files` now take a `views` opt-in after `render`. Unlike
`render`, the list is sent verbatim: nothing injected, nothing de-duplicated, an
explicit `[]` sent as `[]`, because the server resolves the tokens as a set and
lenient-ignores the ones it does not know. Left at `None` the key is absent, so
the default response stays byte-identical for consumers that discard views.

The valid arm now types `warnings`, `liftable_pipes` and `input_form`, and
`ValidationErrorItem` types `missing_pipe_code` and `suggested_fix` with the
whole fix-op vocabulary as a closed discriminated union. Both lists default
empty and `input_form` defaults `None`, so a body from an older runner still
parses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre
Two prose fixes `@pipelex/sdk` 0.14.0 shipped, which apply here for the same
reason: `pipelex-sdk` is a public PyPI package.

`TokensUsageRecord` was described as "specified in the MTHDS protocol spec".
It is not — inference accounting is a Pipelex runtime extension the MTHDS
Protocol does not model, so the hosted API is what pins the wire contract and
this SDK mirrors the runtime's own record. Getting that wrong misplaces the
brand boundary the rest of the architecture is organized around.

Several docstrings, comments and doc passages cited internal specs and the
conformance suite by bare repo-relative path. Those resolve to nothing for
anyone who clones this repo, so they read as rot rather than as a deliberate
boundary; each now states the rule it was citing. References to the sibling
public pipelex-sdk-js repo are kept where they explain a port.

No behaviour change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre
…ullable run fields

`list_methods` and `list_runs` crashed against the deployed platform. Both
routes now answer a `{items, next_cursor}` envelope — methods since 2026-08-18,
runs since 2026-08-11, both live in production — and this SDK still iterated a
bare array. Iterating the envelope dict yields its keys, so the very first call
was `MethodData.model_validate("items")` and every invocation raised. Nothing
was red because the unit tests mocked the pre-paging shape.

`list_methods` now returns a `MethodPage` of `MethodSummary` rows and
`list_runs` a `RunPage`, each with the paging and filter parameters the platform
serves, kept on presence rather than truthiness. `iterate_methods` and
`iterate_runs` follow the cursors; there is deliberately no `list_all_methods()`,
because an all-at-once helper needs a cap and a cap is the silent truncation
paging removed. The two iterators stop on different signals and the difference
is in the server: a method page can be empty with a live cursor because `q`
filters after the index read, a run page cannot because its date bounds are key
conditions.

`PipelineRun.method_id` and `pipe_code` are nullable, which the platform
genuinely serves and both cases are ordinary. `MethodData.python` is a typed
`list[MethodFile]` converted at the boundary, so the platform's three-way write
contract falls out of `exclude_none=True`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre
A published client validates its request-option types where it names them,
raising rather than dropping or forwarding a wrong-typed value. The bare
truthiness check this replaces made an arbitrary partition of the wrong values:
it silently dropped the falsy ones (`0`, `[]`) and forwarded the truthy ones
(`123`, `["mt_1"]`) to a server `422` — a different partition than
`@pipelex/sdk` makes for the same argument on the same wire. One wrong value,
one answer, and now the same one in both SDKs.

`None` and `""` still contribute nothing. The merge helper takes `object`
rather than `str | None` because it *is* the runtime boundary, and the callers
it guards against are the untyped ones a type checker never sees.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre
Three claims the code no longer supports, found on the Phase-5 read-through:
the intro line advertising "the full 0.1.0 surface", the parity section's
"Methods — full coverage" (which contradicted the gap list directly above it),
and "Models — full field-for-field match". The Models paragraph now also names
the two deliberate divergences from the JS mirror: the page envelopes keep the
wire's snake_case `next_cursor`, and the method-files converter lives here
rather than in the protocol package.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre
The plan reasoned that the run iterator needed no page ceiling because its
empty-page stop already caught a server minting fresh cursors. That reason was
too narrow: the empty-page stop only fires when the server returns *nothing*,
so a cursor cycling across two or more values (`c1 -> c2 -> c1`) while every
page is non-empty trips neither it nor the adjacent-cursor check, and the
generator would request forever while re-yielding the same runs.

Both iterators now share `_MAX_LIST_PAGES` and raise `PagingNotTerminatingError`
at it. Reusing the existing backstop is deliberate over tracking every cursor
seen, which would cost unbounded memory for the same protection.

Found independently by Greptile and Codex on PR #14.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre
Three sites the plan named or implied were left out of sync, all found on PR
review and all prose:

- `docs/architecture.md`'s `TokensUsageRecord` bullet still attributed the
  record to the MTHDS protocol spec. Phase 2 named that site and the changelog
  asserts it was corrected, but the commit only reached the `method_id`
  citation in that file. It now carries the same wording as `runs.py` and
  `docs/run-usage.md`: inference accounting is a Pipelex runtime extension the
  MTHDS Protocol does not model, so the hosted API pins the wire contract.
- `CHANGELOG.md` still cited `docs/specs/pipelex-platform-api.md`, a workspace
  path that resolves to nothing for anyone who clones this public package —
  the exact pattern the entry a few lines below claims to have removed. The
  sentence now states the rule and points at the sibling public JS SDK.
- The `validate` override section of `docs/architecture.md` still introduced
  "two Pipelex-API extensions" after Phase 1 added the third; the client
  docstring already said three.

`TODOS.md` records these alongside the review findings that were judged not
worth acting on, with the reason for each.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre
Cubic read Phase 2's citation rule as covering this tracker. It does not: the
rule is about the shipped surface, where a workspace path resolves to nothing
for anyone who installs the package. A tracker read by this PR's reviewers is
a different document, it cites the workspace throughout by design, and the
sentence in question already states its rationale before citing the item.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre
Pre-landing review findings, all mechanical and none touching behaviour.

The README's "Public import paths" section told readers to reach
PipelexValidationResult through mthds.runners.api.models, which raises
ImportError — that name is not in the installed mthds at all. The Pipelex
narrowing of the verdict union is owned here, exactly as the "Brand
boundary" section of docs/architecture.md says, so the repo contradicted
itself. The section now carries a pipelex_sdk.validation_models bullet and
cites mthds.protocol.models.ValidationResult as the neutral union it
narrows.

The two page-ceiling tests asserted only PagingNotTerminatingError.page_limit,
which echoes back the constant the test itself patched — so five scripted
responses against a limit of two passed whether the raise fired on the first
page or the last. Each now also asserts the call count, mutation-checked by
loosening the comparison in client.py: both tests fail where they previously
passed.

Two hardcoded counts ("three Pipelex-API ways/extensions") had already gone
stale once inside this branch, and the Raises: entries on execute and start
named only the extra-smuggling trigger, not the non-string method_id guard
this branch added.

The deferred findings are recorded in wip/pr-14-review-notes.md, and the one
that reaches other repos — pipe_statuses, a field no server fills, declared in
this SDK, @pipelex/sdk and pipelex-app — is filed in the workspace inbox.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre
The hosted-run-extensions section of docs/architecture.md contrasted the
method_id run option with "build_inputs(method_id=…) and prepare_inputs,
which are client-side sugar that resolves an id to inline files". Neither
helper accepts a method_id: build_inputs takes a BuildInputsRequest of
files / pipe_ref / format / explicit, prepare_inputs takes files / pipe_ref
/ inputs, and catalog-id resolution for input preparation is recorded as
deferred in the 0.5.0 changelog. Following that sentence gets a TypeError.

The contrast the bullet wanted to draw is real — the run routes pass the id
through untouched, the input-preparation helpers work on an inline closure —
so it now draws it truthfully instead of inventing a signature.

Also corrects the mthds floor in the tracker's preflight: it recorded
>=0.8.1, but pyproject.toml has said >=0.8.2 since bc17c07, an ancestor of
this branch's base, so the number was wrong the day it was written.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre
Follow the platform's paged lists, type the 0.17/0.18 validate contract, and guard method_id
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre

@cubic-dev-ai cubic-dev-ai Bot 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.

All reported issues were addressed across 22 files

Heads up: you’re close to your included review allowance. Set a flex budget so reviews don’t pause.

Re-trigger cubic

Comment thread wip/updates.md
Comment thread wip/updates.md
Comment thread wip/updates.md
Comment thread wip/updates.md
Comment thread wip/updates.md
Comment thread wip/pr-14-review-notes.md Outdated
Comment thread docs/architecture.md
@greptile-apps

greptile-apps Bot commented Aug 25, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge, with no concrete changed-code defect identified.

The pagination, method-file serialization, validation extensions, deletion response, and method-ID execution paths are internally consistent and covered by focused contract tests; the remaining considered edge cases are intentional contracts or lack a realistic reachable failure.

Reviews (1): Last reviewed commit: "Release v0.6.0" | Re-trigger Greptile

Review of PR #15 raised seven documentation findings, five of them on
`wip/updates.md` alone, each asking to rewrite or delete a section of it
because the work it designs has since shipped. That is what a design
document is for, and this repo already splits the two roles: the design
says what and why, and `TODOS.md` is the tracker that carries the
per-item status, by the decision recorded in the tracker itself. The
sections stay as written; what was missing was a pointer saying so, which
is why the file read as stale five separate times. It now opens with one
line naming its status, the release it shipped in, and the tracker.

The other two findings were real and small. The sdist listing in the
PR #14 review notes was taken at that review's own commit and introduced
as a build of the current tree, so it now reads as the current release's
archive; it says which build it is and why it is kept rather than re-run.
And the architecture doc's scope heading still said "for v0.1" over a
list maintained through later releases, including a bullet corrected on
this branch — the heading dates to the original scaffolding commit and
was the half that sweep missed.

Documentation only. No Python, no dependency and no changelog change: the
wip notes are not release-facing and a heading rename is not either.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011p6KPGP2eiLjni5sErWUre
@lchoquel
lchoquel merged commit 1752868 into main Aug 25, 2026
21 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 25, 2026
@lchoquel
lchoquel deleted the release/v0.6.0 branch August 25, 2026 10:44
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant