Changelog
All notable changes to the fluxrig project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Phase 4: scale & hardening
| Version | Date | Status | Summary |
|---|---|---|---|
| v0.10.0 | 2026-09-07 | Delivered | The semantic layer stops being documentation: a spec's rules are enforced on traffic |
| v0.9.0 | 2026-09-03 | Delivered | Enrichment from outside the message, and correlation keys that survive a bus hop |
| v0.8.0 | 2026-08-24 | Delivered | EMV chip data: BER-TLV parsing with unknown-tag preservation |
| v0.7.1 | 2026-08-10 | Delivered | ISO 8583 TLV length hardening |
| v0.7.0 | 2026-08-01 | Delivered | Payment switch: Conductor gear, gear manifests, ISO 8583 TLS |
[v0.10.0] - 2026-09-07
The semantic layer stops being documentation: a spec could state its rules and nothing applied them.
Before upgrading. Two changes refuse specs that used to load, and both are
about a spec declaring what it is. Every spec must carry spec.id and
spec.version, and every spec must carry a wire block saying where its wire
layer comes from. A spec missing either is refused at boot, with a message naming
it, never per transaction. Every spec shipped in this repository is already in
that shape; both entries under Changed say what one that is not needs. New
behaviour is off by default: validation starts at off, so a message accepted
yesterday is not rejected today because the code was upgraded.
Added
- The spec's rules can be enforced on traffic.
codec_iso8583gainsvalidation:off(default),warnorenforce. Per-MTI field usage, the conditions that decide whether a rule applies, closed value sets and cross-fieldchecksare answered against every message the codec decodes or encodes. A rejection followson_error, exactly as a decode failure does; violations travel on the message ascodec.violationsand are counted onflux.iso8583.violationsby severity, kind and MTI.- The default is
offdeliberately: a message accepted yesterday must not be rejected today because the code was upgraded.warnis how you find out whether your spec matches your traffic before enforcing it.
- The default is
- A spec can state when a rule applies, and what a message must satisfy. Fields carry a per-MTI matrix (
usage,when,values_ref) and a spec carrieschecks, written in a total, side-effect-free expression language over the message being validated.- A
checkcarries a severity:rejectfails the message,warnrecords it and lets it through, which is what makes a rule deployable to a live fleet before it is enforced on one. - An element compares the way its
format.kindsays it does.amount,date,time,datetimeand the newnumerickind compare as numbers on every operator, so a rule can writefield(4) == 1000rather than the element's own zero padding. Every other kind compares as the characters it carries, which is what a response code needs:"00"is not"0".panis deliberately excluded, because a leading zero makes it a different card.
- A
fluxrig spec docrenders the protocol reference from the spec. The Mixer serves it too, atGET /api/v1/specs/{name}/{tag}/doc, and every entry in the spec listing carries the path to its own. Markdown for a repository or a docs site, HTML for a page that is read, printed or mailed. The HTML is self-contained: no scripts, stylesheets or fonts are fetched, so it opens offline.--scope publicomits every field markedscope: privateand states how many it withheld;--scope completeis the internal view. The per-message tables are derived on every render from the rules stored on the fields, so the two cannot drift.format.kind: numeric. A value that is a number rather than a code (a trace number, a sequence, a count), which had no way to be declared.- A stored spec's versions can be listed.
fluxrig spec history <name>andGET /api/v1/specs/{name}return every version of one spec, newest first by version rather than by arrival.fluxrig spec listand the/specslisting now carry when each version was filed, its size, the document's title and which versionlatestreaches;--jsonon both.
Changed
- BREAKING: a spec declares where its wire layer comes from. Every spec now carries a
wireblock:sourcenames a Moov base (moov:<name>) or a wire document beside the spec,fieldsstates what the dialect changes, and each is valid alone. Specs in the legacy vocabulary (meta:with a top-levelfields:fusing both layers,llvar_n-style type tokens) no longer load. Every spec shipped in this repository is already in the new shape; the SDL reference describes what a spec that is not needs. - BREAKING: a spec must declare
spec.idandspec.version. The schema has required them all along and the loader never read them, so a spec with no version at all loaded clean and its traffic carried a content hash that says which file ran and not which contract. A spec missing either is now refused at load: at boot, with a message naming the spec, never per transaction. Every spec shipped in this repository already declares both; a spec that does not needs the two fields added before upgrading. codec_iso8583manifest:on_erroris documented as defaulting todrop. It has always defaulted todrop; the manifest saidreject, so an operator reading the published contract configured for one behaviour and got the other.
Fixed
unknown_tags: droprejected instead of dropping. The policy documented three behaviours and implemented two: anything that was notpreservetook the same branch, so a spec asking to drop an unknown TLV tag had the whole message rejected, which is the opposite of what it asked for.VerifyConnectivitycould report convergence on a cancelled context. The bus delivers to its handlers without consulting the caller's context, so a probe could land after cancellation and Go picked at random between the two ready cases. A caller shutting down was told the telemetry plane is ready.
[v0.9.0] - 2026-09-03
Added
coatcheck:key_normalize. Key field values are canonicalized before they are joined, so the two sides of an exchange agree on a key even when they render the same value differently.trim(default) removes surrounding whitespace;numericalso drops leading zeros, for fixed-width fields decoded against specs that declare different widths.coatcheck:await_store. A store can forward the message without waiting for the write. The default stays blocking, which is right when the reply depends on the entry; set it false when the entry only enriches a record and holding a message for a control-plane write costs more than losing one.codec_iso8583:iso8583.mti_class. A decode now also exposes the leading MTI digits, which a request and its reply share. Correlation keys can be scoped by message class, so an authorization and a reversal reusing a trace number are no longer indistinguishable.- Scenarios can name what a diagram cannot derive. A Rack's
rolelabel reaches its description, and two gear labels,peerandpeer_played_by, say who is on the far side of a socket and whether anything is standing in for it. iso8583-tool:-scheme-move. The host simulator can report a request field back in another, so a host receiving a private field can show which value arrived. It reports into a different field deliberately, and pads to the destination's declared width.- Enriching an authorization from outside the message. A use case on the GSMA Open Gateway APIs in payments, and a tutorial building one end to end: an operator call under a hard deadline, four named reasons for having no signal, and the degradation paths, all as configuration.
Fixed
- Nested field paths silently stopped resolving after a bus hop.
GetValuedescended only intomap[string]any, but CBOR decodes a nested object asmap[any]any. A correlation key built from an ISO 8583 field therefore worked in a single-gear pipeline and returned "field missing" in any real deployment, with nothing logged. - The
bentogear injected a memory buffer over a config that declared its own input. A buffer acknowledges the input before the pipeline has produced anything, so a synchronous responder answered with an empty body and no error anywhere. The injection now happens only when the gear supplies the input itself. - A
bentogear in a relay path dropped the wire bytes.RawPayloadsurvived only when the structured view was empty, so any gear that merely read fields destroyed the payload a downstream io gear had to write. It now travels across the bridge. fluxrig scenario vizdrew both ends of one socket as strangers. Every I/O gear produced its own external box, so a client and the server it dials appeared as two unrelated outsiders. When both ends are in the scenario they are now one relationship.
[v0.8.0] - 2026-08-24
The EMV release: fluxrig parses BER-TLV composite fields, and carries the tags it does not model through untouched.
Added
- BER-TLV composite parsing: a field declared
structure: tlv, such as ICC data in DE 55, is parsed into its EMV tags. Tags the spec does not declare are retained rather than discarded and re-emitted on encode, which is what forwarding to a scheme depends on, and are exposed to downstream gears underiso8583.unknown_tags. Validated by a round trip across a serialization boundary and by a Robot suite against a running Rack.- Tag order is canonical rather than preserved: tags are re-emitted sorted, so every value survives but the byte layout of a field may differ from the one that arrived.
Changed
- Binary field values cross the bus as bytes: a field whose value is not valid UTF-8, such as chip data, PIN blocks or MACs, is placed on the
fluxMsgas bytes rather than as a string, including when reached through analiasor as a composite subfield. Gears and pipelines reading such a field now receive[]bytewhere they received astring. Serialization requires it: a Go string holding binary is not valid CBOR text, so a spec declaring a binary field previously lost the message at the first rack boundary.
Fixed
- The bus no longer drops undecodable messages silently: a message that cannot be decoded is logged with its subject and the reason, instead of being discarded without trace.
[v0.7.1] - 2026-08-10
Fixed
- ISO 8583 TLV length hardening: a crafted BER-TLV long-form length in a composite field (for example ICC data in DE 55) could wrap to a negative value, bypass the bounds check and crash the codec while skipping the unknown tag. Length decoding now rejects unsupported long forms, out-of-range values, invalid BCD length bytes and non-numeric ASCII lengths, so malformed input is reported as an error instead of failing the message.
v0.7.0 - 2026-08-01
The payment-switch release: the Conductor transaction switch, a manifest system that makes every gear self-describing, and native TLS on the ISO 8583 I/O path.
Added
- Conductor gear (transaction switch): routes each request across a destination tree of strategy nodes (
failover,round_robin,least_loaded) whose leaves are output ports, correlates the reply under a ticket, and surfaces timeouts on a dedicatederrorport. Availability sensing binds each local destination to its uplink link-state. Validated end-to-end by thepayment_switche2e and the Conductor stress and chaos Robot suites. - Valet correlation engine: the local-by-default ticket store behind the Conductor's reply matching, with per-ticket TTLs and idempotent redemption.
- Cross-Conductor handoff: a request can exit one Conductor and its reply return through another, routed by an in-band origin stamp, so active/active multi-region topologies need no shared session state.
- Named multi-port gear I/O: gears declare multiple named input/output ports; the Bento gear honors every declared output port and fails loudly on an ambiguous multi-output config.
- Gear manifests: every gear publishes a manifest (identity, ports, config JSON Schema, terminus). The runtime validates a gear's config against its schema at activation, the Mixer API serves the manifest catalog, and
fluxrig gears docgenerates the gear reference documentation from it. - Native TLS / mTLS on
io_iso8583, plus connection link-state signals (conn.up/conn.down) on the control plane that drive Conductor availability sensing. fluxrig scenario viz: generates an interactive LikeC4 topology model (zones, racks, gears, sockets, the Snake) from a scenario file.- Lean Rack build:
-tags nobentocompiles a Rack without the Bento gear for minimal-footprint deployments.
Changed
- Port addressing: port names are dot-free and wires address the fully-qualified
rack.gear.port, so a wire endpoint is unambiguous across a multi-rack topology.
Fixed
- Reply-correlation timeout under load: JetStream deduplication is now keyed per subject, fixing a Conductor timeout where distinct requests collided on the dedup key.
- Rack stability: panics on the gear
emitpath are recovered and nil emits dropped, so a misbehaving source gear can no longer crash the Rack. - Conductor field resolution: correlation, match, and park fields resolve as dotted paths (e.g.
iso8583.field.11) consistently. - Loud topology validation: scenario topology inconsistencies now fail at load instead of surfacing later as runtime errors.
- Gear schema completeness: the
io_tcpandbentoconfig schemas now declare every field the gears actually accept (previously undocumented options such asio_tcpdelimiter framing andbentolog_level).
Phase 3: open & flexible logic
| Version | Date | Status | Summary |
|---|---|---|---|
| v0.6.1 | 2026-07-20 | Delivered | Wasm runtime, supply chain security, polyglot gears |
| v0.6.0 | 2026-06-06 | Delivered | Release metadata only, no code changes |
| v0.5.0 | 2026-05-07 | Delivered | Sovereign identity (UUID v7) & telemetry hardening |
| v0.4.5 | 2026-04-29 | Delivered | Documentation Hardening & Zero-Config |
| v0.4.4 | 2026-04-23 | Delivered | Logic Extensibility & Secure Enrollment |
| v0.4.3 | 2026-02-19 | Delivered | Operational Resilience & NATS V2 |
| v0.4.2 | 2026-02-15 | Delivered | Spec Management & E2E Automation |
| v0.4.1 | 2026-02-09 | Delivered | Stateless Context & I/O Decoupling |
| v0.4.0 | 2026-02-01 | Delivered | ISO8583 Native Gear & Telemetry QoS |
| v0.3.0 | 2026-01-08 | Delivered | Bento Integration & Load Testing |
v0.6.1 - 2026-07-20
Added
- Wazero Integration: Implemented a secure, native Wasm execution environment using
wazero. - Wasm Supply Chain Security: Embedded Ed25519 signatures within
.wasmmodules with Mixer-level trust roots and countersignature enforcement prior to Rack execution. - Dynamic Catalog Distribution: Added NATS Snake hot-loading for edge distribution of Wasm logic.
- PKI & Catalog CLI: Introduced
fluxrig keys gen-cluster,fluxrig wasm sign, andfluxrig wasm importcommands. - Path Sanitization: Added
pkg/utils/pathto centralize traversal-safe path handling.
v0.6.0 - 2026-06-06
Changed
- Release metadata only. This tag contains no source changes relative to
v0.5.0; the Wasm work intended for it was not merged and shipped inv0.6.1instead.
v0.5.0 - 2026-05-07
Changed
- Sovereign Identity Plane (v0.5.0 Foundation): Migrated the entire platform identity system to 128-bit UUID v7 (RFC 9562). This enhances entropy, ensures global uniqueness without centralized coordination, and provides time-ordered sequence integrity for high-performance storage indexes.
- Deduplication Logic: Updated NATS JetStream deduplication to utilize 128-bit identifiers, ensuring consistent exactly-once delivery across complex telemetry pipelines.
- Telemetry Hardening: Standardized the dotted metric naming schema (e.g.,
flux.gear.messages_in) across OTel, Prometheus, and DuckDB. - Directional Monitoring: Split unified I/O counters into distinct Inbound and Outbound channels for precise protocol translation metrics.
- Resource Guardrails: Implemented mandatory
MaxHops(64) andMaxPayloadSize(2MB) validation influxmsgto prevent bus exhaustion and "poison pill" scenarios. - Concurrency Resilience: Integrated global
PanicMiddlewareto ensure Rack stability during individual Gear failures and hardened mutex locking for atomic hot-reloads. - Mixer Reliability: Replaced fragile telemetry discovery with a robust recursive traversal engine, ensuring full visibility of historical Parquet data via the API.
- Security Hardening (CodeQL Certification):
- Fixed high-severity path traversal in scenario management by implementing robust name sanitization.
- Hardened TLS configuration in the
snakeserver with CA-based client verification support. - Resolved integer overflow/truncation risks in telemetry ingestion and ISO8583 codecs.
- Upgraded core dependencies (NATS Server v2.14, NATS Go v1.52) to address multiple upstream vulnerabilities.
CAUTION
DESTRUCTIVE CHANGE: This migration is a hard architectural break.
- Storage: Existing DuckDB databases (V3 and below) and cached
.fluxstate files are incompatible with this version. - API: REST handlers and NATS topics have transitioned from decimal integer IDs to standard UUID string representations.
v0.4.5 - 2026-04-29
Added
- Zero-Config Getting Started: Global Gears (a gear with no
deploytarget runs on every connected Rack), enabling scenarios that work without knowing Rack names in advance.
v0.4.4 - 2026-04-23
Added
- Enrollment Architecture: Implemented configuration-driven rack adoption with secure nonce-based passports.
- CBOR Migration: Transitioned internal wire-format to deterministic CBOR for binary stability.
- Data-Plane Integrity: Enforced technical UTF-8 validation and hex-encoded binary metadata handling.
- IO Stabilization: Implemented robust connection polling and rate-limited background WAL replay.
v0.4.3 - 2026-02-19
Added
- Documentation Website: Docusaurus-based documentation site with diagram support and full-text search.
v0.4.2 - 2026-02-15
Added
- Spec & Scenario Manager: CAS-backed spec/scenario management with CLI (
fluxrig spec,fluxrig scenario) and API integration. - E2E Test Suite: Comprehensive test runner for spec lifecycle, API scenarios, and concurrent access.
v0.4.1 - 2026-02-09
Added
- Coat Check Pattern: Implemented architectural pattern to handle "Detached State" during connection handovers.
- Bus KV: Implemented the
Bus.KV()key-value interface with a NATS backend, backing the Coat Check ticket store.
Changed
- IO Refactor: Decoupled TCP connection management from protocol logic.
- Gear Rename:
simple_tcp→io_tcp(renamed as part of the IO refactor above).
v0.4.0 - 2026-02-01
Added
- ISO8583 Native Gear (Alpha): First release of the high-performance payment switch gear.
- Telemetry Governor: Introduced QoS constraints for telemetry ingress to protect business traffic.
v0.3.0 - 2026-01-08
Added
- Bento Integration: Native support for the
warpstreamlabs/bentoecosystem, enabling the Bento connector ecosystem. The standard binary ships the Pure Logic and Local I/O sets; institutional connectors (Kafka, SQL, AWS) require a custom build. - Load Testing Suite: Integrated
e2e_loadcapabilities for stress testing.
Phase 2: core runtime
| Version | Date | Status | Summary |
|---|---|---|---|
| v0.2.0 | 2026-01-05 | Delivered | Observability Stack & TLS Foundations |
v0.2.0 - 2026-01-05
Added
- Observability Stack: Full OTel integration (Metrics, Traces) with DuckDB backend.
- Configuration V2: Unified TOML-based configuration schema.
- TLS Support: Enabled mutual TLS for internal bus and HTTPS for management API.
Phase 1: architecture & foundation
| Version | Date | Status | Summary |
|---|---|---|---|
| v0.1.0 | 2025-12-27 | Delivered | Initial engine architecture and Snake Protocol |
v0.1.0 - 2025-12-27
Added
- Foundation: Initial release of the 4-Repo Architecture.
- Snake Protocol: Secure tunneling implementation for Rack-to-Mixer connectivity.
- FluxMsg: Canonical JSON schema for inter-gear communication.