ITF is an Elixir library for decoding and inspecting traces emitted by Apalache. It is tested against Apalache 0.58.3.

ITF only consumes .itf.json data. It does not execute Apalache, implement Victoria semantics, replay traces, or encode ITF.

Installation

Add itf to mix.exs:

{:itf, "~> 0.1.0"}

Usage

Load a trace from disk:

{:ok, trace} = ITF.load("counter.itf.json")
trace.vars
trace.states
trace.loop_index

Or decode an existing JSON binary:

{:ok, trace} = ITF.decode(json)

Both functions accept max_bytes: and max_depth: limits. The defaults are 256 MiB and 256 semantic expression levels; use :infinity explicitly to disable either limit. Invalid ITF returns a source-aware, path-aware ITF.Error. Invalid arguments or options raise ArgumentError.

Primitive values use native Elixir booleans, strings, and integers. Sequences are lists and records are maps. Ambiguous ITF forms stay distinct:

case value do
  %ITF.Set{values: values} -> {:set, values}
  %ITF.Map{entries: entries} -> {:map, entries}
  %ITF.Variant{tag: tag, value: payload} -> {:variant, tag, payload}
end

Tuples use ITF.Tuple and unserializable values use ITF.Unserializable. Set elements and map entries retain emitted order for inspection, but that order has no semantic meaning. Metadata and unknown trace/state extensions are preserved as raw JSON and are never expression-decoded.

The Rust code under test/oracle/ pins itf-rs 0.4.0 and is used only as an independent development/CI oracle for the shared subset. No Rust, Apalache execution code, fixtures, or tests are included in the Hex package.

Development

Install asdf 0.16.5 first. The root .tool-versions file is the authority for the exact versions of all project runtimes and command-line tools. On a new machine, bootstrap just once, then let the public setup recipe install the complete toolchain through asdf:

asdf plugin add just https://github.com/olofvndrhr/asdf-just.git
asdf install just
asdf exec just setup

Mix owns Hex and the dependencies locked in mix.lock; Cargo owns the oracle crates locked in test/oracle/itf_rs/Cargo.lock. The setup recipe does not replace either ecosystem's dependency installation.

just setup
just doctor
just deps
just check
just docs
just package-audit
just consumer-smoke
just test-oracle
just test-apalache

Ordinary mix test uses committed fixtures and requires neither Rust nor Apalache. just setup is the only toolchain-mutating workflow. The oracle and real-Apalache recipes are intentionally separate evidence lanes.

CI consumes the same version authority through specialized, commit-pinned Beam and Java setup actions. Its minimum lane is intentionally explicit at Elixir 1.18.4 and OTP 27.0 rather than reading the current Beam versions from .tool-versions. CI uses asdf only for just, Apalache, and Rust, then invokes the same public Justfile recipes used locally. Mix continues to own Hex and Elixir dependencies, and Cargo continues to own the Rust oracle dependencies.

Maintainer release

From a clean, synchronized main, run just release and review the guarded preflight summary before confirming the exact release tag. The command runs all release gates, publishes to Hex, pushes only the tag, and creates the GitHub release; partial failures require manual recovery.

License

MIT License. See LICENSE.