schematron 0.3.2

Schematron: pure Rust implementation of ISO/IEC 19757-3 rule-based XML validation, with its own XML parser, XPath 1.0 engine, XPath 2.0 subset, schema linting, and SVRL reporting. By SixArm.com.
Documentation
# CLAUDE.md

Instructions for Claude Code in this repository.

**The instructions are in [`AGENTS.md`](AGENTS.md). Read that file.**

This file is deliberately a pointer, not a copy. Agent instructions split
across two files drift apart, and the drift is invisible until an agent acts
on the stale half. `AGENTS.md` is the single source of truth; everything below
is Claude-specific mechanics that do not belong there.

## Quick orientation

- **What this is** — a pure Rust ISO/IEC 19757-3 Schematron validator. No C,
  no XSLT, no FFI, no `unsafe`.
- **Where the truth lives** — [`spec/`]spec/ is normative. Code and spec
  disagreeing is a defect in one of them.
- **The gate** — these four must pass before any change is done:

  ```sh
  cargo test --all-features
  cargo clippy --all-targets --all-features -- -D warnings
  cargo doc --no-deps --all-features
  cargo +1.94 test --all-features
  ```

## Working notes

- **`cargo test --test cli` takes ~40 s** because it spawns the binary per
  test. `cargo test --lib` is the fast loop; run the full suite before
  declaring done.
- **Fuzzing needs nightly**, which is installed:
  `cargo +nightly fuzz run fuzz_xpath -- -max_total_time=60`.
  Budget for it; the default run is unbounded.
- **Benchmarks are slow by default.** For a quick signal use
  `--warm-up-time 1 --measurement-time 2 --sample-size 10`.
- **`cargo clippy --fix` needs `--allow-no-vcs`** here, since the repository
  has no version control initialised. Do not run `git init` to work around
  that — it is not this project's decision to make.
- **The MSRV toolchain `1.94` is installed.** If a bump is needed,
  `rustup toolchain install <version> --profile minimal` first, then actually
  run the tests on it.

## Things that look like bugs and are not

- `a = b` and `a != b` can both be true. XPath 1.0 node-set comparison is
  existential. Correct, deliberate, tested.
- `'x' > 0` is false rather than an error. Relational operators convert to
  number; the string becomes NaN.
- An unprefixed name in a schema matches **no namespace**. XPath 1.0 has no
  default namespace. This is the most common reason a schema appears to do
  nothing.
- A `report` firing does not make a document invalid. It is an observation.

Full list with reasoning: [`agents/invariants.md`](agents/invariants.md).

## Before claiming a change is done

Do not report success on a partial run. If a gate fails for a reason unrelated
to the change, say so explicitly rather than describing the work as complete.
New behaviour needs a test that fails without the change — verify that, do not
assume it.