/** * The anomaly classifier over the D36 feature space. * * D18 deferred the algorithm until the feature space settled. It has, so this is * the first classifier: and the choice of algorithm is itself a decision worth * stating. * * **Why a distance-to-reference model rather than a learned one.** A learned * classifier needs labelled traffic, and D34 records that none exists: what the * project has is generated personas (D45), which are hypotheses about behavior * rather than ground truth. Training on them would produce a model that has * learned the author's assumptions and reports them back as findings. So this * classifier is explicitly *not* trained. It measures distance from a declared * reference profile, where every number in the profile is a policy an adopter is * expected to change. * * That keeps the property the rest of the library has: nothing here is a * discovered threshold presented as a fact. * * ponytail: weighted Manhattan distance against a fixed reference, no learning. * Upgrade path: once IXFE's real logs are labelled, fit the reference per * population and keep this as the cold-start default. */ import type { BehaviorFeatures } from './behavior.ts'; /** * The reference profile: what unremarkable human traffic is assumed to look like * on each feature, and how much a deviation on that feature counts. * * Only features whose deviation is *interpretable* are included. `count` and * `meanGapMs` are deliberately absent: volume is the farming problem (D49) and * belongs to the velocity check, and absolute gap length is what D42 refuses to * publish a threshold for. */ export type AnomalyReference = { /** Expected scope entropy for varied browsing. Deviation below counts. */ readonly scopeEntropy: number; /** Expected inter-arrival CV. Human traffic is bursty; deviation below counts. */ readonly interArrivalCv: number; /** Expected immediate-repeat ratio. Deviation above counts. */ readonly immediateRepeatRatio: number; /** Expected distinct scopes. Deviation below counts. */ readonly distinctScopes: number; }; export type AnomalyWeights = { readonly scopeEntropy: number; readonly interArrivalCv: number; readonly immediateRepeatRatio: number; readonly distinctScopes: number; }; /** * PoC reference. Every value is a guess, chosen leniently: a wrong number here * under-reports rather than manufacturing a finding. */ export declare const DEFAULT_REFERENCE: AnomalyReference; /** * Feature weights. Ordered by how hard the feature is to fake while still * accomplishing something: gap *shape* is the hardest, which is why the design * notes single it out, so it carries the most weight. */ export declare const DEFAULT_ANOMALY_WEIGHTS: AnomalyWeights; /** How many observations before a score means anything. */ export declare const MIN_OBSERVATIONS = 4; export type AnomalyScore = { /** * Distance from the reference profile in [0,1]. Higher is more unusual. * `undefined` when the window is too small to score, not the same claim as 0. */ readonly score: number | undefined; /** Per-feature contribution, for the trace. */ readonly contributions: Readonly>; /** Which feature contributed most. `undefined` when unscored. */ readonly dominant: keyof AnomalyReference | undefined; }; export type AnomalyOptions = { readonly reference?: AnomalyReference; readonly weights?: AnomalyWeights; readonly minObservations?: number; }; /** * Score behavior against the reference profile. * * One-sided per feature: only deviation in the *suspicious* direction counts. * Browsing more diversely than the reference is not anomalous, and a symmetric * distance would report it as such. */ export declare function anomalyScore(features: BehaviorFeatures, options?: AnomalyOptions): AnomalyScore; /** * Does the anomaly dimension concur that behavior is varied? D37. * * The classifier's answer to the question `diversityConcurs` currently answers * with three independent threshold comparisons. Both are kept: this one is a * single interpretable number, the other is the conjunction the D37 gate was * written against, and which reads better against real populations is not * something generated traffic can settle. */ export declare function anomalyConcurs(features: BehaviorFeatures, suspicionCeiling?: number, options?: AnomalyOptions): boolean | undefined; //# sourceMappingURL=anomaly.d.ts.map