On this page

Releases

Faultbox release history. Every tagged version ships with full release notes on GitHub and a matching entry in CHANGELOG.md.

For the next version in flight, see the Issues board filtered by version label (v0.12.x, etc.).

Current

  • v0.13.0 — 2026-05-29 — Five RFCs ship together as one coordinated epic: determinism levels (RFC-040), temporal properties (RFC-041), exploration plan (RFC-042), non-deterministic operators (RFC-043), and spec language simplification (RFC-044). The new determinism() top-level builtin declares the spec’s reproducibility contract — defaults to L1 (mediated-event determinism) with strict mode on, so any unmediated I/O (clock reads, RNG, DNS to a non-Faultbox resolver, connect() to an undeclared address) fails the test at the first untolerated leak. RFC-041 adds five temporal primitives — eventually(p), always(p, between=), await_event(matcher), await_stable(quiescence_window=), and a rewritten monitor(name, on=, state_init=, update=, check=) — plus a declarative test(name, body=, expect=, timeout=, terminate_when=) builtin and the PASS/FAIL/INCONCLUSIVE three-valued verdict. RFC-042 introduces faultbox plan (static plan-tree analysis without launching services), plan.json in every bundle, the report’s Plan tab, --coverage / --suggest / --check-cost --max-instances N, and the body-re-execution engine that turns named choose("name", [opts]) axes, syscall-level probability fan-out (max_fires=/mode="exhaustive"), and parallel(..., interleavings=) orderings into multi-leaf test executions with stable LeafID attribution flowing through TestResult → bundle manifest → HTML report. RFC-043 ships the four operators (choose, nondet, halt, assume) with per-leaf assume= evaluation and an AST denylist sandbox. RFC-044 withdraws RFC-013 (param() superseded by choose()) and RFC-002 (domain()service()/interface() proved sufficient); unifies the three plan-tree fan-out axis kinds under one NonDeterministicChoice interface; collapses the event-source and decoder surfaces under observe.stdout/observe.stderr and decoder("name", ...); deprecates faultbox generate in favor of faultbox plan --suggest. Two new tutorial chapters (Part 4 — Safety & Verification) walk the operator and fan-out vocabulary end-to-end. Full repo go test -race ./... green; Lima sweep 21/21 PASS across the same 6 integration spec suites as v0.12.29.

