Changelog¶
All notable changes to Jitterbug are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased¶
2.3.0 - 2026-09-24¶
Added¶
- Zstandard (
.zst) input and output. A path ending in.zstis decompressed on read (jitterbug analyze rtts.csv.zst; the extension before.zstpicks the format) and compressed on write (--output results.json.zst,results.csv.zst, and the same inResultExporterandJitterbugAnalyzer.save_results). Newzstdextra (zstandard, only needed before Python 3.14, which hascompression.zstd), included inall..parquet.zstis rejected, since Parquet is already compressed. Seedocs/INPUT_FORMATS.md.
Changed¶
- Text inputs and outputs (CSV, scamper JSON, JSON and CSV results) are read and written as UTF-8 instead of the platform's default encoding.
2.2.0 - 2026-09-24¶
Added¶
- Non-sequential (clustering) analysis mode:
analysis_mode: clustering/jitterbug analyze --mode clustering. Minimum-RTT intervals are clustered by (minimum RTT, jitter IQR) with a Gaussian mixture (components chosen by BIC), k-means, or k-means with the silhouette-best k (clustering.algorithm,--clustering-algorithm); every cluster is compared with the lowest-latency one by latency jump and a KS test on raw jitter, wherever its intervals fall in time; a temporal smoothing (clustering.min_period_intervals, default 2) merges the per-interval verdicts into periods. Output is the usualCongestionInferenceResult, with aclusteringsummary in the metadata. On the PAM 2022 dataset the GMM recovers 15 of the 15 reference congestion periods; its 2 extra periods are at the two ends of the data, where the minimum RTT is elevated but the sequential reference cannot give a verdict (sequential BCP + KS: 14/15, 0 extra). Newclusteringextra (scikit-learn), included inall; guide indocs/CLUSTERING_MODE.md. The sequential mode stays the default and is unchanged. - Clustering mode:
clustering.min_ks_statistic(default 0.1) requires the KS statistic, not only the p-value, to show a jitter change. Clusters pool thousands of samples, so the p-value is significant for negligible differences (p < 1e-49 for every cluster of the PAM 2022 dataset, including one at the baseline's latency, whose statistic is 0.088; the congested clusters are at 0.21–0.32).clustering.latency_threshold(default:latency_jump.threshold) sets a latency threshold for this mode alone. Results on the PAM 2022 dataset are unchanged. - Documentation site built with MkDocs (Material theme): the guides in
docs/, an API reference generated from the docstrings, and the README, changelog, contributing guide and citation included from the root files. CI builds it with--strictand validatesCITATION.cffon every PR;.github/workflows/pages.ymlpublishes it to GitHub Pages frommain. Newdocsdependency group. - The documentation is online at https://estcarisimo.github.io/jitterbug/: README badge,
the
Documentationproject URL (shown on PyPI from the next release) and the repository website point to it.
Changed¶
- American English is now a documented convention (
AGENTS.md,CONTRIBUTING.md, the review brief). Existing British spellings in docs, comments, the changelog and one test name (test_unrecognizable_content_is_an_error) were corrected; no public function, method, option or message changed. - README: the extras table lists
jupyter.
2.1.1 - 2026-09-23¶
Added¶
.github/workflows/publish.yml: publishing a GitHub release uploads the tag's sdist and wheel to PyPI with Trusted Publishing (OpenID Connect, no stored token), after checking that the version matches the tag and smoke-testing the wheel, then attaches both files to the release. A manual run uploads an existing tag to TestPyPI or PyPI.
Changed¶
- README links and the figure use absolute GitHub URLs, so they work on the PyPI project page.
- First release on PyPI:
pip install jitterbug-inference. README (with a PyPI badge),docs/INSTALLATION.md,AGENTS.mdinstall instructions updated accordingly. CODE_OF_CONDUCT.md: incidents are reported privately through GitHub (maintainer profile, the repository's private reporting form, GitHub's Report content); the document no longer lists an email address.
2.1.0 - 2026-09-23¶
Maintenance release: the project is back to a maintainable state, with CI, a
protected main, tests, and only the components that work. Jitterbug is now a
library plus a CLI with two change point detectors (ruptures and the paper's
Bayesian bcp, now installed from PyPI as bayesian-changepoint); the REST API,
Docker image, experimental detectors and plotly dashboards described in 2.0.0 are
gone (see Removed). Python 3.10 or newer is required. The distribution is renamed
jitterbug-inference; installation is from GitHub, there is no PyPI release yet.
Added¶
- CLI tests for
validate(metrics table,--verbose, contract violations, missing file),config --template(YAML/JSON to stdout and round trip through a file) and the error paths ofanalyze(bad input, unknown method), completing the CLI coverage item of the roadmap. docs/INPUT_FORMATS.md: the input contract (columns, units, ordering, what is dropped and why) for CSV, scamper JSON, DataFrames and InfluxDB, linked from the README.- Unit tests for
analysis/(latency jumps, jitter dispersion, KS test, the congestion state machine) andio/(CSV, DataFrame, scamper JSON, format inference, mocked InfluxDB, validation, the JSON/CSV/summary exporters) on small synthetic series. Coverage 23 % → 84 %; CI now fails below 75 %. tests/test_paper_regression.py: golden counts for both detectors on the PAM 2022 dataset (ruptures + jitter dispersion: 22 periods / 11 congested; BCP + KS test: 34 / 14) and overlap-based agreement with the paper's reference intervals (11/15 and 13/15 recovered, no spurious detections). A dedicated CI job runs the Bayesian half with thebcpextra; Linux resolves torch from the CPU wheel index.tests/test_cli.py::test_visualize_writes_the_standard_plots: first test of the visualization code path (headless,MPLBACKEND=Agg).bcp_deviceoption inchange_point_detection(defaultcpu). The Bayesian library picks a GPU when it sees one, and on Apple Silicon that made the paper's configuration take over half an hour; on CPU it takes about two minutes. The value is validated (cpu,cudaormps), and a test with a mocked backend checks that it reaches both the likelihood and the detection call.get_available_algorithms()now reports only the detectors whose packages are installed (importlib.util.find_spec), with tests.- Continuous integration on GitHub Actions: ruff lint and format checks, mypy
(blocking since #19),
pip-auditover the locked dependency set, tests on Python 3.10–3.13 (Ubuntu) and 3.12 (macOS) with a CLI smoke test on the bundled PAM 2022 dataset, and a build job that installs the wheel in a clean environment. (#4) tests/test_cli.py: first tests for the command-line interface, run through Typer'sCliRunner. (#5)- Extras
rbeastandadtkfor the corresponding change point back ends, which the code already supported but no extra declared.bayesianis kept as a deprecated alias ofbcp. (#5) - Pre-commit configuration (ruff plus file hygiene hooks), Dependabot for GitHub
Actions and Python dependencies, and a committed
uv.lock. (#4) - Community and policy files:
SECURITY.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md,AGENTS.md,CITATION.cff,CODEOWNERS, issue and pull request templates.
Changed¶
- The
bcpextra now installs the Bayesian library from PyPI asbayesian-changepoint>=1.2(the import namebayesian_changepoint_detectionis unchanged), replacing the unmaintained upstream release and the git dependency used during development.gitis no longer needed to install any extra, and a wheel of Jitterbug no longer carries a direct URL dependency. The new release fixes the offline segment likelihoods and the detection performance: on the PAM 2022 dataset the paper's configuration (--algorithm bcp --method ks_test) runs in about four seconds end to end (under one second of detection) instead of two minutes, and yields 28 periods / 14 congested (was 34 / 14), recovering 14 of the paper's 15 congested intervals (was 13) with no spurious detections. Golden values, the example plots and summaries, and the timing notes in the docs are updated. The detector no longer passestruncate=-40, deprecated in 1.2; the exact sum is as fast and matches the truncated one to 1e-12 on the paper dataset. - The distribution is now named
jitterbug-inference([project] name); the import package and thejitterbugcommand are unchanged.jitterbugon PyPI belongs to an unrelated project, so this is the name a future PyPI release will use.jitterbug.__version__reads the metadata of the new distribution name. -
docs/INSTALLATION.mdrewritten: install from a clone with uv or pip, or directly from GitHub withpip install "jitterbug-inference[...] @ git+..."; the extras table; notes on thebcpextra; verification commands; a troubleshooting table of symptoms that actually occur. It anddocs/ALGORITHM_USAGE.mdsaidpip install jitterbug[...], which installs the unrelated project. -
README:
jitterbug visualizeis back in Usage (it was left out while broken, #7) anddocs/VISUALIZATION_USAGE.mdis in the documentation table; coverage figure refreshed. - Build backend requirement raised to
uv_build>=0.12.14,<0.13(Dependabot). Building from source with an olderuvCLI still works: it fetches the backend from PyPI. examples/README.mdandexamples/network_analysis/README.mdrewritten to match the directory: setup withuv sync --extra ..., the script and the notebooks as the two entry points, the dataset described (dates, sizes, what the paper found and what Jitterbug recovers), and the reference CSV layout explained. The example scripts no longer patchsys.path;results/and the benchmark outputs are ignored by git.- Code review policy: PRs are reviewed by an independent, fresh-context session
following
.github/REVIEW.md(today a Claude Sonnet subagent) instead of GitHub Copilot; merge requiresAPPROVEon the final commit.AGENTS.md,CONTRIBUTING.mdand the PR template updated. - Input validation happens once, at the edge, in
DataLoader.load_from_dataframe(CSV and InfluxDB go through it too): rows with a missing epoch or RTT, a non-positive RTT, or an RTT aboveMAX_RTT_MS(10 s) are dropped with a warning and counted inmetadata["dropped_rows"]; unsorted rows are sorted (stable) with a warning instead of being rejected; a non-numeric cell is aValueErrornaming the column and value. Before, the first bad row surfaced as a Pydantic error from inside the loading loop. The loop itself is vectorized: the bundled dataset loads in 0.1 s instead of 1 s. -
The scamper JSON reader applies the same RTT bounds per response: a
pingresponse with an RTT of 0 (a timeout) or above 10 s no longer makes the whole file fail with a Pydantic error; it is dropped with a warning and counted inmetadata["dropped_responses"]. -
Dependency floors raised to releases that support Python 3.10 (
numpy>=1.24,pandas>=2.0,scipy>=1.10,pydantic>=2.5,pydantic-settings>=2.1,ruptures>=1.1.9,typer>=0.12,rich>=13);clickandrequestswere declared but never imported and are no longer dependencies. banditruns in the CI lint job (clean at the time of writing).- mypy passes with
disallow_untyped_defson the whole package and is now a blocking CI check. Pydantic models usemodel_config = ConfigDict(...)/SettingsConfigDictandmodel_dump()instead of the deprecatedclass Config/.dict(); the two remaining test warnings are from third-party libraries. - README rewritten in the project's canonical layout: features, quick start, usage,
configuration, architecture, development, example output, citation. The table of
contents, the duplicated installation sections and the
pip install jitterbuginstructions are gone; every command was run before being documented. The REST API, Docker andvisualizecommand are not documented until they work (#6, #7). - Python 3.10 or newer is required (was 3.8). (#4)
- All temporary ruff ignores are gone except
B008(Typer'sOption(...)defaults):pathlibeverywhere (Path.open,/,mkdir,iterdir),raise ... frominside everyexcept, collapsed nested conditions, no line over 100 characters.tools/scripts no longer patchsys.pathto a directory that does not exist. Behavior unchanged (CLI output on the bundled dataset is identical). pyproject.tomlis the single source of packaging metadata;setup.py,requirements.txt,requirements-new.txtandinstall_dev.share gone. The build backend isuv_build. Development tools live in thedevdependency group, souv syncinstalls them. (#5)jitterbug.__version__and the API's reported version are read from package metadata instead of hard-coded strings. (#5)- Code style is enforced by ruff (line length 100) instead of black, isort and flake8;
type annotations use the Python 3.10 syntax (
X | None,list[str]). (#4) - The Docker image installs from
pyproject.toml. (#5)
Fixed¶
- A file with an unknown extension whose content is not text raises the documented
ValueError("Cannot infer format ...")instead of leakingUnicodeDecodeError. load_from_influxdbcomputed epochs asastype(int) / 1e9, which assumes nanosecond timestamps; pandas 3 parses_timeat microsecond resolution, so every epoch was 1000× too small. The conversion is now resolution-independent. Found by running the mocked InfluxDB tests in CI, where theinfluxextra is absent (a stub module now stands in for it).verbose: truein a configuration file had no effect from the CLI: the command installs a logging handler before reading the file, and the analyzer's secondbasicConfigwas a no-op. The analyzer now sets thejitterbuglogger level.- The two analysis notebooks in
examples/run again: they importedrequests(no longer a dependency), read fields that do not exist on the result models (start_time,confidence_score,jitter_ratio,ks_statistic), and their "REST API" sections exercised the server removed in this release. Executed end to end withnbconvertbefore committing. - Change point timestamps are timezone-aware UTC, like the measurements they come from.
They used to be naive local time, so
start_timestamp/end_timestampin results files and the CLI table depended on the machine's timezone (the epochs were always right). The CLI table columns are now labeledStart (UTC)/End (UTC). DataLoader.validate_data()returns plain Python numbers and booleans (it used to return numpy scalars, whichjson.dumpsrejects); CSV datasets recordsource: csvand the file path in their metadata;.jsonlis recognized as scamper JSON.jitterbug analyzeandjitterbug visualizeno longer overwrite thealgorithm,method,thresholdandoutput_formatvalues of a--configfile with the CLI's own defaults; a flag now overrides the file only when it is given explicitly. A wrong--algorithmvalue is rejected with Pydantic's message instead of failing later.jitterbug visualizeworks again: it now writes the five matplotlib figures throughJitterbugPlotter.save_all_plotsand prints the summary. It used to abort with'CongestionInference' object has no attribute 'timestamp'(#7). The--static-only/--interactive-onlyflags are gone;--prefixis new. When the analysis yields no inferences the confidence heatmap is an empty placeholder instead of animshowerror, so the command still writes its five files.- Time axes in every plot use matplotlib's automatic date locator and concise formatter instead of one labeled tick per hour, which produced an unreadable axis on multi-day series.
- The Bayesian detector no longer swallows exceptions and returns "no change points";
a failure is raised as
RuntimeErrorwith the cause attached. JitterbugAnalyzer.analyze()returns the samemetadatakeys (total_measurements,min_intervals,change_points) on its early-return paths as on the full path. (#3)- Test suite: eight assertions that had drifted from the code, and five tests that failed during the last fifteen minutes of every hour. (#3)
Removed¶
examples/basic_analysis.py(synthetic two-hour series on which nothing is detected) andexamples/output_formats_demo.py(600 lines, crashed on a PyYAML argument, still used Pydantic v1.dict()).examples/network_analysis/basic_analysis.pyis the script example.- The
influxfile format:--format influxand.flux/.influxfiles were routed to a placeholder that raisedNotImplementedError. Loading from an InfluxDB server throughDataLoader.load_from_influxdb()is unchanged. Format inference now fails with a clear message instead of guessinginfluxfor anything it does not recognize. - Dead code in
analysis/:LatencyJumpAnalyzer.analyze_detailed,CongestionInferenceAnalyzer._apply_inference_logicand_post_process_inferencesimplemented alternative rules that nothing called. - The plotly dashboard and interactive modules (
visualization/dashboard.py,visualization/interactive.py), theplotlydependency,examples/visualization_demo.pyand the generatedinteractive_bcp_ks/timeline.html. They had no tests, the dashboard crashed on every real result (#7), and the demo called a method that does not exist.docs/VERSION_COMPARISON.md, a 1.x-versus-2.x page that described all of the removed components as features, is gone too. - The experimental
torch,rbeastandadtkdetectors and their extras. None of them was evaluated in the paper;torchwas a heuristic rather than a trained model, andrbeast/adtksilently fell back to an internal statistical method when their package was missing while still labeling the output with the back end's name. The detectors are nowruptures(default) andbcp.algorithms.pyshrinks from 1 215 to 318 lines;examples/interactive_algorithm_selector.pyand the stale plots for the removed detectors are gone, andexamples/network_analysis/plots/was regenerated (BCP 14/15, ruptures 11/15, unchanged). - The REST API server and the Docker image.
jitterbug.api, theapiextra, theDockerfile,docker-compose.yml, the entrypoint script,docs/DOCKER.mdand the two related examples are gone. The server had not been able to start since the 2.0 rewrite (create_app()raised on import and/analyzecalled a method that did not exist, #6), had no tests, and the Docker image's only entrypoint was that server. Jitterbug is a library and a CLI; wrap it in your own service if you need HTTP. - The DockerHub push, PyPI publish and Codecov upload jobs from CI; none of them had working credentials. (#4)
- The
print-based smoke scriptstest_algorithms.pyandexamples/test_new_implementation.py, replaced by real tests. (#5)
2.0.0 - 2025-07-19¶
Complete rewrite of the PAM 2022 framework: Pydantic models, five change point detection back ends (ruptures, BCP, PyTorch, Rbeast, ADTK), CSV/JSON/InfluxDB input, Typer CLI, optional REST API and visualization modules. See the pull request.
1.0.0 - 2024-03-18¶
Original implementation accompanying the paper Jitterbug: A new framework for jitter-based congestion inference (PAM 2022).