Skip to content

Release v0.14.0 - #65

Merged
lchoquel merged 8 commits into
mainfrom
release/v0.14.0
Sep 6, 2026
Merged

lchoquel merged 8 commits into
mainfrom
release/v0.14.0

Conversation

@lchoquel

@lchoquel lchoquel commented Sep 6, 2026 •

Copy link
Copy Markdown
Contributor

Release v0.14.0

Bumps version from 0.13.0 to 0.14.0. A minor bump, because the standard-version cut is breaking for consumers evaluating manifest constraints.

Closes L-260906-52f8e4

Changelog

Added

  • Version constraint evaluation helper: Added is_mthds_version_satisfied to mthds.package.manifest.schema, letting runtimes evaluate a manifest's mthds_version constraint against the implemented MTHDS_STANDARD_VERSION. Manifest parsing deliberately skips this check, leaving the decision to warn or fail up to the runtime.
  • Versioning documentation: Added docs/versioning.md defining the four version numbers in play (Standard, Protocol, Package release, and Runner) and how manifest constraints and crate stamps interact with them.
  • New test fixtures: Expanded the projection fixture corpus to cover native.Anything at an input slot and a structured concept using text fields named url and homepage_url.

Changed

  • Standard version bump (Breaking): MTHDS_STANDARD_VERSION moved from 1.0.0 to 2.0.0. Manifest constraints are now evaluated against 2.0.0 (e.g., >=1.0.0 still passes, but ^1.0.0 no longer does), and pipelex now stamps normalized crates with this version. PROTOCOL_VERSION remains at 0.6.0, as the HTTP runner contract and routes are unchanged.
  • Version constant docstrings: MTHDS_STANDARD_VERSION and PROTOCOL_VERSION now include docstrings pointing to the governing specification pages and clarifying that these values are copies of standard cuts rather than package-level decisions.
  • Fixture unshapeable records: Updated the fixture manifest's unshapeable array to track a second open engine bug (L-260902-10eb56), where the input shaper incorrectly refuses the empty object template for native.Anything slots.

