aprender-core 0.65.1

Next-generation machine learning library in pure Rust
[package]
name = "aprender-core"
version.workspace = true
edition = "2021"
rust-version = "1.91"
authors = ["Noah Gift <noah@paiml.com>"]
license = "MIT"
description = "Next-generation machine learning library in pure Rust"
repository = "https://github.com/paiml/aprender"
documentation = "https://docs.rs/aprender"
readme = "README.md"
keywords = ["machine-learning", "classification", "clustering", "statistics", "graph-algorithms"]
categories = ["science", "algorithms"]
exclude = [
    # Build/IDE artifacts
    "target/",
    "*.profraw",
    "*.profdata",
    ".vscode/",
    ".idea/",
    "proptest-regressions/",
    # Dev tool artifacts (CB-510 class: recursive patterns required)
    ".pmat/",
    ".pmat-metrics/",
    ".pmat-metrics.toml",
    "*.bak",
    # CI/CD and dev infrastructure (not needed by library consumers)
    ".github/",
    ".githooks/",
    ".bashrsignore",
    "Makefile",
    "scripts/",
    # Documentation (published on GitHub Pages, not crates.io)
    "docs/",
    "book/",
    # Test data and traces
    "golden_traces/",
    # root-anchored: /tokenizer.json not tokenizer.json per CB-510.
    # Cargo excludes use gitignore semantics, so a pattern with no `/` matches at
    # ANY depth -- the bare form silently stripped
    # tests/fixtures/setfit/tokenizer.json (loaded by the ENC-02 parity gate)
    # from the package while leaving tokenizer_cases.json in.
    "/tokenizer.json",
    # The two SetFit conformance fixtures over the 1 MiB publish ceiling
    # (scripts/check_publish_safety.sh MAX_PACKAGED_BYTES = 1048576):
    # gradients.json is 1854378 bytes and optimizer_step.json is 1713469.
    # Both carry `/`, so gitignore semantics anchor them at the package root --
    # the same CB-510 trap the `/tokenizer.json` entry above documents. The rest
    # of tests/fixtures/setfit/ stays packaged deliberately, because the ENC-02
    # parity gate loads tokenizer.json from it.
    "tests/fixtures/setfit/gradients.json",
    "tests/fixtures/setfit/optimizer_step.json",
    "defect-report-*.json",
    "trace_*.json",
    "fuzz/",
    # Model files (root-anchored: /models/ not models/ per CB-510)
    "/models/",
    # Contracts not consumed by build.rs (model-families/ IS needed)
    "contracts/chat-template-semantics-v1.yaml",
    "contracts/classification-finetune-v1.yaml",
    "contracts/kernel-fusion-v1.yaml",
    "contracts/layer-parity-v1.yaml",
    "contracts/model-metadata-bounds-v1.yaml",
    "contracts/quantized-dot-product-v1.yaml",
    "contracts/special-tokens-registry-v1.yaml",
    "contracts/tensor-layout-v1.yaml",
    "contracts/tokenizer-vocab-v1.yaml",
    "contracts/publish-safety-v1.yaml",
]

[lib]
name = "aprender"

[lints]
workspace = true

[dependencies]
# Serialization
serde = { version = "1.0", features = ["derive"] }
# SafeTensors JSON metadata. `float_roundtrip` is DECLARED HERE rather than inherited:
# `json_roundtrip_of_an_f64_is_bit_exact` and the HeadFitReport stability test assert that
# `from_str(to_string(x)) == x` bit for bit, and a crate that asserts a guarantee has to be
# the crate that requests it. Without the feature serde_json's fast float parser can land
# one ULP away from the value ryu wrote (measured: 2.1531120041346774e-5 -> +1 ULP), which
# is why those tests previously asserted the INEXACTNESS instead. The feature adds no
# dependency (`float_roundtrip = []` in serde_json's manifest).
serde_json = { version = "1.0", features = ["float_roundtrip"] }
bincode = "1.3"
rmp-serde = "1.3"  # MessagePack for .apr metadata (spec §2)
tempfile = "3.14"  # Streaming APR writer temp file (realizar#136)

# Random number generation for model_selection
rand = { version = "0.9", features = ["small_rng"] }
rand_chacha = "0.9"  # ChaCha20 PRNG for Monte Carlo simulations

# Audio processing
rustfft = { version = "6.2", optional = true }  # FFT for mel spectrogram computation
thiserror = { version = "2.0", optional = true }  # Error handling for audio module

# Native audio capture (Linux ALSA)
alsa = { version = "0.9", optional = true }  # ALSA bindings for Linux audio capture

# Parallelization for graph algorithms (optional for WASM compatibility)
rayon = { version = "1.10", optional = true }