v0.12.x — TLS-aware proxy

  • v0.12.29 — 2026-05-02 — Remote services (RFC-036). New service(remote=...) kwarg points Faultbox at an externally-running endpoint — typically a real pod in a customer’s k8s dev cluster — without launching a process. The proxy datapath from RFC-024 dials the remote upstream and the SUT reaches it through the proxy unchanged, so every protocol-level fault (response(), error(), slow(), gRPC method targeting, SQL matchers) keeps working. Process-level kwargs (seed=, reset=, reuse=, volumes=, ports=, args=, seccomp=, observe=, ops=) and syscall-level faults are rejected at spec load with explicit error messages naming the offending kwarg and pointing at protocol faults or mock_service(). Composes with RFC-038 tls=tls_cert(...) for TLS-required upstreams (the auto-generated proxy cert covers 127.0.0.1 so SUT-side verification works against the env-rewritten loopback addr). New typed remotes({"iface": "host:port"}) value for services whose interfaces live on different hosts. New @faultbox/discovery/k8s.star stdlib helper exposing k8s.service, k8s.endpoint, and k8s.local — pure string sugar over <name>.<namespace>.svc.cluster.local, no runtime k8s client. The .fb bundle’s env.json records every (service, interface, host, protocol) tuple from a remote-using run; faultbox replay warns when replaying such a bundle and points at RFC-037 (the open companion design RFC for the offline-replay determinism story). Cluster connectivity is the user’s responsibility — Telepresence connect, kubectl port-forward, in-cluster execution, or VPN — documented in the new Connectivity guide. 49 new tests across spec-load validation (32), runtime/proxy lifecycle (10 incl. TLS×remote interop), bundle round-trip (2), replay warning (2), and string-grep doc gates (3). Full repo go test ./... green; go vet ./... clean; make demo-container Lima smoke 4/4 PASS (proxy datapath refactor confirmed non-regressive against the seccomp + Postgres + Redis path).

  • v0.12.28 — 2026-05-02 — TLS-aware proxy (RFC-038) + proxy traffic observability (RFC-034) + container fault paths (RFC-035). Twelve patch versions consolidated into one release; the per-version detail lives in CHANGELOG.md. Headline: declare interface(..., tls=tls_cert(...)) on a service interface and the proxy terminates TLS at its listener and re-establishes TLS dialing the upstream — all protocol-aware fault rules (http.error(path=...), grpc.error(method=...), kafka.drop(topic=...), redis.error(key=...)) keep firing on the plaintext between the two TLS legs. Six plugins ship migrated this release (http, http2, gRPC, Kafka, Redis, TCP); the remaining 8 (postgres, mysql, mongodb, cassandra, clickhouse, memcached, nats, amqp) are tracked in RFC-039 — declarations against unmigrated plugins emit a proxy_tls_pending event. The tls_cert(...) builtin is kwargs-only with full spec-load validation (cert/key pairing, file existence, CA PEM parse, insecure=True + ca= exclusion); empty tls_cert() auto-generates a self-signed proxy cert in memory for dev/test. Two TLS plumbing patterns landed across the 6 plugins: listener wrap-and-dial via proxy.ListenTLS(serverCfg) + proxy.Dial(ctx, target, clientCfg) (http, http2, kafka, redis, tcp) and framework credentials via grpc.Creds(credentials.NewTLS(...)) for gRPC (whose server owns its own TLS handshake). Also in this release: RFC-034 connection lifecycle observability — proxy_conn_open, proxy_conn_close with byte counts and reason classification, proxy_handshake_complete, and proxy_stall (1Hz watchdog, 5s warn / 30s extend tiers) — wired into 13 of 15 plugins (udp/grpc deferred). RFC-035 container-consumer fault paths on Linux Docker (proxy bind defaults to 0.0.0.0 so container consumers reach proxies via host.docker.internal). New stderr() event source. Container-mode observe=[stdout(...)] now works for container services (was binary-mode only). Race fix on tcp.go::handle — both io.Copy goroutines were writing closeReason concurrently. New internal/proxy/{http,grpc,kafka,redis,tcp}_tls_test.go suites (~30 tests). Full repo go test ./... -race green; Lima sweep 21/21 PASS across 6 integration spec suites.

