From 73cd92c782db5ce6efc0ff782de7fdf7982c2099 Mon Sep 17 00:00:00 2001 From: Trevor Hudson Date: Fri, 31 Jul 2026 16:09:27 -0700 Subject: [PATCH] Release 0.13.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Six merged PRs of correctness and test-quality work, unreleased since 0.12.1. The user-facing change is fan_out: a node marked `fan_out: true` now dispatches once per element on all six runtimes, not just DBOS. The other five handed the whole upstream list to a single invocation, so the "one call per element" the IR describes was a fiction everywhere but one target, and judge signatures had to accept the batch. The rest is the suite's ability to catch regressions. Three mutation sweeps (64 mutations) found fifteen places where a real regression would have shipped green — per-node timeouts ignorable on two runtimes, DEFAULT_MODEL flippable to Opus at ~5x cost, an agent-side cost estimate that could be off by 1000x because it was only compared against itself. Every slow e2e suite now runs in CI (three of twenty-seven did), all seven checks are required, and a test can no longer spend inference tokens. Also bumps the three companion version files the suite pins against the package version, and repairs the CHANGELOG compare links, which had been stale since 0.9.0. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01SBuSDL7Svm7iDzgmhTpDSW --- .claude-plugin/marketplace.json | 2 +- CHANGELOG.md | 76 ++++++++++++++++++++++++++++++- CITATION.cff | 2 +- plugin/.claude-plugin/plugin.json | 2 +- src/rote/__init__.py | 2 +- 5 files changed, 79 insertions(+), 5 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 627e940..0235a2c 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,7 +10,7 @@ "name": "rote", "source": "./plugin", "description": "Compile an Anthropic-style skill into a deterministic pipeline (Temporal, Cloudflare Workflows, or DBOS) from inside Claude Code, then trigger the deployed workflows over MCP.", - "version": "0.12.1" + "version": "0.13.0" } ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index a79ccf9..39ab0f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,75 @@ While `rote` is pre-1.0, minor versions may include breaking changes. ## [Unreleased] +## [0.13.0] - 2026-07-31 + +### Added +- **`fan_out` dispatches per element on all six runtimes.** A node marked + `fan_out: true` is invoked once per element of its bound list, and the + result binds as a list in input order. This worked on DBOS only; the + other five handed the whole upstream list to a single invocation, which + meant a judge signature had to accept the batch and the "one call per + element" the IR describes was a fiction everywhere else. Per runtime: + DBOS enqueues one durable step per element, python uses `pool.map`, + Temporal `asyncio.gather` over one activity execution each, Cloudflare + and Inngest `Promise.all` over per-element steps, DBOS-TS + `Promise.allSettled` + unwrap. + + Which input is the fanned list is resolved by + `rote.adapters._common.fan_out_element_param` — fan_out edge marker > + incoming-edge source > only node-bound param, with ambiguity an + emit-time error rather than a guess. It lives in the language-neutral + common module on purpose: two adapters disagreeing about which input is + the list would make one `pipeline.yaml` mean two different things. + + Two traps worth knowing if you read the emitted code. Cloudflare and + Inngest key a durable step by its *name*, so each element emits + `` `[${_index}]` ``; reusing one name made Cloudflare return element + 0's cached result for all N, so the run succeeded, the output had the + right length, and every entry was identical. And a parkable (MCP-bound) + fan_out node on Cloudflare runs its elements sequentially, because + `waitForEvent` inside a promise combinator is undocumented and its + timeout throws. +- **An undefined fanned list names the node that expected it.** Emitted + code routes the list through a guard (`fanOutList` in TypeScript, + `_fan_out_list` in Python) that throws with the node id and the IR + reference. Without it the failure was `Cannot read properties of + undefined (reading 'map')` inside generated code the user never wrote — + found by running it, on the first live fan_out run. The cause is almost + always an upstream node that didn't return the key the IR says it does. + +### Changed +- **Every slow end-to-end suite now runs in CI.** Three of twenty-seven + did; Cloudflare, DBOS-TS and Inngest had no automated coverage at all, + on the reasoning that they need a Node or Docker toolchain that CI + doesn't have. `ubuntu-latest` ships both, and the premise had never + been checked. All seven jobs — lint/types/sanity, three Python + versions, and the Python, TypeScript and DBOS-TS e2e suites — are now + required status checks. +- **A test can no longer spend inference tokens.** Anything that doesn't + require inference is a test: automated and fast. Anything that costs + tokens is an eval: run deliberately, never in CI. That split is now + enforced rather than trusted — the suite scrubs vendor credentials and + makes a bare-name lookup of `claude` / `codex` fail. The second half is + the one that matters, because `claude -p` authenticates from an OAuth + session, so having no API key was never protection. Two DBOS suites had + been quietly burning real subscription inference on every run. + +### Fixed +- **Fifteen test gaps found by mutation testing**, across three sweeps + and 64 mutations. These are defects in the suite's ability to detect + regressions, not in shipped behavior — but each one is a real + regression that could have shipped green. The most consequential: + per-node `timeout:` was ignorable on Temporal and Cloudflare gates; + `DEFAULT_MODEL` could be flipped to Opus (~5x cost) and + `DEFAULT_MAX_TURNS` halved with nothing failing; the agent-side cost + estimate could be off by 1000x because it was only ever compared + against itself; an `agent_loop` could understate its tokens and wall + time threefold; and `rote compile` could report success while doing + nothing when handed a bad config. +- `1h` in a per-node `timeout:` rendered as `"1 hours"` in emitted + comments and docstrings. + ## [0.12.1] - 2026-07-30 ### Changed @@ -542,7 +611,12 @@ While `rote` is pre-1.0, minor versions may include breaking changes. Anthropic API, Codex stub), the `rote compile` / `rote emit` CLI, and the BDR-outreach example skill. -[Unreleased]: https://github.com/trevhud/rote/compare/v0.9.0...HEAD +[Unreleased]: https://github.com/trevhud/rote/compare/v0.13.0...HEAD +[0.13.0]: https://github.com/trevhud/rote/compare/v0.12.1...v0.13.0 +[0.12.1]: https://github.com/trevhud/rote/compare/v0.12.0...v0.12.1 +[0.12.0]: https://github.com/trevhud/rote/compare/v0.11.0...v0.12.0 +[0.11.0]: https://github.com/trevhud/rote/compare/v0.10.0...v0.11.0 +[0.10.0]: https://github.com/trevhud/rote/compare/v0.9.0...v0.10.0 [0.9.0]: https://github.com/trevhud/rote/compare/v0.8.0...v0.9.0 [0.8.0]: https://github.com/trevhud/rote/compare/v0.7.0...v0.8.0 [0.7.0]: https://github.com/trevhud/rote/compare/v0.6.0...v0.7.0 diff --git a/CITATION.cff b/CITATION.cff index 9f6069d..9590da0 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -15,7 +15,7 @@ authors: repository-code: "https://github.com/trevhud/rote" url: "https://roteskills.com" license: Apache-2.0 -version: 0.12.1 +version: 0.13.0 keywords: - agent-skills - claude-skills diff --git a/plugin/.claude-plugin/plugin.json b/plugin/.claude-plugin/plugin.json index b5331c1..d6a9820 100644 --- a/plugin/.claude-plugin/plugin.json +++ b/plugin/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "rote", "displayName": "Rote", - "version": "0.12.1", + "version": "0.13.0", "description": "Compile fuzzy AI skills into deterministic workflows: /rote:compile compiles a SKILL.md into a runnable pipeline (Temporal, Cloudflare Workflows, or DBOS); /rote:serve exposes compiled pipelines as MCP tools.", "author": { "name": "Trevor Hudson", diff --git a/src/rote/__init__.py b/src/rote/__init__.py index f634e4d..18bc388 100644 --- a/src/rote/__init__.py +++ b/src/rote/__init__.py @@ -1,3 +1,3 @@ """rote — compile fuzzy AI skills into deterministic workflows.""" -__version__ = "0.12.1" +__version__ = "0.13.0"