Best Practices¶
These recommendations follow documented library behavior. They are not a substitute for detector-specific calibration or an application threat model.
Make the event contract explicit¶
- Validate required feature names and units at the ingestion boundary.
- For schema-owning numeric models, keep the feature-key set fixed after the
first successful
learn_one. Dictionary insertion order can vary because the shared schema canonicalizes names. - For
IncrementalPCAandRandomProjection, passkeys=when order must be declared before learning; otherwise the first learned dictionary's order is retained. - Do not encode missingness as an undocumented numeric sentinel. Impute or reject it under a policy the model was calibrated with.
- Reject non-finite values before they reach static threshold wrappers too.
Stateful numeric boundaries reject them, but
ThresholdModelis a rule evaluator rather than a general numeric validator. - Keep feature units stable. A distance, reconstruction error, radius, or covariance threshold calibrated in one unit system is not portable to another.
Define score/learn order once¶
Use one event-processing function for the application and test its call order. For prequential evaluation and ordinary prospective alerting:
- validate and construct the event;
- call
score_one; - record the score and make any threshold decision;
- update drift monitoring from the chosen scalar;
- call
learn_oneonly if the application's learning policy accepts the event.
score_one means that the event is not learned. It does not promise that every
incidental implementation detail is immutable: query caches can be refreshed,
and RandomModel.score_one deliberately advances its model-local generator.
Pipeline learning uses post-update transforms. If application code performs manual preprocessing instead, match that ordering deliberately rather than assuming transform-then-learn is equivalent.
Treat warm-up as an experiment parameter¶
- Distinguish application warm-up from a detector's minimum internal readiness.
- Suppress or separately label warm-up scores instead of interpreting a forced
0.0as normal evidence. - Record whether warm-up data is curated-normal, unlabeled, or contaminated.
- Do not use future labels to decide retrospectively which warm-up events the model should have learned.
- Recalibration after reset or model replacement needs its own warm-up policy.
Calibrate score policy per detector¶
- Never reuse a numeric threshold merely because two detectors both return
values in
[0, 1]. Boundedness is not probability calibration. - Preserve the raw detector score even when an external threshold produces a binary alert; it is needed for ranking metrics and incident analysis.
- For
QuantileThreshold, decide which scores enter its window. Learning every score adapts to persistent anomalies and can raise the threshold. - Set thresholds from prior calibration data or an online policy available at the decision time, not from labels in the evaluated interval.
- Monitor score distributions and alert rates separately. A stable alert rate can conceal a moving adaptive threshold.
Handle time deliberately¶
- With
time_key=None, time-aware models use arrival order. Retries, buffering, and partition merges can therefore change semantics. - With an explicit
time_key, ABERRANT accepts non-decreasing time. Equal values are valid; a later smaller value raisesValueError. - Models based on buckets require integer-like timestamps. Do not silently round wall-clock values in application code.
score_onepreviews but does not commit shared model time. A subsequent successfullearn_oneadvances it.- Define how late and duplicate events are handled before the model boundary; the library does not reorder a stream.
Separate drift signal from drift response¶
A drift flag identifies statistical change in the monitored scalar, not its cause. Before deployment, choose which signal is monitored and specify a response matrix for data-quality failures, expected seasonal change, model degradation, and incident bursts.
Do not assume reset is universally correct. Depending on the model and failure mode, a safer response can be to investigate, recalibrate only the threshold, warm a replacement model in parallel, or reject an upstream release. See Drift Detection.
Reproducibility and concurrency¶
- Set every exposed seed and record it with the constructor parameters and ABERRANT version.
- Compare stochastic models across multiple seeds; one repeat is deterministic evidence, not a stability estimate.
- ABERRANT's seeded NumPy and PyTorch initialization paths use model-owned generators where implemented. External libraries, user-supplied architectures, optimizers, and hardware kernels can introduce additional nondeterminism.
- Treat each model instance as single-owner. The package does not promise that
concurrent
learn_oneandscore_onecalls on one instance are atomic or thread-safe. OnlineIsolationForest(n_jobs=-1)parallelizes work across all reported logical CPUs; it does not make concurrent caller access safe.- When processing partitioned streams, give each partition its own model or serialize access under an application-owned ordering policy. Incremental model state is generally not mergeable.
Persistence and upgrades¶
ABERRANT does not currently define a stable, cross-version model serialization format. Do not document or rely on generic pickle/joblib persistence as a package guarantee.
If an application checkpoints model objects anyway:
- own the serializer and storage security policy;
- never load an untrusted pickle-like artifact;
- record the exact Python, ABERRANT, NumPy, SciPy, and optional dependency versions;
- test round-trip scores and subsequent learning for every model type;
- retain the source event offset needed to resume without gaps or duplicates;
- keep a path to rebuild state from events when upgrading; the public API compatibility policy does not guarantee cross-version checkpoint compatibility.
Long running streams¶
The streaming interface alone does not guarantee constant memory or unlimited numeric lifetime. The package-wide longevity audit exercises all built-in model families, transformers, drift detectors, evaluation, batching, and native FAISS. The bounds below assume fixed feature dimensions and constructor parameters; they describe retained observations and arrays, excluding exact lifetime counters.
| Implementations | Retained state and conditions |
|---|---|
ASDIsolationForest, HalfSpaceTrees, OnlineIsolationForest, RandomCutForest, StreamRandomHistogramForest, XStream |
Configured windows, trees, samples, or sketches. Large OnlineIsolationForest.learn batches are processed in bounded chunks, and retained rows own their storage. XStream(max_feature_cache_size=None) permits an unlimited feature-name cache; keep a finite cache budget for schema churn. |
MondrianIsolationForest |
Default lifetime trees can grow indefinitely. Set window_size=W for periodic replacement from the latest W events. Between replacements each tree represents at most 2W - 1 events; replacement has a bounded latency spike. This is periodic rebuilding, not exact per-event sliding-window deletion. |
KNN, LocalOutlierFactor, SDOStream, CellNeighborhoodDetector, StationaryRegionNeighborDetector |
Configured point windows, observer budgets, cells, and bounded indexes. A custom KNN engine owns its own retention policy. |
MStream, StreamingLODA, StreamingRSHash |
Fixed sketches, projections, histograms, and feature statistics. Novel values do not create a persistent key per value. |
MIDAS, ISCONNA, AnoEdgeL, SignedGraphSketchDetector |
Fixed sketches or configured active-graph budgets. Novel node/graph identities do not accumulate without eviction. |
GraphGatedOneClassSVM, IncrementalOneClassSVMAdaptiveKernel |
Fixed support-vector, feature-map, and neighborhood budgets. |
RollingMatrixProfile, MultivariateRollingMatrixProfile, XLagDAMP, SeasonalResidualDetector |
Configured rolling series, lag, season, and residual arrays. DAMP rejects constant subsequences. |
All ten univariate moving statistics, MovingCovariance, MovingCorrelationCoefficient, MovingMahalanobisDistance |
Configured observation windows and feature matrices. Exact rolling order statistics and moments operate on bounded histories. |
QuantileThreshold, ThresholdModel, NullModel, RandomModel |
Configured score window, fixed rule configuration, or generator state. |
OnlineAutoencoderEnsemble |
Fixed feature-map statistics and network weights; frozen and adaptive phases retain no observation history. |
Autoencoder, bundled feedforward/LSTM architectures |
Fixed tensor buffers, network parameters, gradients, and ordinary optimizer state. Supplied architectures, losses, and optimizers can have their own unbounded state or numeric failures. |
MinMaxScaler, StandardScaler, RollingRobustScaler |
State grows with distinct feature names. Place FeatureSchemaGuard first to enforce a finite schema. Robust windows are bounded per feature, not across an unlimited feature vocabulary. |
FeatureSchemaGuard, RandomProjection, IncrementalPCA |
Fixed schema/projection arrays. PCA retains only its first n0 events during initialization, then releases them. |
ADWIN, KSWIN, PageHinkley |
Default ADWIN uses O(log N) buckets on stationary streams; max_window_size bounds its represented history by discarding oldest whole buckets. KSWIN has a fixed window; Page-Hinkley uses scalar statistics. |
Pipeline, PrequentialEvaluator, BatchStreamer |
Pipeline retains components; evaluation retains at most metric_window_size labeled scores; batching retains at most batch_size events. Evaluation with metric_window_size=None explicitly retains O(N) scores when metrics are enabled. |
| NPZ loading, dataset cache, download and validation | NPZ iteration materializes the complete feature and label arrays. It is a finite benchmark source, not an out-of-core or infinite source. Downloads and hashing use bounded byte chunks; cached artifacts occupy disk. |
For bounded service operation, consume records incrementally, enforce a fixed
schema, use positive integer window/batch sizes, and keep both the input queue
and output sink bounded. iter_evaluate and BatchStreamer can consume infinite
generators lazily; evaluate returns only after its input ends. Close generators
when stopping early. Storing all outputs with list, or accepting arrivals faster
than processing, can exhaust application memory independently of model bounds.
Numeric limits remain observable even with bounded data retention:
- Exact Python counters occupy O(log N) bits; cumulative floating-point counts eventually lose unit precision. ISCONNA's fixed-width pattern counters saturate at the signed 64-bit maximum rather than wrapping negative.
StreamingRSHashnormalizes faded occupancy by a lifetime sample count. Its absolute scores can approach 1 on a long stationary stream with positive decay; calibrate against recent scores rather than assume a stationary scale.- Shared integer clocks and
MIDAS/ISCONNA/AnoEdgeLedge identifiers remain exact past2**53when supplied as Python/NumPy integers. The numeric identifiers inSignedGraphSketchDetectorand categorical vectors inMStreamstill use float64. Passing integers through float-valued preprocessing orPrequentialEvaluator's float event conversion loses that exactness. Supply integers directly to models when this matters. Floating timestamps cannot recover precision already lost by the caller. SDOStream's internal float64 observer timestamps still lose single-step age precision beyond2**53and reject values outside float64's finite range before changing model state. - A reproduced PyTorch Adam limitation is that a float32 step counter stops
advancing at
2**24updates. Finite loss and gradients also do not guarantee finite internal optimizer moments. The generic wrapper does not change the semantics of a caller-supplied optimizer. - FAISS float32 squared distances and some Euclidean/moment calculations can
overflow for large finite values. Raw distances, variances, gradients and
scores still require a representable numeric range. Standardize inputs at
ordinary magnitudes; cumulative sums in
StandardScaleralso have finite floating-point range.
The tests/test_stream_longevity_*.py suites cover long window turnover,
retained-object/NumPy storage bounds, released-history weak references, live
tracemalloc plateaus, score-only calls, lazy infinite inputs, and accelerated
large counters/timestamps. Strict expected-failure tests preserve reproduced
unresolved numeric limits. These are finite tests plus source-level state bounds,
not a proof of execution for infinitely many events, arbitrary parameter sizes,
custom components, devices, or every optional dependency build.
The audit includes CPU PyTorch and the real native FAISS index. On the tested
Windows installation FAISS required FAISS_OPT_LEVEL=generic and importing
faiss before the test runner to avoid intermittent native DLL initialization
failures. Native index sizes and FIFO scores were checked; native allocator leak
instrumentation and CUDA testing were unavailable.
Verified on 2026-10-08 with Windows, CPython 3.12.10, NumPy 2.3.5, SciPy 1.16.3, PyTorch 2.13.0 CPU, and FAISS 1.13.0: the complete unit and integration run finished with 1,963 passed, 109 passing subtests, 5 strict expected failures, and 1 CUDA skip. The four longevity suites contain 240 cases. Additional focused suites cover rejected ensemble events, timestamp representation, and integer-capacity contracts. The five expected failures reproduce FAISS/SDOStream/LOF extreme-value distance errors and the two external Adam limitations above; they are unresolved constraints. Ruff lint and formatting, mypy across 95 source files, wheel/sdist builds, and an isolated built-wheel import/bounded-mode smoke check also passed. Integration used a validated local SHUTTLE artifact; no dataset downloads were needed.
Deployment checklist¶
- Pin the feature schema, units, event-time policy, model constructor, and package version.
- Test first-event, warm-up-boundary, window-eviction, timestamp-tie, non-finite-input, and reset behavior.
- Run a chronological canary stream and compare the complete score sequence, not only an aggregate metric.
- Measure scoring/update latency and state growth at production dimensions.
- Log model readiness, raw score, threshold value, alert decision, event time, and model version without logging sensitive features unnecessarily.
- Define alert suppression, incident grouping, and operator feedback paths.
- Keep a rebuild path from trusted events because in-memory state is not a durable interchange format.