Release v0.6.0 - #15
Merged
Merged
Conversation
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
There was a problem hiding this comment.
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
Confidence Score: 5/5The 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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release v0.6.0
Bumps version from
0.5.0to0.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
iterate_methodsanditerate_runsasync 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 newPagingNotTerminatingErrorinstead of looping forever on a cursor that cycles across non-empty pages.get_run_detail(run_id)to fetch a single run's execution details, includingmthds_contentsandinputs, which are excluded from list views for performance.viewsparameter tovalidateandvalidate_filesfor opt-in structured views (e.g.VALIDATION_VIEW_INPUT_FORM), and extendedPipelexValidationReportwith typedwarnings,liftable_pipes, andinput_formfields.SuggestedFixand a fix-operation vocabulary (FixOpKind,FixSafety, etc.) toValidationErrorItem, along with a newmissing_pipe_codefield.parse_method_filesandserialize_method_filesto convert custom Python source files to and from the platform's at-rest catalog string format.method_id:execute,start, andstart_and_waitnow acceptmethod_idas a first-class, typed keyword parameter.Changed
list_methodsandlist_runsnow return page envelopes (MethodPageandRunPage) instead of bare arrays, withq,limit, andcursorquery parameters forwarded based on presence rather than truthiness. (Breaking)PipelineRun.method_idandpipe_codeare now nullable to accurately reflect platform behavior for ad-hoc runs and dynamic pipes. (Breaking)MethodData.pythonis now a typedlist[MethodFile]instead of a raw string, converted automatically at the client boundary. (Breaking)delete_methodnow returns aMethodDeletionAcceptedobject instead ofNone, reflecting that deletion is an asynchronous cascade rather than an immediate synchronous action. (Breaking)extraparameter on run methods now rejectsmethod_id; it must be passed via the dedicated named parameter, and passing a non-stringmethod_idraises aPipelineRequestErrorat the client boundary rather than delegating the failure to the server. (Breaking)mthdsdependency floor from>=0.8.1to>=0.8.2.ruffdev dependency to0.16.4to match the version the VS Code extension bundles, convertedpyproject.tomlselector lists to rule names instead of codes, and explicitly ignoredtoo-many-statements-in-try-clause.Fixed
list_methodsandlist_runscrashed against the deployed platform after the API shifted to{items, next_cursor}envelope responses; tests were updated to mock the correct paginated shape.docs/architecture.mdto honestly reflect the parity gaps with the TypeScript@pipelex/sdk(e.g. deferringlint,format,codegen) instead of claiming a surface-complete client.README.mdquickstart (PipelexValidationResultis owned by this package, notmthds).TokensUsageRecordas a Pipelex runtime extension rather than an MTHDS protocol specification.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_runsreturned arrays and crashed against{items, next_cursor}; they now return page envelopes with async iterators and raisePagingNotTerminatingErroron runaway cursors.New Features - New features added
iterate_methodsanditerate_runsfollownext_cursoracross pages with a capped backstop.get_run_detail(run_id)returns a run’s inputs and method contents.validate/validate_filesacceptviews; reports typewarnings,liftable_pipes, andinput_form.ValidationErrorItemaddsmissing_pipe_codeand a structuredSuggestedFix(fix-op union).parse_method_files/serialize_method_filesconvert custom Python sources to the catalog form.execute/start/start_and_waitaccept a typedmethod_id; iterators may raisePagingNotTerminatingError.Migration - Steps needed for adoption (if applicable)
MethodPage/RunPage; useiterate_*to traverse all items.PipelineRun.method_idandpipe_codebeing null.MethodData.pythonaslist[MethodFile]; use the parse/serialize helpers when reading/writing.delete_methodcall sites to handleMethodDeletionAccepted(async cascade).method_idvia the named parameter; remove it fromextra, and expect a clientPipelineRequestErrorfor non-strings.mthds>=0.8.2and, for dev,ruff==0.16.4.Written for commit eaf4132. Summary will update on new commits.