# Shared formatting and system utilities (Batuta stack)
batuta-common = { workspace = true }

# Core compute primitives - SIMD-accelerated tensor operations
# v0.14.5: wgpu adapter limits fix (buffer >256MB for 7B+ models)
trueno = { workspace = true }

# K-quantization formats (Q4_K, Q5_K, Q6_K) - Toyota Way: ONE source of truth
# Path dependency until published to crates.io
trueno-quant = { workspace = true }

# APR-2231: sovereign `.apr` container leaf. aprender-core From-wraps its
# AprFormatError into AprenderError and re-exports it (no API break). Leaf has
# no dependency back on core, so this introduces no publish cycle.
apr-format = { path = "../apr-format", version = "0.65" }

# NOTE: trueno-rag (=aprender-rag) removed (APR-MONO self-containment): aprender-rag
# depends on aprender-core + aprender-serve, so core→rag closed a core→rag→serve→core
# cycle. RAG lives in the aprender-rag crate (which depends on core), not the reverse.

# Compression for .apr format (optional, spec §3.3)
lz4_flex = { version = "0.11", optional = true }
zstd = { version = "0.13", optional = true }

# Half-precision floats for quantization (spec §6.2)
half = { version = "2.4", optional = true, default-features = false, features = ["std"] }

# Digital signatures for .apr format (optional, spec §4.2)
ed25519-dalek = { version = "2.1", optional = true, default-features = false, features = ["std", "zeroize", "rand_core"] }

# Encryption for .apr format (optional, spec §4.1)
aes-gcm = { version = "0.10", optional = true }
argon2 = { version = "0.5", optional = true, default-features = false, features = ["std"] }
x25519-dalek = { version = "2.0", optional = true, default-features = false, features = ["static_secrets"] }
hkdf = { version = "0.12", optional = true }
sha2 = { version = "0.10", optional = true }  # For HKDF-SHA256

# Data loading
alimentar = { workspace = true, optional = true }

# entrenar: removed as runtime dep — explainable types now live in aprender (GH-305)
# entrenar remains as dev-dependency for InferenceMonitor integration tests

# Syscall/GPU profiling for showcase benchmarks (dev-only to avoid circular dep)
# renacer depends on aprender, so it cannot be a runtime dep
# renacer = { version = "0.10", optional = true }

# SIMD-accelerated compression for KV cache (optional)
trueno-zram-core = { workspace = true, optional = true }

# Hugging Face Hub integration (optional, spec §11.8, hf-hub-upload-spec.md)
hf-hub = { version = "0.4", optional = true, default-features = false, features = ["ureq"] }
dirs = { version = "6.0", optional = true }
ureq = { version = "2.12", optional = true, features = ["json"] }  # Direct HTTP for HF Hub upload (APR-PUB-001)

# HF Xet protocol for files > 5 GiB (F-PUB-LFS-001,
# contracts/apr-publish-hf-large-file-v1.yaml, spec §12.8)
hf-xet = { workspace = true, optional = true }

# SafeTensors format parsing (optional, for HF model comparison)
safetensors = { version = "0.4", optional = true }

# HuggingFace tokenizers (optional, `setfit` feature only — Phase 1 ENC-02).
# Workspace pin carries `default-features = false, features = ["fancy-regex"]`
# so no onig/esaxx native toolchain is required. D-06: a build without `setfit`
# must not contain a `tokenizers` node at all.
tokenizers = { workspace = true, optional = true }

# Counter-based Philox RNG (lib name `trueno_rand`), `setfit` feature only —
# Phase 3 TRN-06. The SetFit encoder's dropout masks are derived from
# (root_seed, site, forward_ordinal, element) through Philox 4x32-10 rather than
# drawn from a stateful `Mutex<StdRng>`, so a `rand` version bump cannot move the
# loss trace and mask element `i` is a pure function of its index. Leaf crate
# (deps: thiserror only), so the edge is acyclic. Optional and reached ONLY
# through `setfit`: a build without that feature must not contain the node.
aprender-rand = { workspace = true, optional = true }

# WASM bindings for noise generator (optional, spec: noise-generator-apr-wasm-spec.md)
wasm-bindgen = { version = "0.2", optional = true }
js-sys = { version = "0.3", optional = true }
minijinja = { version = "2.14.0", features = ["loader", "serde"] }

# UCBD: compile-time contract enforcement via #[contract] proc macro
provable-contracts-macros = { workspace = true }

# Toyota Way: ONE source of truth for quantization (Step E)
# NOTE: Currently blocked by cyclic dependency (realizar optionally depends on aprender).
# Resolution requires creating a separate quantization crate.
# See docs/specifications/qwen2.5-coder-showcase-demo.md Section E.7 for roadmap.
# realizar = { version = "0.6", default-features = false, optional = true }  # BLOCKED

[build-dependencies]
serde = { version = "1", features = ["derive"] }
serde_yaml_ng = "0.10"

[dev-dependencies]
proptest = "1.6"
criterion = { workspace = true }
# Permissive version + path: locally resolves via path; clean-room's
# strip_path_deps removes `path = "..."` leaving a valid `version + package`
# entry. Permissive range (>=0.27) breaks the publish-time cycle (otherwise
# aprender-core's publish requires entrenar/renacer at workspace 0.32.0 on
# crates.io BEFORE aprender-core itself ships, but those crates can't ship
# until aprender-core does).
renacer = { path = "../aprender-profile", package = "aprender-profile" }
tempfile = "3.14"  # For format module tests
jugar-probar = { path = "../aprender-test-lib", package = "aprender-test-lib" }  # TUI/GUI testing framework with coverage tracking (spec §8)
ctrlc = "3.4"  # Signal handling for SIGINT/SIGTERM (PMAT-098-PF: zombie process mitigation)
provable-contracts = { path = "../aprender-contracts", package = "aprender-contracts" }  # Contract enforcement (dev-only)
# Integration tests for InferenceMonitor (GH-305: was runtime dep, now dev-only).
# Same publish-time cycle break as renacer above.
entrenar = { path = "../aprender-train", package = "aprender-train" }
serde_yaml = "0.9"  # YAML contract binding in tests (FALSIFY-SHIP-009 GATE-APR-PROV-004)
# The in-tree contract crate is reached through `provable-contracts` above: upstream
# repointed that key from the crates.io package to ../aprender-contracts, which is
# exactly what the old `setfit-contract-schema` alias (plan 01-08, D-14) existed to
# achieve. Two keys for one package in one table is a cargo error, so the alias is
# gone and the setfit conformance harness uses `provable_contracts::` directly — still
# the SAME deserializer `pv validate` uses, so the generator cannot drift from pv.
half = { workspace = true }  # IEEE f16 oracle for the convert_report f32_to_f16 RNE falsifier (PMAT-905)
# `tests/setfit_conformance.rs` hashes fixture bytes to pin what it compared against.
# `sha2` is already an OPTIONAL runtime dep (setfit/format-encryption/hf-hub), and an
# optional runtime dep is NOT available to `tests/` unless that feature is on — so a
# plain `cargo test --test setfit_conformance` build needs this dev-dependency.
# Workspace-pinned: no new external package enters the tree.
sha2 = { workspace = true }

[features]
default = ["parallel"]
parallel = ["rayon"]  # Enable parallel graph algorithms (disable for WASM)
# `sha2` was an IMPLICIT feature (cargo synthesises one per optional dependency)
# that `format-encryption` and `hf-hub-integration` referenced by bare name. The
# moment any feature writes `dep:sha2`, cargo stops synthesising the implicit
# one and those two references fail to resolve. Declaring it explicitly keeps
# the published feature surface byte-identical while letting `setfit` use the
# unambiguous `dep:` form.
sha2 = ["dep:sha2"]
datasets = ["alimentar"]  # Enable data loading from alimentar
format-compression = ["lz4_flex", "zstd", "apr-format/compression"]  # Enable LZ4/ZSTD compression for .apr format (spec §3.3, GH-146); forward to apr-format so container I/O actually compresses
format-signing = ["ed25519-dalek"]  # Enable Ed25519 signatures for .apr format (spec §4.2)
format-encryption = ["aes-gcm", "argon2", "x25519-dalek", "hkdf", "sha2"]  # Enable encryption for .apr format (spec §4.1)
format-quantize = ["half"]  # Enable quantization for .apr format (spec §6.2)
format-homomorphic = []  # Enable homomorphic encryption for .apr format (spec: homomorphic-encryption-spec.md)
# Note: mmap is automatic on native platforms, no feature needed (spec: bundle-mmap-spec.md)
hf-hub-integration = ["hf-hub", "dirs", "ureq", "sha2"]  # Enable Hugging Face Hub integration (GH-100, APR-PUB-001)
xet = ["hf-hub-integration", "hf-xet"]  # Enable HF Xet protocol for files > 5 GiB (F-PUB-LFS-001, spec §12.8)
audio = ["rustfft", "thiserror"]  # Enable audio processing (mel spectrogram, resampling)
audio-capture = ["audio"]  # Enable audio capture base functionality
audio-alsa = ["audio-capture", "alsa"]  # Enable ALSA audio capture (Linux only)
audio-coreaudio = ["audio-capture"]  # Enable CoreAudio capture (macOS only)
audio-wasapi = ["audio-capture"]  # Enable WASAPI capture (Windows only)
audio-webaudio = ["audio-capture"]  # Enable WebAudio capture (WASM only)
audio-playback = ["audio"]  # Enable audio playback
audio-codec = ["audio"]  # Enable audio codec decoding (WAV, MP3, AAC, FLAC, Opus)
audio-noise = ["audio"]  # Enable ML-based noise generation (GH-144)
audio-noise-wasm = ["audio-noise", "wasm-bindgen", "js-sys"]  # Enable WASM bindings for noise generator
safetensors-compare = ["safetensors", "hf-hub-integration", "half"]  # Enable SafeTensors comparison (GH-121)
# `rag` feature removed (APR-MONO self-containment) — RAG lives in the aprender-rag crate.
# inference-monitoring feature removed — explainable types now unconditional (GH-305)
gpu = ["trueno/gpu"]  # Enable GPU acceleration via trueno wgpu backend
model-tests = []  # Enable heavy model/inference tests (requires models/ dir, ollama, GPU)
cuda = ["trueno/cuda-monitor"]  # Enable CUDA monitoring via trueno-gpu (NVIDIA GPUs)
cpu-only = []
showcase-profile = []  # Renacer profiling (disabled: renacer→aprender circular dep)
showcase-zram = ["trueno-zram-core"]  # Enable trueno-zram KV cache compression for showcase benchmarks (PAR-040)
explainable-monitor-integration = []  # Enable integration tests for aprender explainability + entrenar InferenceMonitor (GH-305)
# Chaos engineering features (from renacer)
chaos-basic = []
chaos-network = ["chaos-basic"]
chaos-byzantine = ["chaos-basic"]
chaos-full = ["chaos-network", "chaos-byzantine"]

