Warning codes
Structured WarningCode payloads attached to every
EvaluationResult.warnings. Use these as the SSOT
when you need to filter, route, or trigger downstream behaviour from
factrix output without parsing free-text strings.
WarningCode— risk flags surfaced onEvaluationResult.warnings. Does not affectMetricResult.p_value; the user decides whether to pre-filter on warnings before multi-factor Benjamini-Hochberg-Yekutieli (BHY).
Each member's trigger / meaning is sourced from
factrix._codes.WarningCode.description (single source of truth, also
surfaced at runtime on each result's warnings). For the per-procedure
breakdown of which codes a given pipeline can emit, see
Architecture § Procedure pipelines.
The scalar statistics that populate EvaluationResult.metrics are not
enum-keyed — each MetricResult exposes its statistic on
MetricResult.stat with stat_type / h0 / method in
MetricResult.metadata; see Stat keys by metric.
WarningCode¶
| WarningCode | Trigger / meaning |
|---|---|
unreliable_se_short_periods |
n_periods is below the WARN floor (~30); NW HAC SE may be biased. Reused across panel time-series guards (MIN_PERIODS_WARN) and primitive inference (MIN_FM_PERIODS_WARN); both default to 30. |
event_window_overlap |
Adjacent events sit within forward_periods; AR windows overlap. |
persistent_regressor |
ADF p exceeds the configured threshold on the continuous factor; beta may carry Stambaugh bias. |
serial_correlation_detected |
Ljung-Box p < 0.05 on residuals; NW lag may be under-set. |
few_assets |
Cross-section asset count is below the relevant WARN floor (panel-wide MIN_ASSETS_WARN=30, per-date MIN_IC_ASSETS_WARN=10, or per-date MIN_FM_ASSETS_WARN=10). The statistic is returned, but small n_assets inflates critical values or leaves minimal residual degrees of freedom. Severity scales with n_assets; read the relevant n_assets metadata. A by-design few-asset study declares the regime once via evaluate(..., expected_warnings=('few_assets',)): the record is kept and marked expected=True, and the per-run UserWarning echo stops. |
thin_quantile_groups |
quantile_spread with the median cross-section split into n_groups buckets leaving < MIN_GROUP_ASSETS (5) assets per bucket; each bucket mean rests on a handful of names so the spread can be dominated by individual assets. Advisory only — reduce n_groups (the warning suggests a value) or treat the spread as a fragile small-cross-section diagnostic. Distinct from few_assets, which keys off the absolute cross-section size. |
sparse_magnitude_weighted |
Sparse factor column is mixed-sign and not a clean ±1 ternary; statistic is magnitude-weighted (Sefcik-Thompson) rather than textbook MacKinlay signed CAAR — apply .sign() before calling for sign-flip semantics. |
few_events |
CAAR significance test with MIN_EVENTS_HARD ≤ n_event_periods < MIN_EVENTS_WARN (4..29). caar is an equal-weight calendar-time portfolio across event periods, so this counts the number of periods with an event, not events; a sub-30 series is power-thin for the asymptotic t-distribution — read borderline p-values cautiously. |
borderline_portfolio_periods |
top_concentration with MIN_PORTFOLIO_PERIODS_HARD ≤ n_periods < MIN_PORTFOLIO_PERIODS_WARN (3..19); one-sided t-test on the per-date diversification ratio is returned but df=n-1 inflates t_crit relative to the asymptotic cutoff. |
few_directional_pairs |
directional_hit_rate with MIN_DIRECTIONAL_PAIRS_HARD ≤ n_pairs < MIN_DIRECTIONAL_PAIRS_WARN (10..29); the Pesaran-Timmermann hit rate is returned but n counts pooled non-overlapping (date, asset) directional trials, and the normal approximation to S_n is power-thin below ~30 pooled pairs — read borderline p-values cautiously. Below the HARD floor the metric short-circuits to NaN. |
few_ordering_pairs |
directional_pair_accuracy with MIN_PAIR_ACCURACY_PAIRS_HARD ≤ n_pairs < MIN_PAIR_ACCURACY_PAIRS_WARN (10..29); the descriptive ordering accuracy is returned but n counts pooled non-overlapping within-date asset pairs after factor/return ties are removed. Below the HARD floor the metric short-circuits to NaN. |
rect_kernel_negative_variance |
Rectangular-kernel HAC variance-of-mean came out negative (no PSD guarantee, Andrews 1991); clamped to 0 → SE=0, t=0, p=1.0. Fires only on short / mildly anti-correlated samples. |
bmp_return_vol_fallback |
bmp_z ran without a price column: the estimation-window volatility falls back to the per-asset rolling std of forward_return, lagged by forward_periods so it ends before the event's forward window. This is a coarser, horizon-overlapping vol proxy than a daily-price std — supply price for the clean BMP standardiser. |
upstream_unavailable |
DAG-executor consumer skipped because an upstream producer short-circuited. The downstream MetricResult carries metadata['upstream'] / ['upstream_reason'] for the original cause. |
metric_unavailable |
Metric short-circuited on its own precondition (missing input column / config, or insufficient sample at its own floor); the NaN MetricResult's metadata['reason'] carries the specific cause. Distinct from UPSTREAM_UNAVAILABLE, which flags a dependency failure. |
structure_mismatch |
Metric's declared factor cell (scope / density / data structure) does not match the detected factor cell; under strict=False the metric short-circuits to NaN instead of executing. |
low_cardinality_dense_signal |
Dense factor has few distinct non-null values but no sparse event contract. Sparse event metrics require the {0, R} zero-value event contract and a sparse_ratio above the routing threshold; always-in-market states such as {-1, +1} stay dense and should use dense / directional metrics. |
frequent_event_signal |
Sparse event metric explicitly ran on a factor with zero-valued rows but sparse_ratio below the automatic SPARSE routing threshold. The metric treats zeros as non-events; confirm that zero encodes the intended event contract. Events are frequent, so read event-study inference cautiously and inspect clustering / overlap diagnostics. |
cross_factor_density_mismatch |
Factor columns carry inconsistent FactorDensity (dense and sparse mixed). |
cross_factor_scope_mismatch |
Factor columns carry inconsistent FactorScope (individual and common mixed). |
single_asset_event_data |
Single-asset event-shaped data (TIMESERIES + SPARSE, n_assets=1): event-axis metrics run over the event cross-section (n_events) and are usable on a single name. Metrics that need the asset cross-section — same-date event clustering (clustering_hhi) is degenerate at one event per date — need n_assets>=2 and are unavailable. Do not pool unrelated assets to clear this; that mixes return-generating processes. |
excessive_period_drops |
An upstream PANEL→SERIES primitive dropped more than DROP_RATE_WARN_THRESHOLD of dates at its cross-sectional filter; the metric was computed on a shortened sample. Exact counts are in MetricResult.metadata (n_periods_in / n_periods_out / dropped_periods / drop_rate / drop_reason). |
excessive_asset_drops |
An upstream primitive dropped more than DROP_RATE_WARN_THRESHOLD of assets at its per-asset filter (e.g. compute_common_betas dropping assets with insufficient history or zero factor variance); the cross-asset aggregate was computed on a shortened sample. Exact counts are in MetricResult.metadata (n_assets_in / n_assets_out / dropped_assets / drop_rate / drop_reason). |
slice_boundary_truncation |
by_slice partitioned a panel on a date-axis column (one whose value varies within an asset over time, e.g. calendar year or regime label) while the metric declares MetricSpec.slice_boundary_sensitive (a capability of the estimator, not inferred from its aggregation category). Each slice is evaluated on its own rows, so a rolling window / per-asset time-series regression / event window sees truncated history at the slice boundary — the per-slice value differs from the full-sample value decomposed by period. Metrics that don't declare the flag and cross-sectional partitions (constant within an asset, e.g. sector) are unaffected and do not trigger. |