Fixed

  • Compound version constraint parsing: Fixed parse_constraint raising a SemVerError on compound constraints containing a space (e.g., ">=1.0.0, <2.0.0"). Whitespace around blocks is now stripped, aligning the parser with the documented manifest format.
  • Specification site links: Fixed broken 404 links to the MTHDS specification site across documentation and docstrings; links now use the /latest/ prefix (e.g., https://mthds.ai/latest/spec/...).
  • Fixture README provenance: Corrected the fixture corpus README.md to match the current capture state, adding output_bundle.mthds to the bundle list and output_form.json to the required copy instructions.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Fztu8DBy81PdyzSEG4cVRR


Summary by cubic

Releases v0.14.0, following the standard's 2.0.0 cut. The breaking change: MTHDS_STANDARD_VERSION goes from 1.0.0 to 2.0.0, so constraints like ^1.0.0 no longer satisfy while >=1.0.0 still does. Also adds is_mthds_version_satisfied for runtimes to evaluate a manifest's mthds_version (parsing still doesn't), and fixes parse_constraint to accept spaced compound constraints like >=1.0.0, <2.0.0 instead of raising SemVerError. Closes L-260906-52f8e4.

  • Adds versioning documentation, docstrings for the version constants, and updates projection fixtures with new pipes and an unshapeable entry.

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

Review in cubic

lchoquel and others added 8 commits September 2, 2026 14:51
* chore: re-capture the projection fixture corpus from pipelex dev

The shared inputs-template projection corpus moved in `pipelex`, so the
copy committed here was stale. This is a pure re-capture: no projection
code changed, because the Python projection reads whatever kind the
descriptor states and both moves are descriptor-side.

The capture adds one pipe, `input_semantics_scaffold.scaffold_open_natives`,
which puts the natives whose payload shape the descriptor states openly at
slot positions — the one place the corpus never reached. `native.Dynamic`
and `native.Composite` are structureless by design, so their node is
`unknown` and both renderers agree on the empty mapping. `native.JSON` is
not: its pinned blueprint carries a required `json_obj`, which makes the
dict inside it the corpus's first required unknown node.

That position is what the capture declares as a new divergence class,
`unknown-empty-object`. The projection renders the empty object, because
the descriptor withholds the payload shape there and inventing one would
stop it projecting the descriptor; the reference engine reflects the
runtime content class instead and fills the dict with a sample key/value
pair whoever fills the template in has to delete. The empty object
round-trips through the input shaper cleanly, so the class records a
difference of vantage rather than a defect and carries no ledger item.

`input_form.json`, `pipe_io_contracts.json` and `inputs_template/manifest.json`
move with the new pipe; every pre-existing key in all three is byte-for-byte
unchanged. `mthds-js` commits the identical bytes.

Advances L-260831-56a78f

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01TEH4cihpjsEwgtKL16nzbK

* docs: hold the divergence record's prose half to the manifest

Review follow-ups on the open-natives recapture, all outside the capture
itself — the fixture bytes are untouched and stay byte-identical to the
mthds-js twin.

The README beside the corpus explains each divergence class in prose, and
that was the one half of the record nothing enforced: the manifest is
checked hard, so a class that stops occurring has to be retired
deliberately, but a retired class used to leave its bullet behind
describing a difference that no longer exists, with the suite still green.
`test_inputs_template_projection.py` now holds the README's bullet list to
the manifest's own declarations, in both directions — the twin of the check
`mthds-js` carries.

`input_form.json` and `pipe_io_contracts.json` are one capture taken in one
command, but nothing outside the contracts file's own parse test read it, so
one half could lose a pipe the other still held with the whole suite green.
Deleting the new pipe's contract took tests/unit from 557 passed to 556
passed and no failures; the two payload files now have to name the same
pipes.

The changelog entry claimed the JSON blueprint's `json_obj` is the corpus's
first required unknown node. It is not: `widget.matrix[]`, `opt.matrix[]`
and `many[].matrix[]` are required unknown nodes and pre-date this capture.
What is new is the position — the first required unknown node at an
object-field rather than a list-item slot, which is where the engine's
rendering diverges.

Two more prose claims the committed bytes contradict: the README's summary
of which divergence entries carry a `null` ledger item named two of the
three there now, and it still described byte parity as skip-gated on a
projection that has since landed under L-260830-e7c5b5, so the job runs.

Advances L-260831-56a78f

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01TEH4cihpjsEwgtKL16nzbK

---------

Co-authored-by: Claude Opus 5 <[email protected]>
…ut contract (#59)

Mirrors the standard's new Output-Form Descriptor page and the `json_schema`
member it added to the output contract, which landed in one version because
neither is useful without the other.

`mthds.protocol.output_form` declares no node type: `field` is `InputFormField`,
reused verbatim — an output is a concept reference exactly like an input is, so
its kinds, its nesting and its constraints are the same questions with the same
answers, and a second node union would be a second place for them to drift. One
`field`, not a `fields` list: a pipe has exactly one output. What the module adds
is the enforcement of what an output does NOT carry — `presence` and `gating` are
optional on the node so a slotless node can exist, not so a producer may fill
them in with something plausible, and one that does now fails the parse.

`PipeOutputContract.json_schema` is breaking: the shape is closed and the member
required, so a payload from an earlier engine fails the parse. It is the
PAYLOAD's schema, which is where its rule departs from its input twin's — an
input's describes what a caller sends, an output's what comes back, so a plural
output's is the list content model rather than a bare array.

The parity capture gains an output_form.json and a fourth corpus bundle covering
outputs specifically. That bundle exists because the three before it all resolved
to Text: a corpus whose every pipe outputs one native scalar can only capture one
output descriptor and one output schema, so the plural wrap — the producer
obligation that fails silently — would never have appeared in it.


Claude-Session: https://claude.ai/code/session_019VJ89z3Gza9CW25pQombFK

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
`tests/fixtures/protocol/` is committed byte-identically here and in `mthds-js`, and until now nothing in either repo checked that. The only comparison lived in `conformance`, where it runs on a `conformance` pull request rather than on the one that moves the corpus — so a recapture landed here without its `mthds-js` twin was caught weeks later by an unrelated change, and the pairing held only because prose in two pull request bodies asked for it.

`.github/workflows/protocol-corpus-parity.yml` checks `mthds-js` out on every pull request and compares the two trees, which fails the pull request that would land a one-sided recapture instead of reporting it afterwards.

Two properties make it deployable. It needs no secret: both mirrors are public, so the sibling checkout is unauthenticated and the job runs on a pull request from a fork exactly as it does on one from a branch — a gate that needed `conformance` itself, which is internal, could not have done that. And it resolves the sibling ref as this pull request's own branch name when the sibling carries a branch of that name, falling back to `dev`: a recapture lands as a paired pull request in both mirrors at once, and comparing each against the other's `dev` would leave both red until the first merged.

The file is a vendored copy of `conformance/tests/mthds/fixtures/protocol_corpus_parity_workflow.yml` and is byte-identical in both mirrors, which is why it derives which repo it is running in from `github.repository` rather than naming one. `make check-fixture-drift` in `conformance` fails when a copy drifts or goes missing, so the coupling cannot be quietly undone.

Advances L-260902-61be99


Claude-Session: https://claude.ai/code/session_012E1hEFhVP2Ze394Aic1v58

Co-authored-by: Claude Opus 5 <[email protected]>
…published v0.12.0 (#61)

`ab27956` added its three entries under `## [v0.12.0] - 2026-09-01`, a version published the day before it landed. The code they describe is not in that release:

    $ git cat-file -e v0.12.0:mthds/protocol/output_form.py  ->  absent
    $ git cat-file -e main:mthds/protocol/output_form.py     ->  absent

So the released notes claimed a module and a contract change nobody who installed 0.12.0 has, while `[Unreleased]` — the section the next release draws from — carried neither. The breaking one is what makes this worth a commit of its own: `PipeOutputContract.json_schema` is a required member on a closed shape, so a payload from an earlier engine fails to parse, and cutting a release from `[Unreleased]` as it stood would have shipped that break with no note under its own heading.

This is a pure move; no wording changes. The new module and its suite go to `### Added`, and the required member on an existing contract to `### Changed`, which is what each of them is.

Two entries deliberately stay under v0.12.0. The inputs-template projection, the TOML emitter and the corpus were all in that release — `tests/fixtures/protocol/inputs_template/manifest.json` is present at the tag — so their attribution is correct. The longer restatement of the corpus entry that `ab27956` also added duplicates the shorter one above it, but it describes v0.12.0 content and is not misattributed, so it is left alone.


Claude-Session: https://claude.ai/code/session_012E1hEFhVP2Ze394Aic1v58

Co-authored-by: Claude Opus 5 <[email protected]>
Same shape as the mthds-js sync: the only conflict was CHANGELOG.md, and
main's side wins — its `## [v0.13.0]` heading is the published record, while
dev still carried the same work under `[Unreleased]`.

Verified rather than assumed: every topic under dev's `[Unreleased]` appears
in main's release section, and the released code is there too
(`mthds/protocol/output_form.py`, and `scaffold_open_natives` in the committed
fixture corpus).
Two pipes join the corpus from scaffold_bundle.mthds: scaffold_anything_slot,
which places native.Anything at an input slot the descriptor states as an
unknown node, and scaffold_dynamic_prompt, which pairs native.Dynamic with a
structured concept whose text fields are named url and homepage_url. Both add
worked sites to the existing text-named-url and optional-field-included
divergence classes rather than declaring a new one, so the projection needed no
change.

The unshapeable record gains the scaffold_anything_slot pair in both shapes,
refused with a StuffFactoryError and tracked by L-260902-10eb56.

The fixtures README's provenance is corrected alongside: it listed three bundles
where the capture has been taken from four since output_bundle.mthds joined, and
omitted output_form.json from the files to copy across.

Captured from pipelex dev at 551fe3463. mthds-js commits the identical bytes.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01AUyEZQcLJ4Qhb9vKoSw6vD
….0.0, each constant declared once (#64)

* feature: follow the standard's version cut — MTHDS_STANDARD_VERSION 2.0.0, each constant declared once

The MTHDS specification unified its release number with its standard version
and cut both at 2.0.0 (mthds#63), a major accounting for the breaking native,
manifest, lock and resolution changes it had shipped while MTHDS_STANDARD_VERSION
stood still at 1.0.0 since February. This package copies that cut: the standard
version becomes 2.0.0, the protocol version stays 0.6.0 — the two numbers are
independent and the routes did not change — and each constant now carries a
docstring naming https://mthds.ai/spec/versioning/ as the rule that governs it,
so following the next cut is one edit per number rather than a search.

Adds `is_mthds_version_satisfied`, which evaluates a manifest's `mthds_version`
against MTHDS_STANDARD_VERSION and against nothing else. The constraint was
validated for spelling here and then evaluated nowhere, so every runtime
open-coded the parse-and-match itself. Parsing a manifest still does not
evaluate it: a package asking for a standard version this runtime does not
implement is a well-formed manifest, and whether that warns, refuses the load or
fails validation is the runtime's call.

Fixes a pre-existing bug found at that seam: `parse_constraint` handed the
string to SimpleSpec untouched, which rejects ">=1.0.0, <2.0.0" over the space
alone — while the manifest format documents that exact spelling and
`is_valid_version_constraint` accepts it. Any manifest or dependency written
that way raised SemVerError from the resolver instead of resolving.

The `PipelexRunner.version` TODO stays; it retires when the pipelex CLI exposes
`protocol_version` (L-260829-43c082). Adds docs/versioning.md.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_017VEgU3Bn7kfRA4ddJZ48HH

* fix: prefix every spec-site link with /latest/, and pin the constraint spellings

mthds.ai publishes each release under its own prefix and redirects only the
root to /latest/, so a bare https://mthds.ai/spec/<page>/ is a 404 while
https://mthds.ai/latest/spec/<page>/ is the page. Verified live: the bare shape
returns 404 for input-form-descriptor and pipe-io-contracts, the prefixed shape
returns 200 for both. Every link into the site — the docstrings this branch
adds, docs/versioning.md, and the ones in docs/inputs-template.md and
docs/runners.md that predate it — now carries the prefix.

The versioning page is the exception, and it stays a forward reference: it
landed on the standard's dev branch in mthds-ai/mthds#63 and has never been
published, so it is a 404 at both shapes. mthds.ai's `latest` still aliases
0.4.0, cut before the page existed. Publishing it is L-260906-50cf25.

Also pins that is_valid_version_constraint and parse_constraint agree on every
constraint spelling, in both directions. Stripping the blocks fixed the spaced
compound constraint, and the risk it introduced is the opposite error: an empty
block left by a doubled or trailing comma must stay a refusal rather than being
silently dropped, which would widen the constraint the manifest asked for.

Advances L-260829-5b9a42

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019dKCMzkj6yhetfgNeA4cEm

---------

Co-authored-by: Claude Opus 5 <[email protected]>

@greptile-apps greptile-apps 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.

Your trial has ended. Reactivate Greptile to resume code reviews.

@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-09-06T21:43:09.105082Z 5097555 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 8da87c6 into main Sep 6, 2026
19 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 6, 2026
@lchoquel
lchoquel deleted the release/v0.14.0 branch September 6, 2026 21:51
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.

2 participants