Seshat BI v0.8.2
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: upperwith a positive center suppresses real excursions. For center112, threshold5.19, and a genuine deviation of+6, the correct comparison flags it while the defective comparison tests6 - 112 = -106and 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, addingdocs/worked-examples/statistical-forecast.mdanddocs/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.
forecastrequires all ten of its parameters, includingfinal_periodandpartial_period_policy— the same two that are optional fordetect_anomalies. A contract test readsschemas/statistical-analysis-spec.schema.jsonas 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 skippedpytest tests/integration/test_statistical_artifact_flow.py— 9 passedruff format --check src testsandruff check src tests— clean