# SetFit / MiniLM differentiable conformance (Phase 1, contract
# setfit-encoder-conformance-v1).
#
# `dep:sha2` is NOT optional polish. `sha2` is declared optional above and is
# otherwise enabled only by `format-encryption` and `hf-hub-integration`; the
# setfit module hashes tokenizer bytes and input text in PRODUCTION code, so
# `cargo check -p aprender-core --features setfit` would not compile without it.
# The feature is declared dependency-CLOSED: enabling `setfit` alone must build.
#
# `dep:aprender-rand` (Phase 3, TRN-06) is the same kind of entry: `setfit/dropout_rng`
# uses Philox 4x32-10 in PRODUCTION code, so the feature would not build without it.
# `cargo check -p aprender-core --no-default-features` is the standing proof that
# neither node reaches a build that did not ask for `setfit`.
setfit = ["dep:tokenizers", "dep:sha2", "dep:aprender-rand"]
# Conformance fixtures gate the test-only slice constructor, which lives inside
# `#[cfg(feature = "setfit")] mod setfit` — so this must IMPLY setfit rather than
# being an empty marker that could be enabled alone and gate nothing.
conformance-fixtures = ["setfit"]

# WASM support: enable getrandom's "js" feature for browser environments
[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { version = "0.2", features = ["js"] }

# Memory-mapped I/O for native platforms (spec: bundle-mmap-spec.md)
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
memmap2 = "0.9"

[[test]]
name = "book"
path = "tests/book/mod.rs"

[[bench]]
name = "linear_regression"
harness = false

[[bench]]
name = "kmeans"
harness = false

[[bench]]
name = "dataframe"
harness = false

[[bench]]
name = "graph"
harness = false

[[bench]]
name = "recommend"
harness = false

[[bench]]
name = "citl"
harness = false

[[bench]]
name = "bpe"
harness = false

[[bench]]
name = "ollama_parity"
harness = false
required-features = ["format-quantize"]

[[example]]
name = "shell_encryption_demo"
required-features = ["format-encryption"]

[[example]]
name = "chat_template"

[[example]]
name = "text_preprocessing"

[[example]]
name = "time_series_forecasting"

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--generate-link-to-definition"]
targets = ["x86_64-unknown-linux-gnu"]

[package.metadata.release]
sign-commit = false
sign-tag = false
push = true
publish = true
shared-version = true
tag-name = "v{{version}}"
pre-release-commit-message = "release: aprender v{{version}}"

[[package.metadata.release.pre-release-replacements]]
file = "CHANGELOG.md"
search = "## \\[Unreleased\\]"
replace = "## [{{version}}] - {{date}}"

# PMAT-262: Self-patch so transitive deps (realizar, entrenar) use the local
# workspace aprender instead of a stale crates.io version. This prevents type
# mismatches when building apr-cli from the workspace.
# GH-344: Sibling patches (realizar, trueno, etc.) moved to .cargo/config.toml.dev-overrides
# so that `git clone && cargo check` works without sibling repos.
# See .cargo/config.toml.dev-overrides for full-stack development setup.