blot-git 0.4.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {blot_git-0.4.0 → blot_git-0.5.0}/.pre-commit-hooks.yaml +1 -1
- blot_git-0.5.0/CLAUDE.md +60 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/PKG-INFO +1 -1
- {blot_git-0.4.0 → blot_git-0.5.0}/README.md +2 -2
- {blot_git-0.4.0 → blot_git-0.5.0}/action.yml +1 -1
- {blot_git-0.4.0 → blot_git-0.5.0}/bench/README.md +24 -0
- blot_git-0.5.0/bench/RESULTS.md +82 -0
- blot_git-0.5.0/bench/cases.json +412 -0
- blot_git-0.5.0/bench/labels/django-django.json +646 -0
- blot_git-0.5.0/bench/labels/expressjs-express.json +96 -0
- blot_git-0.5.0/bench/labels/facebook-react.json +616 -0
- blot_git-0.5.0/bench/labels/pallets-flask.json +56 -0
- blot_git-0.5.0/bench/labels/psf-requests.json +86 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/docs/PRD.md +1 -1
- {blot_git-0.4.0 → blot_git-0.5.0}/pyproject.toml +1 -1
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/__init__.py +1 -1
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/bench.py +62 -3
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/checks/cochange.py +12 -1
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/checks/removed_fix.py +2 -1
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/classify.py +9 -7
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/cli.py +10 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/diff.py +6 -2
- {blot_git-0.4.0 → blot_git-0.5.0}/tests/test_bench.py +31 -4
- {blot_git-0.4.0 → blot_git-0.5.0}/tests/test_checks.py +16 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/tests/test_classify.py +8 -0
- blot_git-0.4.0/bench/RESULTS.md +0 -73
- blot_git-0.4.0/bench/cases.json +0 -83
- {blot_git-0.4.0 → blot_git-0.5.0}/.gitattributes +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/.github/ISSUE_TEMPLATE/bench_case.md +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/.github/ISSUE_TEMPLATE/check_idea.md +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/.github/pull_request_template.md +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/.github/workflows/blot.yml +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/.github/workflows/ci.yml +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/.github/workflows/release.yml +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/.gitignore +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/CONTRIBUTING.md +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/LICENSE +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/demo/demo.gif +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/demo/make_demo.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/blue/alert.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/blue/faces.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/blue/happy.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/blue/idle.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/blue/sad.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/blue/sleepy.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/blue/walk.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/blue/worried.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/build_sprites.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/mustard/alert.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/mustard/faces.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/mustard/happy.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/mustard/idle.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/mustard/sad.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/mustard/sleepy.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/mustard/walk.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/mustard/worried.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/orange/alert.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/orange/faces.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/orange/happy.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/orange/idle.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/orange/sad.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/orange/sleepy.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/orange/walk.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/orange/worried.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/sage/alert.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/sage/faces.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/sage/happy.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/sage/idle.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/sage/sad.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/sage/sleepy.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/sage/walk.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/assets/sora/sage/worried.svg +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/docs/EXPLAINER.md +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/docs/PYPI.md +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/docs/competitors.md +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/__main__.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/checks/__init__.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/checks/base.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/checks/readded_bug.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/config.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/git.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/github.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/hooks.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/index.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/report.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/store.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/trace.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/src/blot/why.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/tests/conftest.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/tests/test_action.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/tests/test_cli.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/tests/test_config.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/tests/test_diff.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/tests/test_git.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/tests/test_hooks.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/tests/test_index.py +0 -0
- {blot_git-0.4.0 → blot_git-0.5.0}/tests/test_why_github.py +0 -0
blot_git-0.5.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Blot: notes for Claude
|
|
2
|
+
|
|
3
|
+
Blot is a pre-commit check that has read a repo's git history. It warns (never blocks) when a commit
|
|
4
|
+
removes a fix (`removed-fix`), re-adds a line a fix removed (`readded-bug`), or forgets a file that
|
|
5
|
+
always changes with another (`forgot-related-file`). Mascot: Sora the slime. Owner: Shyam (GitHub
|
|
6
|
+
`Sym-jay`). PyPI name `blot-git`, command `blot`. Repo: https://github.com/Sym-jay/Blot
|
|
7
|
+
|
|
8
|
+
## Layout
|
|
9
|
+
- `src/blot/`: stdlib-only on Python 3.11+ (3.10 also needs `tomli`; keep it that way)
|
|
10
|
+
- `cli.py` commands: index, check, why, install-hook, bench. `check`/`why` build/refresh the index themselves.
|
|
11
|
+
- `index.py` builds `.git/blot.db` (parallel `git log` slices for 2000+ commits); `store.py` SQLite schema v2
|
|
12
|
+
- `classify.py` fix severity 0/1/2 + refactor detection: most precision lives here
|
|
13
|
+
- `checks/` one file per check; `trace.py` blame that follows lines past refactor commits
|
|
14
|
+
- `why.py`, `github.py` (`index --github` via `gh api graphql`), `bench.py` (cases + `--replay N`)
|
|
15
|
+
- `bench/cases.json` scripted real-world cases (30/30); `bench/labels/` hand verdicts for every replay
|
|
16
|
+
warning on the 5 reference repos; `bench/RESULTS.md` replay numbers and precision
|
|
17
|
+
- `action.yml` GitHub Action; `.github/workflows/blot.yml` runs it on Blot's own PRs
|
|
18
|
+
- `assets/sora/build_sprites.py` and `assets/demo/make_demo.py` regenerate the mascot and demo GIF
|
|
19
|
+
- `docs/PRD.md` roadmap; `docs/PYPI.md` is the PyPI page (no relative images there)
|
|
20
|
+
|
|
21
|
+
## Develop
|
|
22
|
+
```bash
|
|
23
|
+
python -m venv .venv && .venv/Scripts/python -m pip install -e ".[dev]"
|
|
24
|
+
.venv/Scripts/python -m pytest -q
|
|
25
|
+
.venv/Scripts/blot bench --workdir <short path> # must stay 30/30
|
|
26
|
+
```
|
|
27
|
+
- Any change to `classify.py` or a check: on each of the 5 clones, checked out at the `head` in its
|
|
28
|
+
labels file, run `blot bench --replay 500 --labels bench/labels/<repo>.json --update-labels`. Keep a
|
|
29
|
+
rule only if precision rises and no `useful` warning disappears; label any new `null` verdicts
|
|
30
|
+
(rules in bench/README.md). Targets: ≤ 1 warning / 10 commits, precision ≥ 80%.
|
|
31
|
+
- Clones live in `%LOCALAPPDATA%\Temp\wl\replay\` (labelled heads) and `...\wl\bench\` (case runs).
|
|
32
|
+
- `blot check` must stay under ~500 ms and never fail a commit because of Blot's own errors.
|
|
33
|
+
|
|
34
|
+
## Release (each release so far followed this)
|
|
35
|
+
1. Branch, bump `version` in `pyproject.toml` and `src/blot/__init__.py`, PR, wait for CI (6 jobs + "blot").
|
|
36
|
+
2. Squash-merge, then `gh release create vX.Y.Z --target main`: `.github/workflows/release.yml`
|
|
37
|
+
publishes to PyPI via trusted publishing. PyPI/pip can lag a minute or two after publish.
|
|
38
|
+
3. Verify: fresh venv, `pip install blot-git==X.Y.Z`, run `blot why src/flask/app.py:355` on a Flask clone.
|
|
39
|
+
|
|
40
|
+
## Conventions
|
|
41
|
+
- Work on a branch, open a PR, merge only when the owner says so. Squash-merge.
|
|
42
|
+
- No `Co-Authored-By` trailer in commits or PRs (the owner's choice); PR bodies end with the Claude Code line.
|
|
43
|
+
- Contributors (e.g. O1sumitkumar) should comment on the issue before starting a PR.
|
|
44
|
+
- Never claim results that weren't run; label replay findings honestly (e.g. the Express
|
|
45
|
+
CVE-2024-51999 advisory was later withdrawn, so its revert was deliberate).
|
|
46
|
+
|
|
47
|
+
## Windows gotchas (this machine)
|
|
48
|
+
- Long paths: clone big repos and make venvs under a short path like `%LOCALAPPDATA%\Temp\wl\`.
|
|
49
|
+
- The user folder has a space ("N Jayasankar"): quote paths; don't word-split commands in loops.
|
|
50
|
+
- Writing code through bash heredocs mangles `\b`, `\n`, `\s`: use the Edit tool for regexes/strings.
|
|
51
|
+
- `gh api` paths: no leading slash (Git Bash rewrites it).
|
|
52
|
+
|
|
53
|
+
## State (2026-10-28)
|
|
54
|
+
- Released 0.5.0: checks, `why`, `--github`, bench/replay with labels, parallel indexing, pre-commit
|
|
55
|
+
framework support (`rev: v0.5.0`), GitHub Action (`uses: Sym-jay/Blot@v0.5.0`).
|
|
56
|
+
- Launch: dev.to post published 2026-10-24; the CVE sentence there should mention the withdrawn advisory.
|
|
57
|
+
- Open issues: #2–#6 (bench cases for Django, Express, React, requests, Flask).
|
|
58
|
+
- Precision (0.5.0, measured 2026-10-30): 57/109 useful (52%); Django 1.19 / 10 commits, others ≤ 0.6.
|
|
59
|
+
`forgot-related-file` has 0 useful warnings in 45 labelled; candidate to become opt-in.
|
|
60
|
+
- Next: remaining noise (renames, API swaps, added arguments, docstrings) in bench/RESULTS.md.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: blot-git
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: A pre-commit check that has read your project's history: warns when a change removes a fix, re-adds a fixed bug, or forgets a file that always changes too.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Sym-jay/Blot
|
|
6
6
|
Project-URL: Issues, https://github.com/Sym-jay/Blot/issues
|
|
@@ -22,7 +22,7 @@ It runs locally, needs no account or AI, and stays quiet unless the history give
|
|
|
22
22
|
|
|
23
23
|
*A real run on Flask. Plain `git blame` points to a 2023 commit that only moved this line; Blot traces past it to the 2020 fix that explains it. (Regenerate with `python assets/demo/make_demo.py`.)*
|
|
24
24
|
|
|
25
|
-
> **Status:** pre-alpha. Milestones M1 and M2 are done: `blot index` builds the history index (Flask's 3,800 commits in ~2 s), `blot install-hook` wires up git, and `blot check` runs the three checks. On Flask it traces an edit to `self_ref = weakref.ref(self)` past the 2023 file split to the 2020 fix, in under 500 ms. Replayed on the last 500 commits of Flask, requests, Express, Django and React, it warns on 0.6–
|
|
25
|
+
> **Status:** pre-alpha. Milestones M1 and M2 are done: `blot index` builds the history index (Flask's 3,800 commits in ~2 s), `blot install-hook` wires up git, and `blot check` runs the three checks. On Flask it traces an edit to `self_ref = weakref.ref(self)` past the 2023 file split to the 2020 fix, in under 500 ms. Replayed on the last 500 commits of Flask, requests, Express, Django and React, it warns on 0.6–9.5% of commits, and about half of its warnings (57 of 109, each labelled by hand) are worth a reviewer's time; see [bench/RESULTS.md](bench/RESULTS.md). Roadmap: [PRD](docs/PRD.md#12-milestones-4-weeks-part-time).
|
|
26
26
|
|
|
27
27
|
## Meet Sora
|
|
28
28
|
|
|
@@ -91,7 +91,7 @@ jobs:
|
|
|
91
91
|
blot:
|
|
92
92
|
runs-on: ubuntu-latest
|
|
93
93
|
steps:
|
|
94
|
-
- uses: Sym-jay/Blot@v0.
|
|
94
|
+
- uses: Sym-jay/Blot@v0.5.0
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
The action checks out the pull request with its full history, installs Blot, runs `blot index` and
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Run Blot on a pull request and show its findings as warning annotations.
|
|
2
2
|
# Usage (in a workflow triggered by pull_request):
|
|
3
|
-
# - uses: Sym-jay/Blot@v0.
|
|
3
|
+
# - uses: Sym-jay/Blot@v0.5.0
|
|
4
4
|
# See "Use in CI" in README.md.
|
|
5
5
|
name: Blot
|
|
6
6
|
description: History-aware checks on the commits of a pull request, shown as warning annotations
|
|
@@ -38,5 +38,29 @@ using only the history that existed before it. It prints how many commits would
|
|
|
38
38
|
and lists every warning, so you can label each one as useful or noise. Noise patterns become fixes in
|
|
39
39
|
`classify.py` or the checks, plus a quiet case here so they never come back.
|
|
40
40
|
|
|
41
|
+
### Labels: precision you can re-measure
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
cd ~/wl/flask && git checkout <head from the labels file>
|
|
45
|
+
blot bench --replay 500 --labels path/to/Blot/bench/labels/pallets-flask.json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`bench/labels/` holds a hand verdict for every replay warning on the five reference repos. With
|
|
49
|
+
`--labels`, replay prints `precision: X useful / Y labelled` and marks each warning `[useful]`,
|
|
50
|
+
`[noise]` or `[?]`. Add `--update-labels` to append new, unlabelled warnings (`"verdict": null`) to the
|
|
51
|
+
file, then fill them in. Labels match on commit, check, path and the commit the warning cites, so
|
|
52
|
+
they survive small line-number drift. Replay at the `head` the file records, or the commits differ.
|
|
53
|
+
|
|
54
|
+
How to label:
|
|
55
|
+
|
|
56
|
+
- **useful**: the cited commit really fixed a bug, and the change touches what that fix did, so a
|
|
57
|
+
reviewer would want to know. This holds even if the change turned out fine (Express's deliberate
|
|
58
|
+
revert of the CVE-2024-51999 patch is useful). For co-change: the partner file really should have
|
|
59
|
+
been looked at.
|
|
60
|
+
- **noise**: the cited commit isn't a real fix (a feature, a refactor, docs), or the change doesn't
|
|
61
|
+
touch what the fix did (formatting, comments, a rename, unrelated code nearby).
|
|
62
|
+
|
|
63
|
+
Write a short `reason` either way; grouping noise by reason shows which rule to fix next.
|
|
64
|
+
|
|
41
65
|
Target: **at most 1 warning per 10 commits**, and most of those should be worth reading.
|
|
42
66
|
See [RESULTS.md](RESULTS.md) for the latest numbers.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Bench results
|
|
2
|
+
|
|
3
|
+
Measured 2026-10-30 with `blot bench`, on Windows 11, Python 3.12.
|
|
4
|
+
|
|
5
|
+
## Cases: 30/30 correct
|
|
6
|
+
|
|
7
|
+
| Check | Cases | Precision | Recall |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| removed-fix | 24 (16 warn, 8 quiet) | 100% | 100% |
|
|
10
|
+
| readded-bug | 3 (3 warn) | 100% | 100% |
|
|
11
|
+
| forgot-related-file | 3 (3 quiet) | n/a | n/a |
|
|
12
|
+
|
|
13
|
+
A quiet case now fails if its scripted edit can't be applied (it used to pass without running).
|
|
14
|
+
|
|
15
|
+
The 21 cases added in this round are real commits from the labelled replays below: each one replays
|
|
16
|
+
that commit's own hunk on its parent. Quiet cases pin the noise patterns fixed here so they stay fixed.
|
|
17
|
+
|
|
18
|
+
## Replay: last 500 non-merge commits of 5 repos, every warning labelled
|
|
19
|
+
|
|
20
|
+
Each commit is checked as if it were being committed at that moment, using only the history before
|
|
21
|
+
it. Every warning was then labelled by hand as **useful** or **noise** (rules in
|
|
22
|
+
[README.md](README.md#labels-precision-you-can-re-measure)); the labels live in [`labels/`](labels/),
|
|
23
|
+
so these numbers can be re-measured after any rule change. "Before" is Blot 0.4.0; "after" is this
|
|
24
|
+
release.
|
|
25
|
+
|
|
26
|
+
| Repo | Labelled at | Commits | Warnings / 10 commits, before → after | Precision, before → after |
|
|
27
|
+
|---|---|---|---|---|
|
|
28
|
+
| pallets/flask | `d086db856` | 500 | 0.10 → **0.08** | 3/5 (60%) → **3/4 (75%)** |
|
|
29
|
+
| psf/requests | `611c6162c` | 500 | 0.16 → **0.16** | 2/8 (25%) → **2/8 (25%)** |
|
|
30
|
+
| expressjs/express | `0dee2c52c` | 498 | 0.18 → **0.18** | 5/9 (56%) → **5/9 (56%)** |
|
|
31
|
+
| django/django | `79502d084` | 497 | 1.29 → **1.19** | 40/64 (63%) → **40/59 (68%)** |
|
|
32
|
+
| facebook/react | `9ffcb463b` | 483 | 1.26 → **0.60** | 7/61 (11%) → **7/29 (24%)** |
|
|
33
|
+
| **All** | | 2,478 | 0.59 → **0.44** | 57/147 (39%) → **57/109 (52%)** |
|
|
34
|
+
|
|
35
|
+
The rule changes removed 38 warnings, all of them labelled noise; no useful warning was lost.
|
|
36
|
+
|
|
37
|
+
**Against the PRD targets:** at most 1 warning per 10 commits is met everywhere except Django (1.19).
|
|
38
|
+
Precision of 80% is **not** met: 52% overall, 68% on Django, where most warnings are fixes touching
|
|
39
|
+
code from earlier fixes and CVEs.
|
|
40
|
+
|
|
41
|
+
### What a useful warning looks like
|
|
42
|
+
|
|
43
|
+
- Django `8fd29079e` relaxed the POST permission check that the CVE-2019-19118 fix added.
|
|
44
|
+
- Django `7ff7fcc05` redid the `parse_header_parameters` simplification that an earlier commit had
|
|
45
|
+
reverted as a bug (#36520). Both `removed-fix` and `readded-bug` fired.
|
|
46
|
+
- Flask `cabda59` changed `bp_subdomain is None` to `is not None` on a line from fix #4834; a later
|
|
47
|
+
commit had to fix the behaviour.
|
|
48
|
+
- Express `697547cd` reverted the CVE-2024-51999 patch. That revert was deliberate (the advisory,
|
|
49
|
+
GHSA-pj86-cfqh-vqx6, was later withdrawn), so it is useful as "a security fix is being undone",
|
|
50
|
+
not as a caught regression.
|
|
51
|
+
|
|
52
|
+
### Noise this release removed
|
|
53
|
+
|
|
54
|
+
| Noise (warnings) | Fix |
|
|
55
|
+
|---|---|
|
|
56
|
+
| React feature-flag forks, per-bundler and per-platform copies of one file (27) | co-change skips variants: same name stem and extension (`ReactFeatureFlags.native-fb.js` ↔ `ReactFeatureFlags.js`); `foo.c` ↔ `foo.h` still pair |
|
|
57
|
+
| deleting a whole file (4) | `removed-fix` skips deleted files |
|
|
58
|
+
| commits cited as fixes that weren't: `Fixed #21189: Cleaned up ...`, `Fixed #12882 - Moved ...`, `[DevTools] upgrade to Manifest V3`, `Change Flask.__init__ to accept ...`, error-message wording (6) | `Fixed #N:` / `Fixed #N -` ticket styles judged by their description; cleanups count as refactors; `[Tag]` prefixes and "change" subjects count as features; error messages are routine |
|
|
59
|
+
| docstrings with `backticks` or (asides) (1) | they count as prose |
|
|
60
|
+
|
|
61
|
+
### Noise still there (52 warnings)
|
|
62
|
+
|
|
63
|
+
| Pattern | Warnings | Why there's no rule yet |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| co-change partner not needed (React) | 9 | **0 of 45 co-change warnings across all five repos were useful.** See below. |
|
|
66
|
+
| renames, equivalent API swaps (`substr` → `slice`, `req.connection` → `req.socket`) | 11 | a rename and a switch to a different variable look the same on one line |
|
|
67
|
+
| new argument or keyword argument on a fix's call | 3 | adding an argument can change behaviour |
|
|
68
|
+
| formatter reflows with f-strings or joined lines (requests' Black commit) | 4 | dropping parentheses can change precedence |
|
|
69
|
+
| deleting a legacy module or feature in pieces (React) | 6 | intentional, but only the commit message says so |
|
|
70
|
+
| docstring lines that still read as code | 3 | needs to know it's inside a docstring, not just how the line looks |
|
|
71
|
+
| other: code moved to another file, fix behaviour kept while restructuring, generic re-added lines | 16 | case by case |
|
|
72
|
+
|
|
73
|
+
**`forgot-related-file` has shown no useful warning yet**: 0/45 before this release, 0/9 after. It
|
|
74
|
+
stays on, because the remaining warnings are rare (React only), but it is the first candidate to
|
|
75
|
+
become opt-in if real-world reports agree.
|
|
76
|
+
|
|
77
|
+
## Reproduce
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
git clone https://github.com/pallets/flask && cd flask && git checkout d086db856
|
|
81
|
+
blot bench --replay 500 --labels path/to/Blot/bench/labels/pallets-flask.json
|
|
82
|
+
```
|