- Releases
- Ironflow v0.31.0
Ironflow v0.31.0
Ironflow v0.31.0 fixes a pub/sub consumer group that never redelivered: ACK_MODE_AUTO resolved to a JetStream policy that tracks no ack state, so max_redeliveries, the redelivery delay and both backpressure modes were quietly inert. Subscriptions can now resume from a stream sequence instead of guessing with a replay count, and the Python SDK gains typed ConnectRPC clients across 44 methods.
Breaking Changes
Section titled “Breaking Changes”- Existing pub/sub consumer groups are rebuilt on first activation after upgrade.
ACK_MODE_AUTOnow maps toAckExplicitPolicy, which is what the dispatcher beneath it always assumed. NATS refuses an ack-policy change in place (err_code=10012), so each pre-existing durable is recreated when that error surfaces — once per durable, driven by the error rather than an upfront probe, so a healthy group pays no round-trip. Position is preserved viaAckFloor.Stream + 1. Groups that silently dropped failed messages will now redeliver them (#1849, #1853)
Features
Section titled “Features”- Resume a fan-out subscription from a stream sequence.
SubscribeOptions.start_after_sequenceis a position, not a count —replaycannot express “the ones I have not seen”, so reconnecting with it either repeats work or skips events depending on how long the disconnect lasted. Mutually exclusive withreplay(INVALID_ARGUMENTrather than a silent merge) and rejected alongsideconsumer_group, whose position the server already owns. Delivery stays at-least-once (#1848, #1851) - Typed ConnectRPC clients in the Python SDK —
IronflowRPCandAsyncIronflowRPC, 44 capability methods across 8 namespaces, 40 unary and 4 server streams, generated from protobuf by Buf via connect-py. A capability ledger classifies all 83 served RPCs and is gated in CI, so a newly served RPC fails the build until it is classified. The REST client is unchanged. The Python SDK is still source-only — it is not published to PyPI (#1781, #1829) - The Python SDK retries unary RPCs the protos mark side-effect-free — 3 attempts on
unavailable, on the same backoff schedule the REST client already uses. Everything else is sent exactly once (#1809, #1846) - The Python SDK reconnects a subscription you positioned, when and only when the caller set
start_after_sequence. Without a position there is nowhere honest to resume from (#1848, #1854) - 35 of the 83 served RPCs are annotated
NO_SIDE_EFFECTS. The protos, not a hand-maintained list, are now the source of truth for what is safe to retry, and Go, TypeScript and Python all carry the annotation through generation (#1809, #1841) - New
ironflow-fitagent skill — analyzes a codebase and reports where Ironflow fits, with ranked opportunities and file:line evidence across Java, C#, Python, Rust, Node and Go (#1874)
- Pub/sub consumer groups never redelivered.
ACK_MODE_AUTOis the default for an unsetack_mode, and it mapped toAckNonePolicy— JetStream tracks no ack state for such a consumer, so everyAck()andNak()in the dispatcher was a no-op whose error was discarded. Inert as a result:max_redeliveries,redeliver_delay_ms, the no-members-available nak, and the redelivery legs of bothBUFFERandBLOCKbackpressure (#1849, #1853) SubscriptionEvent.sequencewas zero on every pub/sub path, for the whole life of the API. The sequence is assigned by the server and arrives on the PubAck, after the payload is already on the wire, so neither construction site could set it — and nothing asserted it (#1848, #1851)ironflow initprojects no longer commit their admin key.servewrites.ironflow/under the cwd, including.ironflow_bootstrap_key.json(an admin API key, mode 0400) and.ironflow_jwt_secret. Neither scaffold template ignored that directory, soironflow initfollowed byironflow servestaged both secrets (#1859)- Every published artifact shipped a stale license. Four byte-identical copies of the root
LICENSEstill carried the[LICENSE_EMAIL]placeholder that was resolved at the root in #1576. The marketing copy is now generated from the root instead of vendored (#1855, #1856, #1857) - Browser SDK bearer authentication for KV, config and KV watches. Token credentials with API-key precedence and empty-key fallback across all three REST paths, plus URL-encoded environment and credential parameters on the KV WebSocket watch. Outbox publications now carry event metadata, and
WaitForEventuses one timeout budget while preserving catch-up semantics (#1823) - Connect routes are derived from the mounted services rather than tracked in a parallel list that could drift from them (#1821)
- Two contracts the agent skills had backwards.
waitForEventwas documented as needing atry/catch— the step suspends the run by throwing an internalYieldSignalthe SDK catches at the handler boundary, so a user catch swallows it and the run “completes” without ever waiting. Separately, four files claimedstreams.appendstarves projections and must be paired with an explicit emit; one append writes two outbox rows in a single transaction, the second on the exact subject the projection durable filters on. The audit scanner enforced the broken advice as a CRITICAL rule; it is now inverted, and covers Go, one-linetryblocks and.catch()chains (#1867) - The Homebrew formula audit audited nothing. Homebrew disabled
brew audit [path ...], and a trailing|| echoin the release workflow swallowed the resulting exit 1 — so the brew channel reported green for an unknown number of releases. Both paths that reach the tap now share one audit script (#1820, #1834, #1835, #1840)
Improvements
Section titled “Improvements”- Typography across the dashboard, docs site and marketing — Figtree as the single sans, a derived JetBrains Mono heading curve, raised type sizes, and shared
brand/tokens instead of per-app values (#1832, #1844, #1876) docs/reference/api/sdk-comparison.mdis gated against derived coverage, so the SDK comparison table cannot drift from what the SDKs actually implement (#1826, #1827, #1833)- Guidance for teams on stacks with no Ironflow SDK, pointing at a working client path rather than overclaiming REST reachability (#1872, #1873, #1877)
make brew-preflightaudits the formula a release would generate, in about 30 seconds, before the release rather than during it
Ironflow Desktop ships on its own cadence; its changes are tracked in the Ironflow Desktop changelog posts.