Skip to content

Seshat BI v0.8.2

Choose a tag to compare

@Kemetra Kemetra released this 06 Aug 12:05
· 368 commits to main since this release
14bd41e

Patch release. Full detail in docs/releases/v0.8.2.md and CHANGELOG.md.

Install

pipx install seshat-bi==0.8.2

Why upgrade

Trailing anomaly detection returned wrong answers. seshat analyze run with method.id: detect_anomalies and parameters.model: trailing_mad misclassified observations on v0.8.0 and v0.8.1. Nothing in the output signalled it: the run completed, wrote schema-valid evidence, and recorded outcome: computed. An installed user could not detect the defect from the tool and could not work around it. (PR #564)

_Baseline.residual already holds observed - center, but the flag compared residual - center against the threshold, so the deviation carried the series magnitude:

deviation = (observed - center) - center = observed - 2*center

On a level-112 series, a point sitting exactly on its own baseline center produced a deviation of -112 against a threshold of 5.19, and was flagged.

The misclassification runs in both directions, because the injected term is the baseline center:

  • False positives. Two-sided on a level series: on a synthetic 48-week fixture the defect flagged 23 of 23 evaluated weeks; the corrected engine flags 1, the single injected excursion.
  • False negatives. direction: upper with a positive center suppresses real excursions. For center 112, threshold 5.19, and a genuine deviation of +6, the correct comparison flags it while the defective comparison tests 6 - 112 = -106 and does not.

So this is not uniformly a fail-open. Depending on the declared direction and the series level, anomaly evidence from v0.8.0 or v0.8.1 may contain fabricated flags, missing flags, or both.

The seasonal_mad path masked the defect in testing, because it centers on STL residuals where the center is near zero. Only trailing_mad, which centers on raw values, scaled the error with the data.

The correction is not a single subtraction. The two baselines center on different quantities, so _Baseline now carries an explicit deviation computed per baseline: the trailing baseline's residual is its deviation, while the seasonal baseline's residual must still be taken relative to the residual center. Thresholding the seasonal residual directly would shift both two-sided and directional limits whenever the residual median is displaced from zero.

Two regression tests sit on the property rather than on an incidental number: a point at its own center is never anomalous, and adding a constant to every observation must not change any verdict.

Who is affected

Only callers of seshat analyze run with method.id: detect_anomalies and parameters.model: trailing_mad. The method needs the optional stats extra and a governed analysis specification citing an approved metric contract, so the reachable surface is narrow — but every such run on v0.8.0 or v0.8.1 returned untrustworthy flags.

Anyone who accepted anomaly evidence produced by v0.8.0 or v0.8.1 should re-run the analysis on v0.8.2 before citing it. The evidence files themselves remain readable; only the anomaly:<key> estimates were wrong.

Also in this release

  • Every closed-catalog method now has an end-to-end worked example. Coverage went from one method (describe) to all eight, adding docs/worked-examples/statistical-forecast.md and docs/worked-examples/statistical-catalog.md. Both publish only numbers produced by committed fixtures, and integration tests assert those numbers, so engine drift breaks a test instead of leaving a page quietly wrong.
  • The closed method catalog marks required and optional parameters separately. forecast requires all ten of its parameters, including final_period and partial_period_policy — the same two that are optional for detect_anomalies. A contract test reads schemas/statistical-analysis-spec.schema.json as ground truth and fails when the prose disagrees in either direction.
  • A Contributor Covenant code of conduct (PR #563), completing the repository community health profile.

Release machinery

The npm package is now published from the same release leg as PyPI, with publish-npm declaring needs: publish-pypi. That guarantees ordering, not atomicity: three packages publish sequentially — seshat-bi on PyPI, then @kemetra/seshat-bi, then the unscoped seshat-bi alias — and no publish can be undone. See the per-package recovery table in docs/releases/v0.8.2.md.

All three packages are confirmed published at 0.8.2 for this release.

Verification

  • pytest tests/unit tests/contract — 4859 passed, 21 skipped
  • pytest tests/integration/test_statistical_artifact_flow.py — 9 passed
  • ruff format --check src tests and ruff check src tests — clean