v0.12.x — Scalable HTML Reports

  • v0.12.16 — 2026-04-30 — Report UX overhaul. Driven by inDrive Freight triage feedback on the v0.12.15.x customer report; entirely scoped to internal/report and the docs that describe it (no bundle format or spec-language changes). Causal links now follow cause, not chronology — findCausalAncestors switched from vector-clock partial order (which on real bundles routinely had only the lifecycle events with complete clocks, so spaghetti pointed at service_ready instead of proxy_fault_applied) to seq-based strict precedence, restricted to faults / violations / errored steps. Hovering an ordinary success step now draws zero lines. New timeline filter bar above every Event Trace block: three presets (Compact default, hides framework lifecycle chatter; Anchors only strips everything except cause-relevant events; All events historical default) plus free-text search across event type / headline / fields. proxy_fault_applied / proxy_fault_removed are now first-class fault markers (red, not default-blue) across markerKind/severityScore/isAnchorEvent/eventHeadline; added to Phase 3 anchorTypes so they survive downsampling. Per-test “Faults applied” section pairs proxy_fault_applied with proxy_fault_removed (one row per assumption: service · protocol · interface · assumption · seq window). Recent block in the Assertion drill-down interleaves fault events between captured step rows by seq, with a fade-and-expand cap (220px max-height + mask-image gradient + Show full assertion toggle, 320ms transition) so long Recent lists / Actual reprs stop dominating the dialog. Group-members table on folded markers (paginated 100/page, sticky header, scrollable) replaces the one-line “collapsed run” hint — runs that hide a 5xx among 99 successes are now legible. Fullscreen toggle on the test details modal (⤢ ↔ ⤡). STDOUT JSON renders as a 2-column key/value table with dot-path flattening for nested objects. Source block falls back to fault_matrix(...) for matrix-generated test names and surfaces three jump links (scenario def get_order_feed(), fault mysql_slow = fault_assumption(...), matrix call site) — was previously “Could not locate def…” for every matrix cell. Plus tooltip vertical-text fix (width:max-content + four-side viewport clamping), detail panel summary no longer truncates, folded marker click routes through markerEvBySeq so the Group-members table actually appears.

  • v0.12.15.2 — 2026-04-30 — Hotfix on top of v0.12.15.1. Customer verified the redis RESP3 fix landed clean (cold-start path green end-to-end, smoke PASS in 16.3 s) but the failure moved to the reuse path: cell 1 of the dbmatrix run passes, cells 2–18 all fail identically with error connect to db: invalid connection (go-sql-driver ErrBadConn) or read: connection reset by peer (go-redis). Root cause: Manager.EnsureProxy rooted each proxy’s Accept goroutine at the caller’s ctx. preStartProxies runs under RunTest’s per-test testCtx which cancels via defer cancel() at end of test — at end of cell 1 that cancellation took down the goroutine while the listener fd stayed bound (only Stop() closes it) and the cached m.proxies[key] entry stayed in place. Cells 2..N hit EnsureProxy → cache hit → proxy_active(reused) fired → but nobody was Accept()-ing, so the kernel completed the TCP handshake and then RST-ed. v0.12.15.2 roots the proxy’s pCtx at context.Background() so its lifetime is bound to Manager.StopAll/StopService (which already drive explicit teardown). Why this surfaced now: pre-v0.12.13 no-seccomp containers were destroyed every cell, forcing fresh proxies via the cold path; v0.12.13 fixed reuse so containers AND proxies stay alive across cells, exposing the latent ctx-rooting bug. New regression test TestManagerEnsureProxy_SurvivesCallerCtxCancel. Lima sweep 21/21 PASS.

  • v0.12.15.1 — 2026-04-29 — Hotfix on top of v0.12.15. Customer verified the MySQL fix landed clean (Finding H closed) but the failure moved one step forward: truck-api hung 6s on its first Redis Ping(). Root cause: go-redis v9 unconditionally sends HELLO 3 from initConn, which switches the server to RESP3; v0.12.15’s redis proxy readRESPRaw only knew RESP2 framing (+, -, :, $, *) and on a %N map header fell through to the default branch — returned just the header line and left the map body unread on the upstream socket. Wire-level proof: redis-cli -p $PROXY -3 PING timed out 6s, redis-cli -p 16379 -3 PING (direct) returned PONG in 8ms. v0.12.15.1 extends readRESPRaw to cover RESP3 aggregates (% map, ~ set, > push, | attribute) and scalars (_ # , ( single-line; = ! bulk-string-framed). Four new regression tests including TestRedisProxy_RESP3_HelloMap reproducing the customer’s exact map shape.

  • v0.12.15 — 2026-04-29 — Hotfix on top of v0.12.14. Customer verified v0.12.14 didn’t unblock Finding H — both caching_sha2_password and mysql_native_password --default-auth still hung 8s through the proxy. Root cause: v0.12.14’s handshake loop assumed strict client/server alternation, but caching_sha2_password fast-auth-success (taken when the user is in the server’s auth cache) emits two server-side packets back-to-back — AuthMoreData(0x01, 0x03) then OK(0x00) — with no client packet between. The proxy read the AuthMoreData, tried to read from the client, deadlocked. Customer’s seed_db populated the auth cache via direct MySQL connections, so every proxy connection hit fast-auth. v0.12.15 peeks the second byte of every AuthMoreData and treats 0x03 (fast_auth_success) as “expect another server packet” rather than “expect client reply”. New regression test guards the path.

  • v0.12.14 — 2026-04-29 — First attempt at Finding H. Loops the handshake until OK/ERR, alternating directions on AuthMoreData/AuthSwitchRequest. Fixed caching_sha2_password cold-cache full-auth (covered by TestMySQLProxy_Handshake_CachingSha2FullAuth), but missed fast-auth-success (back-to-back server packets) — superseded by v0.12.15 the same day. Also bumps step.summary preview cap from 80 → 500 chars.

  • v0.12.13 — 2026-04-28 — Hotfix on top of v0.12.12. Pre-existing bug (RFC-015 vintage): container services without seccomp filters bypassed rt.sessions registration, so stopServicesreused set silently ignored reuse=True for proxy-only Docker upstreams — container destroyed every cell, but the proxy in proxyMgr was kept pointing at the dead host port. Fix populates rt.sessions in the no-seccomp branch and nil-guards ClearDynamicFaultRules in the reuse path.

  • v0.12.12 — 2026-04-27 — Proxy-address surface for host-binary SUT + Docker upstream (RFC-033). New iface.proxy_addr / proxy_host / proxy_port interface attributes give a working spec-language path for wiring host-binary SUTs through the fault-injection proxy — late-bound at spec-load, resolved at buildEnv time, no rsplit() games. Also emits proxy_active events in the reuse=True path so per-cell trace partitions reflect what’s wired up at cell start.

  • v0.12.11 — 2026-04-26 — Compact fold-count labels. Run-marker badges now render counts as × 3.9k / × 86k / × 4M instead of full numerals; the exact count remains in the badge’s hover tooltip. Truncates rather than rounds — × 3.9k always represents ≥ 3900 events.

  • v0.12.10 — 2026-04-26 — Spec-anchored event highlighting. The runtime tags step_send / step_recv events with fields.spec = <test_name> whenever the call originates from inside the currently-running test function (helper functions still register — the test frame is on the stack). Renderer paints these markers with a warm gold ring, prefixes the balloon / log headline with , bumps severity by +50 so they win their slot, and bypasses the lane fold so the user’s own calls always render individually against background traffic.

  • v0.12.9 — 2026-04-26 — Three UX polishes. Run-marker discs scale with log10(fold count) — magnitude is visible at-a-glance even when adjacent chips’ badges would otherwise overlap (count text now sits inside the disc). Drill-down “All fields” / “Vector clock” expansion state persists across pin changes. Step summaries pair the directional arrow with explicit call / reply words — → call · truck-api.get /orders, ← reply · truck-api.get /orders [500].

  • v0.12.8 — 2026-04-26 — Lane filter now folds by key (target.method.summary) before slot bucketing — 1787 identical SELECT 1 errors collapse to a single × 1787 chip instead of 50 indistinguishable red dots. Causal hover lines restored for v0.12.7’s lane routing (cross-lane detection uses laneFor; folded ancestors resolve to their containing chip via _runMembers). Type filter axis becomes click-to-add — the toolbar stays empty until the user clicks a Type cell in the table.

  • v0.12.7 — 2026-04-25 — Step events now lane on their target service: db.exec(...) lands on the db lane, truck-api.get(...) on the truck-api lane, instead of all of them piling onto the test driver lane. Event-log filter applies to the full event set (not just the first 200 loaded rows), so filtering by a service finds matches anywhere in the trace.

  • v0.12.6 — 2026-04-25 — Lane markers color by severity (failed steps + 5xx → red, 4xx → amber); slot picker prefers severity over first-anchor; Recent trail ellipsizes long lines with hover-tooltip; two-axis event-log filter (Service + Type) replaces the v0.11 single-select chip bar — click a cell in the table to filter to its value.

  • v0.12.5 — 2026-04-25 — Hard per-lane marker budget. Walks back the v0.12.2-4 dedup/window approaches (none had an upper bound on DOM node count). New filter buckets each lane’s events into 50 visual slots in seq order; each slot picks one representative (anchor > fold-key head > first event). Hard guarantee: ≤ 50 markers per lane regardless of input size — the customer’s 86874-event lane now renders 50 markers (≈ 250× DOM reduction) at uniformly-spaced visual positions.

  • v0.12.4 — 2026-04-25 — Lane filter rewritten as anchor windows + global cardinality fold (faults / violations / errored steps + ±10 around each render per-event; outside groups by (target, method, summary) and folds large buckets to a × N chip at the median rank). Customer’s noisy 80k-event test now shows ~5 distinct chips. Assertion drill-down gains a “Recent” trail snapshotting the last few step events at fail time so resp.status = 500 is visible inline.

  • v0.12.3 — 2026-04-25 — Drill-down ergonomics. Assertion block now lifts the original expression text from the spec source (assert_true(resp.status in [200, 201]) shows Expression: resp.status in [200, 201], not just Actual: False), with a clickable spec.star:42 location link. Lane dedup also keys on summary so mixed SQL doesn’t flatten into one chip. Click on a lane marker no longer scrolls the page.

  • v0.12.2 — 2026-04-25 — Step-event readability. Runtime enriches step_send/step_recv with sql/query/path/args/status_code/duration_ms/error plus a one-line summary preview; lane dedups consecutive (target, method) runs into a single × N marker (a 1500-iteration db.exec loop renders one chip instead of 3000). FAQ entry added on bundle freezing — old bundles can’t invent new fields; re-run the suite on v0.12.2 to benefit.

  • v0.12.1 — 2026-04-25 — Drill-down polish: structured assert_eq / assert_true Expected vs Actual block, services list now shown for proxy-mode runs (event-log fallback), swim-lane switched to rank-based axis with syscalls relegated to the event-log table — keeps timelines legible at 80k+ events.

  • v0.12.0 — 2026-04-25 — Report architecture redesign (RFC-031). 23 MB reports become ~150 KB by default; --full-events opt-out preserves every event. Plus panic-safe bundles, binary-digest pinning, actionable lock drift, grpc.retryable(), proxy-coverage CI gate, positioning doc.

v0.11.x — Interactive HTML Reports

  • v0.11.3 — 2026-04-25 — MySQL driver EOF noise suppressed, CHANGELOG + per-release pages land.
  • v0.11.2 — 2026-04-24 — Hotfix: gRPC proxy passthrough + fault_matrix mock-target panic. --test glob/regex. Capability matrix in README.
  • v0.11.1 — 2026-04-24 — Five-outcome matrix: expectation_violated (amber), fault_bypassed (grey, opt-in via require_faults_fire).
  • v0.11.0 — 2026-04-24 — Interactive single-file HTML reports. faultbox report <bundle.fb>. Swim-lane trace viewer.

v0.10.x — Reproducibility trio completes

  • v0.10.1 — 2026-04-23 — Assumption ProxyRules applied in fault_scenario/fault_matrix. testops corpus: Critical tier 100% green.
  • v0.10.0 — 2026-04-23 — faultbox replay <bundle>, faultbox lock + faultbox.lock (image-digest pinning, RFC-030).

v0.9.x — Reproducibility, docs, primitives

  • v0.9.9 — 2026-04-23 — JWT/JWKS mock, documentation overhaul (~1500 lines, 6 new pages).
  • v0.9.8 — 2026-04-23 — load_file()/load_yaml()/load_json(), expect_* predicates, gRPC status shorthands.
  • v0.9.7 — 2026-04-22 — .fb bundle format (RFC-025), faultbox inspect, always-on reproducibility.

Older

See the complete CHANGELOG for entries prior to v0.9.7 and the GitHub Releases page for the canonical per-version notes.