Skip to content

Release 0.6.0 (draft: version pending owner) - #246

Merged
deepfates merged 11 commits into
mainfrom
claude/release-0.6.0
Sep 28, 2026
Merged

deepfates merged 11 commits into
mainfrom
claude/release-0.6.0

Conversation

@deepfates

@deepfates deepfates commented Sep 28, 2026 •

Copy link
Copy Markdown
Owner

Draft of the next release. Nothing is tagged, published or merged. The version is 0.6.0 throughout, pending the owner's choice; each mention sits on one line, so changing it is a one-line edit per file (list below).

What changed

  • CHANGELOG.md: ## Unreleased is ## 0.6.0 — 2026-09-28. The sections are Security, Changed, Fixed, GEPA and Documentation, one of each. The section went from 510 lines to 494.
  • RELEASE_NOTES.md: replaced with the v0.6.0 document: description, why minor, install, headline changes, Upgrading from 0.5, and Known limits.
  • mix.exs @version "0.6.0"; priv/public_api.json package_version (regenerated with mix imp.public_api; that is the only line that changed); test/package_contract_test.exs asserts "0.6.0".
  • {:imp, "~> 0.6"} in README, docs/getting-started/setting-up.md, docs/production.md, docs/coming-from-dspy.md, the five livebooks, and examples/deployment (mix.exs, README.md).
  • The tree/v0.5.0 and blob/v0.5.0 links in README, docs and livebook 05 now point to v0.6.0. They point to the source of the release the docs describe, so they 404 until the tag exists.
  • README: "Imp 0.5 is experimental and is its first release on Hex" is now "Imp 0.6 is experimental".
  • Not changed: decisions.md rows that record the 0.5.0 ruling ({:imp, "~> 0.5"}, "0.5.0 is built but not published"). They are history. The second is stale, since 0.5.0 is on Hex; that is left for the owner.

Judgement calls in the CHANGELOG

Structure

  1. I dissolved "Examples and datasets". All four of its entries are breaking, so they are under Changed as "Breaking:", each keeping its migration. Its intro line ("Every change here is breaking…") is gone.
  2. I moved redaction and credential entries from Fixed to Security, as 0.5.0 filed credential leaks: redact-before-convert writers, connection structs, MCP OAuth structs, string map keys and the trajectory refusal message, the ACP session store, the pair rule with its divergence, and the LMError header stripping.
  3. GEPA stays its own section. Its two behaviour changes moved to Changed (item 9).

Breaking items that were not marked "Breaking:" before, now marked and given a migration
4. The tools field name is reserved in an Imp.react task signature, and a saved program with one no longer loads. This was inside the long react Fixed entry. Migration: rename the field and save the program again.
5. An Imp.Clients.ReqLLM client built or loaded no longer equals a bare struct. This was also in the react entry. Migration: compare by model.
6. A reply that answers no output is :missing_fields in Chat, JSON and XML, and ProgramOfThought's error changes from :missing_program to that parse error. This was in Fixed. Migration: match the parse error.
7. ReqLLMBatch no longer resends a request that may have run: timeouts, crashes and 5xx are :ambiguous, and a 0.5.0 checkpoint's transient requests become :ambiguous. I split the old entry. The no-resend behaviour and the classification are under Changed, marked breaking; the retry-after wait is under Fixed. Migration: check an :ambiguous request with the provider before resending it.
8. MCP 503 and 529 become :refused instead of :unknown. This was in Fixed. Migration: match :refused for them.
9. Imp.Datasets.csv/3 refuses some files 0.5.0 loaded, and nimble_csv is a new dependency. This was in Fixed; the migration was already there.
10. GEPA reports :with_errors where it reported :ok, including under the default raise_on_exception: true. Separately, under :beam_native, consecutive_outcome/2 counts an iteration that raised as :proposal_error, not :none. #238 left both unmarked because the return shape is unchanged. I marked them breaking because code that checks status or builds stoppers sees different results. Say if you would rather keep them unmarked in the GEPA section.

