Production diff-detective: when something breaks, what actually changed?
Project description
WhyChanged (whychanged)
Production diff-detective. When monitoring tells you something broke, what actually changed?
Why
Production incidents almost always trace back to something that happened in the recent past — a deploy, a feature-flag toggle, a config push, a dependency bump. But your dashboards tell you what's broken, not why. WhyChanged correlates change sources in a time window around an incident and ranks them by likelihood of having caused it.
Status
v0.1.0 beta. Ships the engine + a local Git change provider + the GitHub Deployments cloud provider. Other cloud plugins (LaunchDarkly, Render, Vercel, ArgoCD, Kubernetes events) land in v0.2+.
What v0.0.1 does
- Asks every configured
ChangeProviderfor changes in the requested window. - Scores each change with a deterministic heuristic:
- Recency — exponential decay relative to the incident time (30-min half-life)
- File scope — bonus when a change touches files that belong to the affected service
- Kind weight — schema migrations and config changes outscore feature-flag toggles when all else is equal
- Sorts by score and emits a JSON + Markdown report.
CLI
whychanged version
# Rolling 30-minute window from now
whychanged explain --repo .
# Explicit incident time + service scope
whychanged explain --repo . \
--since 1h \
--incident-at 2026-05-08T14:30:00+00:00 \
--service api \
--service-file src/api/models.py \
--service-file src/api/views.py
# v0.1: combine local commits with GitHub Deployments events
export WHYCHANGED_GITHUB_TOKEN=ghp_...
whychanged explain --repo . \
--since 2h \
--github-repo myorg/api \
--github-environment production
Output: .whychanged/report.json (versioned, machine-consumable) + .whychanged/report.md (human companion).
Change kinds
| Kind | Source examples |
|---|---|
deploy |
Git commit on main, container release, cloud build |
feature-flag |
LaunchDarkly / Statsig / homegrown flag toggle |
config |
Kubernetes ConfigMap, env-var change, infra apply |
dependency |
package.json / requirements update, image bump |
schema |
Database migration / schema change |
unknown |
Catch-all for unclassified providers |
Roadmap
- v0.2 — GitHub App installation-token auth + incident-aware webhook receiver: post the top culprit to Slack / Datadog
- v0.2 — outcome-trained ranker (replaces the deterministic heuristic with a learned model once we have "was the top rank actually the culprit?" data)
- v0.3 — service-graph integration (rank higher when a change is upstream of the affected service)
Apache-2.0 license. See CHANGELOG.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file devtrust_whychanged-0.1.0.tar.gz.
File metadata
- Download URL: devtrust_whychanged-0.1.0.tar.gz
- Upload date:
- Size: 19.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3156c8ad60a18cf981e2c2aa0e14f1dc802670e18600325c22c1e2f36c5f275e
|
|
| MD5 |
3150cfc803b8002d96369d076d8bbbe1
|
|
| BLAKE2b-256 |
730a1ad550723d798f1083d23091a409192165a2e51a8d0578496464af6dcca3
|
Provenance
The following attestation bundles were made for devtrust_whychanged-0.1.0.tar.gz:
Publisher:
release.yml on AbdullahBakir97/DevTrust
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
devtrust_whychanged-0.1.0.tar.gz -
Subject digest:
3156c8ad60a18cf981e2c2aa0e14f1dc802670e18600325c22c1e2f36c5f275e - Sigstore transparency entry: 1486553464
- Sigstore integration time:
-
Permalink:
AbdullahBakir97/DevTrust@c6fc601fa074dc0135f1b9a7b5e46360ec1d9d4e -
Branch / Tag:
refs/tags/devtrust-whychanged-v0.1.0 - Owner: https://github.com/AbdullahBakir97
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c6fc601fa074dc0135f1b9a7b5e46360ec1d9d4e -
Trigger Event:
push
-
Statement type:
File details
Details for the file devtrust_whychanged-0.1.0-py3-none-any.whl.
File metadata
- Download URL: devtrust_whychanged-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
423dde37755d18a4b5f595d527bc64a3d70972d65f0d08ffb7d84de890e36905
|
|
| MD5 |
2935b8b3d46917551764dc7a20d91420
|
|
| BLAKE2b-256 |
67181040da8b4ad1a2105fb421e9c7cb9f698a4aff4196b8fe07b08abe88413b
|
Provenance
The following attestation bundles were made for devtrust_whychanged-0.1.0-py3-none-any.whl:
Publisher:
release.yml on AbdullahBakir97/DevTrust
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
devtrust_whychanged-0.1.0-py3-none-any.whl -
Subject digest:
423dde37755d18a4b5f595d527bc64a3d70972d65f0d08ffb7d84de890e36905 - Sigstore transparency entry: 1486553558
- Sigstore integration time:
-
Permalink:
AbdullahBakir97/DevTrust@c6fc601fa074dc0135f1b9a7b5e46360ec1d9d4e -
Branch / Tag:
refs/tags/devtrust-whychanged-v0.1.0 - Owner: https://github.com/AbdullahBakir97
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c6fc601fa074dc0135f1b9a7b5e46360ec1d9d4e -
Trigger Event:
push
-
Statement type: