Contract-first anomaly detection over arbitrary corpora. The thesis (from AI
Tools Need Contracts, Not Prompts): the executable is the contract. Output
is a dense, versioned tq1 JSON envelope an agent can trust — never pretty text.
- Determinism is a hard requirement. No wall-clock, no RNG, no environment
reads in the measurement path. All numeric reductions go through
ax_core::det(order-independent, Neumaier-compensated). Same input + sameconfig_version⇒ byte-identical output. If you reach for randomness, you're solving it wrong — find the deterministic method (e.g. Mahalanobis, not isolation forest). - Honest absence. A detector that can't run records an
Absencewith a reason; it never fabricates a clean result. A missing cell isValue::Null, never0.0. An unresolvedexplainhandle fails with exit code2. - The
tq1envelope is an API. Changing a field, the dense row layout, an exit code, or a handle form is a breaking change: bumpenvelope::PROTOCOL, updateanomalyx schema, and update the contract tests. Don't weaken it casually. - The strong gates are the definition of done. Property-based tests
(
proptest) and mutation testing (cargo-mutants) with zero surviving (missed) mutants. Timeouts are acceptable (loop-bound hangs = detected). Run./scripts/gates.shbefore every push. CI runs fmt/clippy/test only — the mutation gate is local-only (too many CI minutes) and is your responsibility before pushing. - Equivalent mutants are documented, never blanket-suppressed. If a mutant
truly cannot change observable behavior, prove why in a comment and add a
specific entry to
.cargo/mutants.toml. Prefer killing it with a test or a small refactor first. - Exit codes are committed:
0clean ·1anomalies found ·2error.
5-crate workspace. The contract is engine-independent so the heavy machinery can change without the output shape moving.
ax-core(pkganomalyx-core) — contract types:RecordSet, the 7-class anomaly taxonomy, thetq1envelope, handles, deterministic reductions (det). No heavy deps — keep it small so the mutation gate stays fast.ax-normalize(pkganomalyx-normalize) — any format →RecordSetvia a parser plugin registry. Polars (Parquet/Arrow) lives only here, behind the default-onpolarsfeature.ax-detect(pkganomalyx-detect) — theDetectortrait +Registry; the nine detectors. Math assembled fromstatrs, not reinvented.anomalyx— the four-verb CLI (describe/schema/scan/explain).ax-validate(publish = false) — NIST StRD validation + stress harness.
Note: crates.io packages are anomalyx-* but the in-source import names stay
ax_core/ax_normalize/ax_detect (Cargo dependency rename). Don't "fix" this.
- A format: new
crates/ax-normalize/src/parsers/<fmt>.rsimplementingFormatParser(id, extensions, contentsniff,parse), then oneregister(...)line inparsers/mod.rs::default_registry. No central match. See the openformatissues. The@format-parseragent /add-formatworkflow exist for this. - A detector: implement
Detectorinax-detect(id,class,detectoverScanContext), register inRegistry::default_set, add any config toDetectConfig(and itsversion()fingerprint), emit findings with a stableHandleand a calibrated confidence. Honest absence when it can't run. - Either way: PBT invariants + exact-value tests, then
cargo mutantsto 0 survivors. The@detector-authorand@mutation-hardeneragents help.
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo fmt --all
cargo mutants -p <crate> # gate: mutants.out/missed.txt must be empty
./scripts/gates.sh # fmt + clippy + test + mutation, all of it
./scripts/publish.sh [--dry-run] # crates.io publish, dependency order
mdbook build docs # the docs site (also auto-deployed by CI)- Add heavy dependencies to
ax-core, or let Polars types escapeax-normalize. - Introduce nondeterminism anywhere a result is computed.
- Weaken the
tq1contract or a test assertion to make a gate pass. - Commit/push or publish unless asked. Branch off
mainfirst.