Skip to content

Release v0.23.0 - #98

Merged
lchoquel merged 4 commits into
mainfrom
release/v0.23.0
Oct 16, 2026
Merged

lchoquel merged 4 commits into
mainfrom
release/v0.23.0

Conversation

@lchoquel

@lchoquel lchoquel commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Release v0.23.0

Bumps version from 0.22.0 to 0.23.0. Promotes dev → main.

Changelog

Added

  • Sending a method by hash: MthdsAPIClient.missing_blobs and upload_blob call the protocol's optional blob routes, typed by BlobRef, MissingBlobsRequest, MissingBlobsResult, MissingBlob and UploadTarget, and prepare_files and prepare_files_from_contents build a request's files from a listed tree or from bytes at hand: inline when the map, written as compact JSON in UTF-8 so that Base64 counts as its encoded text, is at most DEFAULT_INLINE_TREE_MAX_BYTES (256 KiB), or when the runner keeps no blob store, and otherwise uploading only the blobs the runner lacks and sending every file by hash. Files are read and hashed off the event loop, an upload carries exactly its target's headers and never the API key, and a refused one raises BlobUploadError, whose URL keeps no userinfo, query or fragment.
  • VersionInfo.blob_store: the version() handshake reads whether the runner keeps a blob store, false when the runner does not say.
  • EmptyMethodTreeError: list_method_tree and list_method_tree_at_root refuse a directory whose own tree is empty with this MethodTreeRefusedError, which also carries the listing's root, excluded_files, excluded_directories and raw_paths, so a caller that lists a directory to find the packages and repositories nested in it learns them even when the directory holds nothing but nested packages. The refusal's code stays empty_tree and its record stays the conformance corpus's, so a caller catching MethodTreeRefusedError is unaffected; its message now says when the root is itself a virtual environment.
  • Resolving a file reference over a set of tree paths: resolve_reference_in_paths runs the standard's resolution steps, the same implementation resolve_reference runs, in a set of tree paths rather than a MethodTree, for a runtime that holds only a tree's listing; with holder=None it resolves from the root a reference written in no file of the tree, is_one_file_tree gives the one-file tree's refusal, and a refusal as not in the tree names no membership rule, which a set of paths does not record. Steps 1 and 3 in URL context are public as url_path_of and percent_decode_url_path, which refuses as reference_invalid, naming the path, what step 3 refuses, and lexical_join takes holder=None to join from the root.

Changed

  • A method travels as files (Breaking): MthdsAPIClient.execute, start and validate, the MTHDSProtocol interface and PipelexRunner take the method as files, a map from tree path to file entry typed MethodFiles, in place of mthds_contents, and the protected _post_validate seam takes files too; an empty map is refused before any request. A runner that still accepts inline mthds_contents receives it through extra, and PipelexRunner writes the map out as a directory for pipelex run bundle and pipelex validate bundle, refusing a hash entry.
  • Typed file entries (Breaking): encode_file_entry and encode_file_map return FileEntry values, a str, a Base64FileEntry or a HashFileEntry, instead of plain dictionaries, and pydantic_core.to_json writes them in their wire form.

🤖 Generated with Claude Code


Summary by cubic

Promotes mthds to v0.23.0, the breaking release in which a method travels as a files map of typed file entries instead of inline mthds_contents, and the API client can send a tree by hash through the protocol's optional blob routes.

Breaking changes

  • execute, start, validate, MTHDSProtocol, and PipelexRunner now take the method as files; inline mthds_contents is only passed through extra.
  • encode_file_entry and encode_file_map return typed FileEntry values instead of plain dictionaries.

Added

  • prepare_files sends a tree inline when its compact JSON is at most 256 KiB or the runner keeps no blob store, otherwise uploading only the blobs the runner lacks and referencing each file by hash.
  • VersionInfo.blob_store reports runner blob-store support; uploads never send the API key, and a refused upload raises BlobUploadError.
  • EmptyMethodTreeError carries the root and what the listing kept out.
  • resolve_reference_in_paths resolves a reference over a set of tree paths, with url_path_of and percent_decode_url_path public.

Written for commit 5140ba8. Summary will update on new commits.

View guided diff Turn on auto-fix

lchoquel and others added 4 commits October 17, 2026 00:24
`MthdsAPIClient` and the local `PipelexRunner` now take a method as
`files`, the MTHDS standard's map of file entries, in place of
`mthds_contents`, and the client can send a tree by hash: `VersionInfo`
declares `blob_store`, the protocol models carry the blob routes'
shapes, and `prepare_files` sends a tree inline when its encoded map is
small or the runner keeps no blob store, otherwise uploading only the
blobs `POST /blobs/missing` names. This is the breaking protocol change
`pipelex-sdk`'s Python client builds on.

Closes L-261015-bebfc9
Closes L-261016-b75856
Advances L-261012-989e43

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Replaces inline `mthds_contents` with `files`, the MTHDS standard's map
of file entries, in `MthdsAPIClient` and the local `PipelexRunner`, and
lets the client send a method tree by hash. `prepare_files` sends the
tree inline when its encoded map is small or the runner keeps no blob
store, otherwise uploading only the blobs the runner lacks and
referencing every file by hash. This is a breaking protocol change that
`pipelex-sdk`'s Python client builds on.

- `VersionInfo` now reports `blob_store`; the blob routes' wire shapes
are typed models.
- Files are read and hashed off the event loop, an upload sends only its
target's headers and never the API key, and a refused upload raises
`BlobUploadError`.

Closes L-261015-bebfc9 and L-261016-b75856; advances L-261012-989e43.

<sup>Written for commit 2aa615e.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/mthds-ai/mthds-python/pull/95?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/mthds-ai/mthds-python/95?returnTo=https%3A%2F%2Fgithub.com%2Fmthds-ai%2Fmthds-python%2Fpull%2F95&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
An empty tree's refusal now carries what the listing kept out:
`list_method_tree` and `list_method_tree_at_root` raise
`EmptyMethodTreeError`, a `MethodTreeRefusedError` holding the root, the
excluded files and directories and their raw paths, so a caller listing
a directory for its nested packages, as pipelex does for a library
directory, learns them even when the directory's own tree is empty. The
refusal record stays the conformance corpus's `{"code": "empty_tree",
"names": []}`, so existing callers behave as before.

Closes L-261015-855658
Advances L-261012-989e43

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
`list_method_tree` and `list_method_tree_at_root` now refuse a directory
whose own tree is empty with `EmptyMethodTreeError`, a
`MethodTreeRefusedError` that also carries the listing's `root`,
`excluded_files`, `excluded_directories`, and `raw_paths`. This lets a
caller listing a directory for its nested packages learn them even when
the directory holds nothing else. The refusal record stays the
conformance corpus's `{"code": "empty_tree", "names": []}`, so existing
callers catching `MethodTreeRefusedError` are unaffected; the lister
still never returns an empty tree.

Closes L-261015-855658, advances L-261012-989e43.

<sup>Written for commit bf3154b.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/mthds-ai/mthds-python/pull/96?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/mthds-ai/mthds-python/96?returnTo=https%3A%2F%2Fgithub.com%2Fmthds-ai%2Fmthds-python%2Fpull%2F96&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

Co-authored-by: Claude Opus 5.5 <[email protected]>
A file reference can now be resolved over a set of tree paths, from a
holder or from the root, with `resolve_reference_in_paths`, and the URL
context's steps are public as `url_path_of` and
`percent_decode_url_path`, so a runtime holding only a tree's listing,
or a bundle parsed from a content string, resolves by the standard's
steps without its own copy. `resolve_reference` and the new entry point
share one implementation, and every corpus reference probe runs through
both.

Closes L-261016-0b2e7e
Advances L-261012-989e43

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds `resolve_reference_in_paths`, which runs the standard's
file-reference resolution steps over a set of tree paths instead of a
`MethodTree`, so a runtime holding only a tree listing, or a bundle
parsed from a content string, can resolve references without the tree.
With `holder=None` it resolves from the root, exactly as a reference
written in a file at the root; `resolve_reference` and the new entry
point share one implementation, and every corpus reference probe now
runs through both. The URL context steps 1 and 3 are public as
`url_path_of` and `percent_decode_url_path`, and `lexical_join` takes
`holder=None` to join from the root.

Closes L-261016-0b2e7e. Advances L-261012-989e43.

**Notes for callers**
- A refusal as not in the tree names no membership rule, which a set of
paths does not record; only `resolve_reference` adds it.
- A holder that is not one of the tree paths raises `ValueError`, for
both entry points.

<sup>Written for commit 9731079.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/mthds-ai/mthds-python/pull/97?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/mthds-ai/mthds-python/97?returnTo=https%3A%2F%2Fgithub.com%2Fmthds-ai%2Fmthds-python%2Fpull%2F97&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review 🔄 Running since 2026-10-16T22:48:19.635069Z 5140ba8 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@lchoquel
lchoquel merged commit 654db43 into main Oct 16, 2026
21 checks passed
@lchoquel
lchoquel deleted the release/v0.23.0 branch October 16, 2026 22:49
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 16, 2026
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