Skip to content

Add compile-time-checked ghost/observe layer - #56

Merged
carlsverre merged 1 commit into
mainfrom
ghost-observe-layer
Jul 13, 2026
Merged

Add compile-time-checked ghost/observe layer#56
carlsverre merged 1 commit into
mainfrom
ghost-observe-layer

Conversation

@carlsverre

Copy link
Copy Markdown
Contributor

Adds an optional layer on top of the existing API for writing read-only test properties and ghost state, ported from antithesis-sdk-rust#34 and adapted to precept's enabled feature gate and expect_* macros.

observe! runs a property block that may call any precept API and may optionally borrow one or more GhostStates. Its Fn bound makes it easier to avoid unintentionally mutating the system under test — the borrow checker rejects &mut captures, reassignment, and moves inside the block. This is a best-effort guardrail rather than a hard guarantee: it can't stop interior mutability (Cell, RefCell, Mutex, atomics) or unsafe, and the module docs call that out explicitly.

GhostState<T> is opaque auxiliary state that exists only to express properties. Its only mutator is GhostState::mutate and its only reader is observe!, so it can't leak into or perturb the system it describes. When the enabled feature is off it becomes a zero-sized type and every access compiles out, while the read-only and type checks still happen in every build configuration.

Everything is implemented in safe Rust with a plain Fn bound — no unsafe, proc macros, or AST inspection. The layer is exercised by unit tests (gated behavior plus an always-on smoke test) and doctests, including compile_fail doctests that prove mutation attempts don't compile. Verified against the full CI matrix — build, tests, doctests, clippy, and fmt — with and without --all-features.

Add an optional layer on top of the existing API for writing read-only
test properties and ghost state:

- `observe!` runs a property block that may call any precept API and may
  optionally borrow one or more `GhostState`s. Its `Fn` bound makes it
  easier to avoid unintentionally mutating the system under test.
- `GhostState<T>` is opaque auxiliary state that exists only to express
  properties. Its only mutator is `GhostState::mutate` and its only
  reader is `observe!`, and it is compiled out entirely (to a zero-sized
  type) when the `enabled` feature is off.

Ported from antithesis-sdk-rust#34, adapted to precept's `enabled`
feature gate and `expect_*` macros.

Co-Authored-By: Claude <noreply@anthropic.com>
@carlsverre
carlsverre merged commit 9dabe9e into main Jul 13, 2026
3 checks passed
@carlsverre
carlsverre deleted the ghost-observe-layer branch July 13, 2026 19:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant