Skip to content

Releases: TraceFold/tracefold

v0.1.3-alpha: The Unmediated Write, Reported From Outside

Choose a tag to compare

@mahirhir mahirhir released this 03 Sep 10:07

Two defects in the OpenClaw plugin example were reported from outside, by a
reader who read the published code. Neither was found by us. Both are fixed
here, and the fixes are in the public tree as of this tag.

What was wrong

The admitted write was re-applied without a precondition. On Admit the
hook returned { params } and let OpenClaw's own write run afterward. A
comment in the source defended this as "a real property of this design, not an
omission". The comment was wrong about the part that matters: the
re-application was unconditional. Anything landing between our commit and that
native write — a later hook in the chain, a background process, the agent's own
bash, a file watcher — was overwritten with no receipt. A single caller was
enough; no concurrency required.

The refusal named the doors that were still open. cfg.tools covered
write alone. With the membrane unreachable, write came back blocked with a
careful paragraph explaining that gx could not be consulted, and that paragraph
landed in the model's context while edit and apply_patch sat there
untouched. The blast radius of an outage was "writes move".

What changed

Admit now returns block: true, naming the transformation and the receipt.
The effect is already in the substrate; the native write is redundant, and
allowing it was the only path by which unmediated bytes could move. Zero
unmediated byte movement now follows from OpenClaw's own control flow rather
than from our intent.

The reporter's suggested repair — rewrite params so the native call becomes a
verified no-op — turned out not to be expressible. hook-before-tool-call-result
carries {params, block, blockReason, requireApproval} and no result
substitution; writeSchema is {path, content} with no field for a
precondition; and params merges by lastDefined, so a later plugin overwrites
ours. Re-hashing afterward detects, it does not prevent. Blocking was the
stronger available shape, not the preferred one.

MEDIATED_TOOLS now covers write, edit and apply_patch, from one exported
constant instead of four separate call sites. edit and apply_patch describe
a delta rather than a target state, so they are covered by refusal rather than
escrow — worse for the agent, better for the invariant. The message was not made
vaguer. bash is declared statically in docs/LIMITS.md instead.

What this does not fix

bash remains unmediated. There is no in-plugin fix for it.

The drift case is proven by a unit test, not by the gx-backed demo.

An admitted write is now recorded by OpenClaw as blocked, so it emits a blocked
diagnostic and a security event for a write that succeeded. Telemetry built on
those counts will be wrong.

Also in this tag

action.yml called gx verify-receipts, a subcommand that has never shipped —
the action could not have passed. It now calls gx policy lint and
gx receipt verify --offline. Two inputs that mapped to no flag,
enforce-inverses and fail-on-tamper, were removed rather than left standing
as dials that did nothing.

Three engine accessors returned null after a restart because they read only the
in-memory table: deadline(), planned_delta(), and the pair behind
get_transformation/get_candidate. Each now falls back to the shadow row or
the blob store. undo_intent does not, and cannot without locator, context and
actor, none of which the shadow carries; that gap is pinned by an ignored probe
rather than papered over.

Five red tests were asserting facts that had gone stale, not defects. Package
names diverged from directory names, a manifest grew a member, a predicate that
once identified one crate had come to match seven. Fixed in the tests, with no
change to product source.

State

Alpha. 2,918 of 2,980 tests pass; 60 fail, of which 44 need database or probe
services this checkout does not start. Four adapters are public, three are on
crates.io. CI has not run a job since 2026-08-20 — the account's Actions billing
is blocked, and every check you see on recent commits is a check that never
started.

The limits page is still longer than the feature list.

v0.1.2-alpha: A Promised Target, Kept

Choose a tag to compare

@mahirhir mahirhir released this 01 Sep 10:35

Tracefold v0.1.2-alpha

Repairs and additions landed since v0.1.1-alpha, cut at commit 1cfdfa0001c8c31a9d0f4a2648354369794d00d3 (pub_sync round 6, from the private development tree's committed HEAD -- nothing staged from a dirty working copy).

What changed since v0.1.1-alpha

  • A plan() now actually promises a post-state digest, on both shipped stateful adapters. gx-adapter-fs and gx-adapter-git's plan() call the with_promised_target constructor path for the first time in a shipped release (previously always None) -- WM-5a Phase 1.
  • A cold-undo / cold-redo data-loss-shaped defect was found and fixed while wiring the above. A second site in gx-engine that constructs a Transformation (rehydrate_committed, used after an engine restart) was zeroing the promised target instead of carrying it, which meant every undo or redo issued after a cold restart silently lost the promised-target check the hot path already had. Both demo30.sh and demo_one_screen.sh (the fs and git tamper-and-undo demos) now pass end-to-end against this build; they did not before this lane.
  • PredictionOutcome: the engine used to record only a failed post-state prediction (as the seventh not-attempted cause added in v0.1.1-alpha) and stay silent when a prediction held. That made "the engine predicted correctly" and "the engine never checked" look identical from outside. The comparison is now recorded either way, at one site, for both branches. This is an internal engine record -- nothing on the wire changed, and no shipped client needs to do anything differently.
  • Escrowed-inverse resolution now falls through to a Σ-shadow fallback when the direct escrow lookup misses, per the R1017 ruling, instead of surfacing an avoidable failure.
  • GET /v1/transformations/{id} carries inverse_status. A subsequent investigation (prompted by a TUI-side report of a spurious error state) confirmed the wire contract was correct from the start: the API was already sending null correctly for the no-inverse-yet case. The bug was on the reading side, in the terminal face, which is fixed separately in the tui/ sources this sync also carries -- a status_reason classifier now reads a null as Absent (--) instead of misreporting it. Nothing in this repository's gx-api/gx-engine needed to change for that fix.
  • Four Cedar policy packs, previously private, now ship: policies/{fs,git,mcp,postgres}/deny-*.cedar, each with its own scenarios.json fixture beside it (PACK_FORMAT.md F1).
  • docs/ADAPTER_GUIDE.md is new: how to write a SubstrateAdapter against the shipped fs/git/mcp adapters and the conformance harness, without reaching into engine internals.
  • A new example, examples/openclaw-plugin-demo/: a before_tool_call-hook plugin against a real gx binary, demonstrating the escrow/undo membrane pattern for OpenClaw-shaped agent harnesses. It drives a real filesystem and a real gx process; it does not drive OpenClaw itself (the firing order is reproduced by a harness in the same example, and the README says so). One honest note about this example specifically: an earlier working copy of it defaulted an environment variable (GX_DEMO_BIN) to the machine-local absolute path of the machine that wrote it. That default was removed before this sync (the variable is now required, with a clear error if unset) -- named here because it is exactly the kind of thing a "diff, don't trust" sync gate exists to catch, and did.
  • Crate versions bumped 0.1.0 -> 0.1.2 across all 13 crates this tree ships plus tui (gx-tui), workspace-consistently, including every internal path-dependency version pin. gx --version now prints gx 0.1.2 (previous tags shipped a binary that printed gx 0.1.0 regardless of the tag name; this one does not have that mismatch). Not bumped: the TypeScript SDK's package.json (still 0.1.0) -- that drift is disclosed here rather than fixed silently, since fixing it was not part of what this bump covered.

What is still not true of this release (read before assuming otherwise)

  • crates.io publishing is still blocked, for two independent, unresolved reasons found while checking: (1) gx-core, gx-tui, and bare gx are already registered on crates.io by an unrelated third party (a different Rust tool, galax, that happens to use the same short name) -- every crate in this workspace path-depends on gx-core, so the name collision blocks the whole dependency closure, not just one crate; a rename (candidate: tracefold-*) is pending an operator decision, not yet applied to any shipped file. (2) gx-gate's packs.rs reaches three directories above its own crate root via include_str! for policy files that, per cargo package --list, do not end up in the packaged tarball -- publishing gx-gate (and its dependents gx-engine, gx-api, gx-cli) as-is from a cargo publish tarball would build broken. Every crate in this tree still carries publish = false.
  • CI has still run zero jobs on any push, unchanged since the GitHub Actions billing block that started 2026-08-15T17:25:29Z (req/908) -- not a code defect. See docs/LIMITS.md item 8 for the full, dated account; the last run before the block (commit f65aac2f) covered 16 of this tree's 17 workspace crates.
  • The postgres and mysql SubstrateAdapters are not in this public tree at all (private-only, per the sync's own scope ruling), so anything they, or a PostgreSQL-17-specific suite, would test is not just unmeasured here -- the code that would run it is not present in a clone of this repository. docs/LIMITS.md's own postgres disclosures ("not measured for power cuts", four releases running as of that doc) describe the private engineering state, not something buildable from this tree.
  • The published Test Floor number (2,602 probes / 454 suites + SDK 36) is dated 25 Aug 2026 and was not re-measured for this release. Four new test files landed in this sync (wm5a_promised_target.rs x2, r1017_escrowed_inverse_shadow.rs, wm5a_prediction_on_real_data.rs); the badge and README table do not yet reflect them. Re-counting is a docs-sync change, named here rather than silently left implying a number this release did not check.
  • No pre-built binary is attached to this release at publish time (unlike v0.1.0-alpha and v0.1.1-alpha, which each got one added by hand after the tag). gx --version on a self-built binary from this tag prints gx 0.1.2, confirmed on a fresh worktree of the exact tagged commit before this tag was cut; a binary asset may follow the same way the prior two tags' did.
  • Everything else this project does not guarantee is unchanged and still enumerated in docs/LIMITS.md -- the same 8 clauses gx limits prints.

Getting the source

git clone https://github.com/TraceFold/tracefold.git
cd tracefold
cargo build --release -p gx-cli

No binary asset ships with this tag; building from source is the only path for now.

v0.1.1-alpha: Fail-Closed Action Gate & Seventh Not-Attempted Cause

Choose a tag to compare

@mahirhir mahirhir released this 31 Aug 21:09

Tracefold v0.1.1-alpha

Repairs landed since v0.1.0-alpha, cut at commit a77f9432dd84ca5d3a405f39cbc73a10e2961ae1. One process note first: the v0.1.0-alpha binary was uploaded to the existing release on 2026-09-01, and adding an asset to an old release notifies nobody — this tag exists partly so the repairs and the binary actually reach release watchers.

What changed since v0.1.0-alpha

  • action.yml was fail-open and is now fail-closed (issue #5). The old stub printed "Tracefold gate validation passed (stub check)" when the gx binary was not installed — a gate that could not run, passing. It now exits 1 with an error when gx is absent. The retired stub line is kept as a comment in the file, for the record. Second honest limit, stated in the file itself: gx verify-receipts is not a shipped subcommand yet (the CLI ships gx receipt verify), so even with gx installed the step currently fails — the intended fail-closed direction until the input mapping lands.
  • A seventh not-attempted cause, PromisedPostStateWasWrong, is now in the public tree. The cause enum had six reasons and the code needed a seventh: the case where a tool's promised post-state disagrees with what checking it would require. Previously this was collapsed into a neighboring cause.
  • gx limits re-synced its Lean clause (previously 117 theorems; see the number caveat below), and the stale CI claim in it was replaced with a dated statement bound to the diagnosis (req/908) rather than a present-tense sentence that goes quietly false.
  • README and docs overhaul: subcommand list corrected (13 said, 22 exist), Zenodo DOI 10.5281/zenodo.22168558 integrated, architecture and org pages restructured.

Numbers, and one mismatch named rather than smoothed over

  • This binary's gx limits clause 8 says 154 theorems, 14 of them counterexamples, over 14 files. A line-start count on this public tree at this commit returns 117 theorems (119 with leading whitespace tolerated) over 13 .lean files, 12 named counterexamples, 0 sorry, 1 axiom — agreeing with the README badge (117) and docs/LIMITS.md, not with the limits page. The 154/14/14 figures describe the development tree the sync came from; the public transplant carries 13 of its 14 Lean files. Fixing the text is a docs-sync change, not a release change, so it is disclosed here and will be corrected in the next sync.
  • Test floor as published in this tree's own README, with date and method: 2,602 probes across 454 suites plus the SDK's 36 (fresh clone, single run, 25 Aug 2026).
  • Everything this project does not guarantee: docs/LIMITS.md — the same 8 clauses gx limits prints. A copy of LIMITS.md is inside the tarball.

Pre-built binary — Linux x86_64, glibc. That is the only platform this release ships a binary for.

gx-v0.1.1-alpha-x86_64-unknown-linux-gnu.tar.gz

What this asset is, and is not:

  • Built from this release's commit a77f9432 on a fresh clone (Ubuntu 24.04, toolchain pinned by rust-toolchain.toml, rustc 1.97.1) with cargo build --release -p gx-cli. Smoke-tested before upload: gx --version prints gx 0.1.0; gx limits exits 0 and prints the 8 documented limit clauses.
  • --locked did not work, and that is a defect of this tree: the shipped Cargo.lock at this commit still carries entries for development-tree crates that are not in this repository, so cargo refuses --locked. The build regenerated the lockfile; the diff is 913 removed lines (the absent crates and their unique dependencies) and 5 reflowed dependency-list lines — no version of any retained dependency changed.
  • The binary prints gx 0.1.0, not 0.1.1. Crate versions were not bumped; this tag names a repository state, not a crates.io version.
  • Not a CI artifact. The release.yml pipeline has still never produced a run; this was built and uploaded by hand. No DSSE receipt of the build itself is attached, so issue #7's acceptance criteria remain unmet.
  • No macOS, Windows, or ARM binaries. On those platforms: cargo install --git https://github.com/TraceFold/tracefold.git gx-cli (requires a Rust toolchain).
  • Dynamically linked against glibc — it will not run on musl-only systems (Alpine).
  • Verify the download: sha256sum -c SHA256SUMS. The tarball's SHA-256 is 34f2a2615fca2f37367581cfa0d0495f6e93bae23e07511738056db59d6e0b07.

v0.1.0-alpha: Verified Transformation Calculus & Inverses Engine

Choose a tag to compare

@mahirhir mahirhir released this 27 Aug 13:33

Tracefold v0.1.0-alpha Initial Release

Tracefold provides formal reverse-execution guarantees, pre-commit inverse escrow, and offline-verifiable DSSE receipts for AI agent tool executions and filesystem mutations.

Highlights:

  • gx-core: Verified transformation calculus with Lyapunov convergence proofs and invariant assertions.
  • gx-witness: Ed25519 DSSE signed audit receipts with offline verification and full single-bit tamper detection.
  • gx-log: Merkle tile log append, root consistency proofs, and checkpoint verification.
  • gx-cli: Command-line tool for verifying receipts and inspecting execution histories.

Getting Started:

cargo install --git https://github.com/TraceFold/tracefold.git gx-cli

Pre-built binary (asset added 2026-09-01)

gx-v0.1.0-alpha-x86_64-unknown-linux-gnu.tar.gz — Linux x86_64, glibc. That is the only platform this release ships a binary for.

What this asset is, and is not:

  • Built from this release's tag commit e2de2a814ee630e51a3925381656b7a348961ca3 with cargo build --release --locked -p gx-cli on a fresh clone (Ubuntu 24.04, toolchain pinned by rust-toolchain.toml). Smoke-tested before upload: gx --version prints gx 0.1.0; gx limits prints the 8 documented limit clauses.
  • Not a CI artifact. The release.yml GitHub Actions pipeline has never produced a run; this binary was built and uploaded by hand from the tagged source. No DSSE receipt of the build itself is attached, so issue #7's acceptance criteria are not met by this upload — it only closes the "release has no binary at all" gap.
  • No macOS, Windows, or ARM binaries. On those platforms use cargo install --git https://github.com/TraceFold/tracefold.git gx-cli (requires a Rust toolchain).
  • Dynamically linked against glibc — it will not run on musl-only systems (Alpine).
  • Verify the download: sha256sum -c SHA256SUMS (checksum file is attached alongside; the tarball's SHA-256 is 5c0fae3f27138ba0237d3533c0607668c43c778c057f327d9796187d1e652756).

Numbers for the tagged tree, as published in its own README with date and method: test floor 2,602 probes across 454 suites plus the SDK's 36 (fresh clone, single run, 25 Aug 2026); 117 Lean theorems, 12 of them counterexamples, 0 sorry, 1 named axiom (re-counted on a fresh clone, 26 Aug 2026). What this project does not guarantee is enumerated in docs/LIMITS.md — the same 8 clauses gx limits prints, and a copy of LIMITS.md is inside the tarball.

Demo recordings (not a software release)

Choose a tag to compare

@mahirhir mahirhir released this 26 Aug 01:18

Terminal recordings of the verification path, captured with script(1) from real runs against a fresh anonymous clone at commit 177141e on 2026-08-26 (WSL2 Ubuntu 24.04, dev profile).

  • tracefold-demo-10s.gif - the atom: verify an intact receipt (exit 0), flip one byte, verify again (exit 7).
  • tracefold-demo-30s.gif - the chain: an agent acts through gx, a receipt is issued, three files travel, a stranger verifies offline, a tampered copy fails.
  • *.cast - the same two runs as asciicast v2, for anyone who would rather replay the bytes than watch a GIF.

Excluded from both recordings on purpose: cargo build --workspace, measured at 64 seconds on this run. The demos start after the binary exists. No output was retyped or staged.

Figures — 2026-08-19

Choose a tag to compare

@mahirhir mahirhir released this 18 Aug 17:02

Evidentiary figures for the census/retention measurements and instrument-hygiene write-ups. Generator: tools/census/figure.py and tools/math_cards/render.mjs. Not a software release.

Brand assets (not a software release)

Pre-release

Choose a tag to compare

@mahirhir mahirhir released this 17 Aug 15:33

Images the public pages point at. Not a software release; the tag exists so the files have a stable address that is served from a CDN.