NAME

Database::BI::Insights - Automatic statistical insights for Database::BI (Phase 5.2)

SYNOPSIS

use Database::BI::Insights;

my $insights = Database::BI::Insights::compute(
    records  => \@rows,
    columns  => \@cols,
    spec_key => 'table:sales',
    base_url => '/insights?l=table:sales',
);

DESCRIPTION

Pure-arithmetic insight detection. No LLM, no external service calls. Detects four classes of insight:

outlier

A value beyond the Tukey IQR fence (Q1 - 1.5*IQR or Q3 + 1.5*IQR).

period_delta

Overall period-over-period delta between the most recent two month-periods visible in a date column.

top_mover

The dimension member with the largest period-over-period absolute change. Requires at least one categorical column and one date column.

seasonality

Detected via lag-1 autocorrelation on monthly totals. A coefficient >= 0.6 is flagged. Requires at least 8 distinct month-periods.

Every insight includes a view_url that links to the chart or stats view showing the underlying data. An insight without a clickable view_url is a bug.

FUNCTIONS

compute(%args)

my $insights = Database::BI::Insights::compute(
    records  => \@rows,     # arrayref of row hashrefs
    columns  => \@cols,     # arrayref of column names
    spec_key => $l,         # l= spec string
    base_url => $url,       # request URL, used only as a fallback
);

Returns an arrayref of insight hashrefs. Each hashref has:

kind      -- 'outlier' | 'top_mover' | 'period_delta' | 'seasonality'
headline  -- one short sentence
detail    -- numbers that substantiate the headline
view_url  -- URL to the view showing the data
method    -- key for method_note()

method_note($key)

Returns a one-sentence description of the algorithm behind $key.

ALGORITHM NOTES

Outliers

Tukey IQR fence: Q1 - 1.5*IQR and Q3 + 1.5*IQR. Requires at least 4 values per group. Results are sorted by distance from the nearest fence; up to 5 outliers are reported per column.

Period-over-period

Year-month (YYYY-MM) buckets from ISO-8601 date columns. Requires at least 2 distinct periods.

Seasonality

Lag-1 autocorrelation r(1) on the sequence of period sums. Formula: r(1) = cov(y[t], y[t+1]) / var(y[t]). Threshold: r >= 0.6. Requires at least 8 distinct month-periods.

AUTHOR

Nigel Horne <njh@nigelhorne.com>

LICENCE AND COPYRIGHT

Copyright 2026 Nigel Horne.

Usage is subject to the GPL2 licence terms.