Merged, split or moved
11. The sentence about the ReqLLMBatch 0.5.0 checkpoint sat inside the ReqLLM.Error headers entry. It moved into the ReqLLMBatch entry.
12. There is a new Changed entry, "Imp 0.5.0 cannot read some files this release writes". It gathers three facts: a trajectory with atom keys and a report holding an Imp.History (each was a sentence in a GEPA entry, removed there), and a ReqLLMBatch checkpoint at schema version 2. The third is new: I checked it in code. 0.5.0's validate_checkpoint/1 matches only "schema_version" => 1 (git show v0.5.0:lib/imp/clients/req_llm_batch.ex), and this branch writes 2.
13. The two ProgramOfThought/CodeAct entries (the extraction instruction, and save/load) are now one.
14. The two GEPA candidate-label entries ("names real failures only" and "named 'Proposal failed: …'") are now one.
15. The redaction pair-rule entry now leads with the rule, then the three things it fixes, then the divergence, which keeps its reason. The old entry led with the saved-program symptom.
16. ExternalCommand: "It used two patterns of its own before the shared rules" became "in place of its own sk- and Bearer patterns".

Reworded to cut words, with no fact dropped: the StepError, safety-guard, adapter parse, CSV, consecutive_outcome, react step-format and roster-order entries. Please check these against the old text.

Dropped
17. "(a dynamic metric-metadata key, say)", an example in the trajectory atom-key sentence.
18. The examples "500, 502, 504" in the batch status list. The text says "any other 5xx", which covers them.
19. "A fallback never asks for two formats" at the end of the JSON fallback entry, because the sentence before it already says this.

Judgement calls in RELEASE_NOTES

  1. The known limits are the flat ["api_key", v] divergence (Redaction: one high-confidence pattern set, whole-string replacement #226, Redact reports, checkpoints, results and saved programs before converting them #240); checkpoints as sensitive resume state (GEPA from GEPA reports proposals that failed when raise_on_exception is false #238; Fast-Slow and Playbook from Redact reports, checkpoints, results and saved programs before converting them #240); step prose that quotes its own field names (Chat, JSON and XML: a reply that answers none of the requested outputs is a parse error #236); ReqLLM's own stream-failure log (0.5.1: ReqLLMBatch never re-dispatches a possibly-run request; Datasets.csv parses with NimbleCSV #229); the Bearer command-output case (Redaction: one high-confidence pattern set, whole-string replacement #226); and the prepared-validation window (Trajectory codec round-trips; GEPA resumes from every checkpoint it can #243). The Bearer wording is from Redaction: one high-confidence pattern set, whole-string replacement #226: a 12–15 character token, or one with no digit, followed by more text or a newline.
  2. The cowlib paragraph is kept word for word. Today, mix hex.audit lists exactly those two advisories as ignored. .audit_ignore holds both, and cowlib 2.20.0 is still the newest release on Hex (mix hex.info cowlib).
  3. Step 13 of "Upgrading from 0.5" says to re-evaluate saved agents because their prompt text changed. That follows from the react entries; neither says it in those words.
  4. The notes do not mention JetBrains.

Gates (on this branch)

  • mix format --check-formatted: exit 0
  • mix compile --warnings-as-errors: exit 0
  • mix docs --warnings-as-errors: exit 0
  • mix test test/documentation_contract_test.exs: 21 tests, 0 failures (1 excluded)
  • mix test test/public_api_manifest_test.exs: 25 tests, 0 failures. It failed first, on package_version, until the manifest was regenerated.
  • mix test test/package_contract_test.exs: 14 tests, 0 failures
  • mix package.check: "clean-room package proof passed: tmp/package-clean-room"

The full suite was not run. This change touches documentation, the version and the manifest only.

Fact-check corrections (61bc81d)

The fact-check found overstatements and omissions. Each is fixed in both files where it applies.

Corrections

  • Headline redaction claim: only GRPO checkpoints are redacted whole. The SIMBA, MIPROv2, InferRules, random-search and GEPA checkpoints redact failure reasons only. The headline now says so, and the checkpoint Known limit names all five plus Fast-Slow and Playbook.
  • mint 1.11.0 does not reach a Hex user. Imp's lock does not bind a consumer, and Imp sets no mint floor. The CHANGELOG Security line and the headline say so, and Upgrading step 1 adds mix deps.update mint hpax.
  • The Bearer command-output regression is now also stated in the CHANGELOG ExternalCommand entry.
  • The pair divergence is wider than the flat ["api_key", v] case. Any flat two-element name-first list that is not itself an element of a list stays unredacted: at the top level, in a tuple, or under a non-credential key. I checked this: Imp.Redaction.redact(["password","hunter2"]) and redact({:x, ["password","hunter2"]}) come back unchanged.
  • ReActV2 safety-guard migration: match {:error, %Imp.Predict.ReActV2.StepError{reason: %Imp.OperationalSafetyError{}}}; Evaluate and the optimizers already raise it. :cancellation is added to the guard kinds (@kinds in Imp.OperationalSafetyError).
  • tools migration: the saved file does not load, so "save it again" could not be followed. The text now says to rebuild with the field renamed; to keep optimized instructions and demos, rename the field in the saved file or optimize again.
  • "MCP and language-model calls read a status the same way" was wrong. Only MCP and ReqLLMBatch share Imp.Errors.status_outcome/1.
  • Text beside tool calls: keeping the text is DSPy's behaviour. Reading it as next_thought is Imp's; DSPy's Chat adapter leaves that field empty.
  • Wording: the roster order differed between VM runs, not between processes; PyPI is pypi-AgE; Upgrading 12 says "saved with Imp.dump/1".

Omissions added

  • Renderers now shape the JSON fallback and every JSON or XML request; a renderer that ignores its options sends a Chat-shaped fallback. This is in the CHANGELOG, the headlines and Upgrading step 15.
  • Lazy datasets are read once and held in memory (Evaluate, MIPROv2, InstructionSearch, SignatureOptimizer). This fixes one-shot streams.
  • Security: errors about an invalid devset, row, field entry or demo name the type and key names, not values.
  • With provider_stream: true, a stream/3 that raises is recorded and returns {:error, {:lm_failed, lm, error}}.
  • The raw LM output for text plus tool calls is %{text:, tool_calls:}.
  • ReqLLMBatch checkpoints gain retry_stopped and schema_migration events and not_before.
  • A thought that quotes its own field names becomes nil beside native tool calls. This is in the CHANGELOG adapter entry and in Known limits.
  • %Imp.Predict.ReActV2{} gains :tool_order. This is next to the ReqLLM :tool_calling equality entry and in Upgrading step 7.
  • Redaction tries 22 patterns where 0.5.0 tried 7, so it is slower on clean text.

After #247 and #248 merged

  • Merged origin/main (2ef5d01) into the branch.
  • Added a Fixed line for Signature fields named nil, true or false keep their names #248, checked against the merged lib/imp/signature/field.ex: a field written as nil, true or false keeps its name as text and round-trips. The atoms raise ArgumentError.
  • Redaction: an sk- key right after a hyphen #247 (an sk- key right after a hyphen) fixes a regression that was never released, so it gets no CHANGELOG line and no Known limit. No entry said such a key is shown; the ExternalCommand entry names only the Bearer exception.
  • Gates on the final commit:
    • mix format --check-formatted: exit 0
    • mix docs --warnings-as-errors: exit 0
    • doc contract: 21 tests, 0 failures (1 excluded)
    • package_contract: 14 tests, 0 failures
    • public_api_manifest: 25 tests, 0 failures

mint held at 1.10.1 (feba21a)

This supersedes the earlier mint lines in this body: the release no longer takes, requires or claims mint 1.11.

What was found. mint 1.11.0 no longer closes an HTTP/1 connection on a receive timeout (the {:error, %Mint.TransportError{reason: :timeout}} clause in Mint.HTTP1.recv/3), and Finch 0.23.0, the newest release, returns any open connection to its pool (transfer_if_open in lib/finch/http1/pool.ex). The next request on that connection is written behind the unanswered one and times out, and so does a retry that lands there. If the server answers late while a request is waiting, Finch raises CaseClauseError (reproduced here with plain Req.post: no case clause matching: {:status, #Reference<...>, 200}). On mint 1.10.1 the retry opens a new connection. Finch has an open, unmerged, unreleased fix: sneako/finch#397 ("Close abandoned HTTP/1 connections after request errors").

With ReqLLM's default pool (8 shards of one connection, chosen at random per request) a timeout spoils only the requests that draw the stuck shard; with Req's default pool it spoils every later request to that host.

What changed

  • mix.exs: {:mint, "~> 1.10"}. The comment says Imp matches Mint's error structs, and why the floor is not 1.11 (the test, .audit_ignore, finch#397).
  • mix.lock, examples/deployment/mix.lock, examples/workspace_agent/mix.lock: mint 1.10.1, hpax 1.0.4. mix deps.get in each (the deployment one with IMP_PATH=../.., as CI runs it) leaves the locks unchanged.
  • .audit_ignore: EEF-CVE-2026-91043, -92103, -94194, in the cowlib entries' format, with the shared reason, what makes each reachable or not (91043 and 92103 are HTTP/2 only; 94194 is HTTP/1 and reachable with a malicious server behind a strict intermediary), the retire condition (a Finch release with finch#397, or mint closing on timeout again; then move Finch and mint 1.11 together), and the date.
  • test/timed_out_connection_test.exs: a real Imp.req_llm client against Imp.Test.LocalHTTP (Bandit). The server holds the first request past the client's 200 ms timeout and answers the rest; Imp.LM.generate with max_retries: 0 must return {:error, %Imp.LMError{retryable: true}}, then {:ok, _} on a different server connection. The Finch pool_strategy: &hd/1 option pins every request to one shard, because ReqLLM's random shard choice would otherwise make the second call miss the stuck connection 7 times in 8. The comment says this test is why the lock holds 1.10.1 and names finch#397.
  • CHANGELOG: the Security entry now says the locks keep 1.10.1 and why, with the advisories' scope. The Declare the dependencies Imp uses directly #251 dependency entry says mint is ~> 1.10 and replaces "only mint moves an existing lock": the other requirements move no lock, and the mint one moves only a lock below 1.10.
  • RELEASE_NOTES: the headline mint bullet is gone; the Install section says a fresh mix deps.get resolves mint 1.11.0; a new Known limit states the behaviour, who is affected, the advisories' scope, and the application's choice: add {:mint, "~> 1.10.1"} to lock 1.10.1, or take 1.11.0 and accept that a connection that timed out is reused until the server closes it.

A consequence of the ~> 1.10 floor, checked in a disposable project: an application locked at mint 1.9.3 that adds a ~> 1.10 requirement moves to 1.11.0 on mix deps.get (Hex takes the newest release), and one that also declares {:mint, "~> 1.10.1"} resolves 1.10.1. The docs say so. A floor of ~> 1.8 (Finch's) would leave such an application where it is.

Falsification of the new test (the lock swapped with git show HEAD~1:mix.lock plus mix deps.get)

  • mint 1.11.0, Finch 0.23.0: 3 of 3 runs 1 test, 1 failure at the second Imp.LM.generate (line 75), reason %Req.TransportError{reason: :timeout}.
  • mint 1.10.1: 3 of 3 runs 1 test, 0 failures.
  • Without the shard pin the test passed on 1.11.0, which is why the pin is there.

Gates on feba21a

  • mix format --check-formatted: exit 0
  • mix compile --warnings-as-errors --force: exit 0 (427 files)
  • mix dialyzer: exit 0, "done (passed successfully)" (Total errors: 143, Skipped: 143, as before)
  • MIX_ENV=test mix quality.check: exit 0. credo "found no issues"; imp.deps.check "Every application Imp names is declared in mix.exs."; deps.audit "No vulnerabilities found."; hex.audit lists the two cowlib and three mint advisories as ignored.
  • mix package.check: exit 0, "clean-room package proof passed: tmp/package-clean-room"
  • mix docs --warnings-as-errors: exit 0
  • documentation_contract, documented_paths, public_api_manifest, package_contract, deployment_reference, dependency_advisory_mitigation and timed_out_connection together: 87 tests, 0 failures (1 excluded)
  • Full suite (1-minute load 8.6, no other test VM): 59 doctests, 9 properties, 3612 tests, 12 failures, 13 skipped (147 excluded). All 12 need the pinned DSPy/GEPA environments under tmp/ that this worktree does not have (tmp/dspy-parity-venv, tmp/dspy-3.2.1, tmp/gepa-v0.1.4, tmp/gepa-artifact); each fails on :enoent for that path or on the "pinned DSPy/GEPA sources are required" flunk. CI's differential job sets them up. None involves HTTP.

Turn Unreleased into 0.6.0: merge the changelog's sections, put every
breaking change under Changed with its migration, and replace the release
notes with the 0.6.0 document. Bump the version, the install lines, the
tag-pinned links and the API manifest's package version.
…/1 connections

mint 1.11.0 leaves an HTTP/1 connection open after a receive timeout and
Finch 0.23.0 returns it to its pool, so the next request on it waits behind
the unanswered one and times out. Declare mint ~> 1.10, lock 1.10.1 and hpax
1.0.4 here and in both examples, ignore the three mint advisories with their
reasons until a Finch release includes sneako/finch#397, add a regression
test that fails on 1.11.0 and passes on 1.10.1, and say so in the CHANGELOG
and release notes.
@deepfates
deepfates merged commit ce46672 into main Sep 28, 2026
10 checks passed
@deepfates
deepfates deleted the claude/release-0.6.0 branch September 28, 2026 18:49
@deepfates deepfates mentioned this pull request Sep 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant