On this page

Every faultbox test run emits a single .fb archive capturing everything needed to re-run it later: the trace, the environment, per-service logs, a copy of the .star source tree, and a one-liner that reproduces the run. Bundles exist so a failure found on Monday can be re-run by a colleague on Tuesday — without reconstructing the environment from conversation history.

Introduced in v0.9.7 (RFC-025). The bundle is the input contract for faultbox replay (v0.10.0) and faultbox report (v0.11.0) — every downstream tool reads one .fb and nothing else.

Quick start

# Run tests → bundle is emitted automatically in the cwd.
faultbox test faultbox.star
# → Bundle: run-2026-04-22T15-03-11-42.fb

# Inspect what's inside.
faultbox inspect run-2026-04-22T15-03-11-42.fb

# Dump one file to stdout (pipe to jq, less, etc.).
faultbox inspect run-*.fb manifest.json | jq '.summary'

# Extract everything into a directory.
faultbox inspect run-*.fb --extract ./unpacked/

Flags on faultbox test

FlagEffect
(default)Emit run-<ts>-<seed>.fb in cwd
--bundle=<path>Write the bundle to a specific path
--no-bundleSkip bundle emission entirely (rare; CI opt-out)
$FAULTBOX_BUNDLE_DIREnvironment override — bundles go in this dir

Precedence: --bundle > $FAULTBOX_BUNDLE_DIR > cwd.

Archive layout

A .fb file is a tar.gz. The writer emits files in a predictable order so tar -tf run.fb users see the important ones up front.

run-2026-04-22T15-03-11-42.fb  (tar.gz)
├── manifest.json       # schema version + run summary
├── env.json            # host fingerprint (OS, kernel, Docker, …)
├── trace.json          # full event log — same shape as --output
├── replay.sh           # one-liner; `faultbox replay <this-bundle>`
└── spec/               # user .star tree snapshot
    ├── faultbox.star
    └── helpers/…

manifest.json

Top-level summary. Consumers should read this first.

{
  "schema_version": 1,
  "faultbox_version": "0.9.7",
  "run_id": "8ebbad2351b0c7accb6aa1ee8ce1aca8",
  "created_at": "2026-04-22T15:03:11Z",
  "seed": 42,
  "spec_root": "faultbox.star",
  "tests": [
    {"name": "test_happy", "outcome": "passed", "duration_ms": 12},
    {"name": "test_fault", "outcome": "failed", "duration_ms": 204}
  ],
  "summary": {"total": 2, "passed": 1, "failed": 1, "errored": 0}
}

schema_version evolution rules:

  • Additive field changes (new optional keys) do not bump it.
  • Layout changes (new top-level files, renames) do bump.
  • Tools refuse bundles with an unknown schema_version rather than silently mis-parse.

env.json

Everything the runtime could determine about the host. Every field is best-effort; fields it couldn’t resolve are omitted, not nulled.

{
  "faultbox_version": "0.9.7",
  "host_os": "linux",
  "host_arch": "arm64",
  "kernel": "6.8.0-49-generic",
  "go_toolchain": "go1.26.1",
  "docker_version": "27.3.1",
  "runtime_hints": ["lima"]
}

trace.json

Identical to today’s --output trace.json — the full event log with vector clocks, per-test syscall summaries, and diagnostics. Embedded in the bundle so everything needed for a report lives in one file.

replay.sh

A tiny POSIX script that re-runs the bundle:

#!/usr/bin/env sh
# Generated by faultbox 0.9.7 at 2026-04-22T15:03:11Z
DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
exec faultbox replay "$DIR/run-2026-04-22T15-03-11-42.fb" "$@"

Pass --test <name> to re-run a single test.

spec/

A snapshot of every local .star file the Starlark runtime loaded: the root spec plus every file pulled in via load("./helpers/…"). Paths preserve the tree structure relative to the root’s directory, so faultbox replay can rehydrate the run against the exact source that produced it.

@faultbox/… stdlib loads are NOT captured — they’re part of the consuming binary already, so re-archiving them would bloat bundles without adding reproducibility value.

Version compatibility

manifest.faultbox_version records which Faultbox binary produced the bundle. Different consumers apply the field differently:

ConsumerSame X.Y.ZMinor/patch driftMajor drift
faultbox inspectsilentwarn, proceedwarn, proceed
faultbox replay (v0.10.0)silentwarn, proceedrefuse
faultbox report (v0.11.0)silentwarn in header, renderwarn in header, render

Rationale: major bumps are deliberate breaking changes; re-running a pre-1.0 bundle on 1.x would silently change semantics. Minor/patch drifts are tolerated because Faultbox doesn’t yet ship a version-switcher — users would otherwise be stranded if they lacked the exact producing version.

The warning message names the exact version needed for byte-identical replay so, when a version-switcher does ship, the guidance turns from informational into actionable.

Observability paired with bundles

Every failed test prints a replay hint at the end of the terminal session:

Replay: faultbox replay run-2026-04-22T15-03-11-42.fb --test test_fault --seed 42

Every fault_zero_traffic event (rule installed but matched no syscalls) also surfaces at session end:

Zero-traffic faults (1): rule installed, matched no syscalls
  test_fault — db.connect (deny)
  Hint: the scenario may not be exercising the upstream during the fault window.

Both were previously visible only inside trace.json. Users writing fault_matrix tests now see them directly.

Checking bundles into git

Bundles are useful as regression evidence — “here’s the failure I found, check if v0.9.8 still reproduces it.” A common pattern:

# .gitignore
*.fb
!regressions/*.fb

This ignores everyday bundles while allowing a curated regressions/ directory with named golden bundles to ride in the repo.

Security note

Bundles contain:

  • Resolved .star source under spec/
  • Captured stdout/stderr of every service (Phase 1.5)
  • Environment-variable values the test passed in

Treat bundles with the same care as service logs — they carry whatever secrets were in the test environment. The bundle emitter has no redaction logic; that’s the caller’s responsibility when running against production-like configs.

See also