scori 0.1.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.
@@ -0,0 +1,29 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ os: [ubuntu-latest, macos-latest]
15
+ python: ["3.11", "3.12", "3.13"]
16
+ runs-on: ${{ matrix.os }}
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - uses: astral-sh/setup-uv@v5
20
+ with:
21
+ python-version: ${{ matrix.python }}
22
+ - name: Install deps
23
+ run: uv sync --group dev
24
+ - name: Lint
25
+ run: uv run ruff check .
26
+ - name: Type-check
27
+ run: uv run mypy src/
28
+ - name: Test
29
+ run: uv run pytest
@@ -0,0 +1,33 @@
1
+ # Publica no PyPI ao fazer push de uma tag v* (ex.: v0.1.0).
2
+ #
3
+ # IMPORTANTE — antes do primeiro push é preciso configurar o Trusted
4
+ # Publisher em https://pypi.org/manage/account/publishing/ com:
5
+ # PyPI Project Name : scori
6
+ # Owner : <teu-user-github>
7
+ # Repository name : scori
8
+ # Workflow filename : publish.yml
9
+ # Environment name : pypi
10
+ # Sem isso o passo "uv publish --trusted-publishing always" falha por
11
+ # falta de credenciais — não há tokens nem secrets para configurar.
12
+
13
+ name: publish
14
+
15
+ on:
16
+ push:
17
+ tags: ["v*"]
18
+
19
+ permissions:
20
+ id-token: write
21
+ contents: read
22
+
23
+ jobs:
24
+ publish:
25
+ runs-on: ubuntu-latest
26
+ environment:
27
+ name: pypi
28
+ url: https://pypi.org/p/scori
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: astral-sh/setup-uv@v5
32
+ - run: uv build
33
+ - run: uv publish --trusted-publishing always
scori-0.1.0/.gitignore ADDED
@@ -0,0 +1,30 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .coverage
9
+ .coverage.*
10
+ htmlcov/
11
+ .pytest_cache/
12
+ .mypy_cache/
13
+ .ruff_cache/
14
+
15
+ # uv / venv
16
+ .venv/
17
+ .python-version
18
+ uv.lock
19
+
20
+ # OS / IDE
21
+ .DS_Store
22
+ .idea/
23
+ *.swp
24
+
25
+ # Claude Code local config
26
+ .claude/
27
+
28
+ # scori
29
+ .scori/
30
+ scori-report.html
@@ -0,0 +1,4 @@
1
+ {
2
+ "MD013": false,
3
+ "MD024": { "siblings_only": true }
4
+ }
@@ -0,0 +1,12 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.6.9
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+ - repo: https://github.com/pre-commit/mirrors-mypy
9
+ rev: v1.11.2
10
+ hooks:
11
+ - id: mypy
12
+ additional_dependencies: [types-requests]
@@ -0,0 +1,9 @@
1
+ {
2
+ "recommendations": [
3
+ "ms-python.python",
4
+ "ms-python.mypy-type-checker",
5
+ "charliermarsh.ruff",
6
+ "eamodio.gitlens",
7
+ "tamasfe.even-better-toml"
8
+ ]
9
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "version": "0.2.0",
3
+ "configurations": [
4
+ {
5
+ "name": "scori scan",
6
+ "type": "debugpy",
7
+ "request": "launch",
8
+ "module": "scori",
9
+ "args": ["scan", "--path", "."],
10
+ "justMyCode": false
11
+ },
12
+ {
13
+ "name": "scori friction (json)",
14
+ "type": "debugpy",
15
+ "request": "launch",
16
+ "module": "scori",
17
+ "args": ["friction", "--path", ".", "--format", "json"],
18
+ "justMyCode": false
19
+ },
20
+ {
21
+ "name": "scori friction (table)",
22
+ "type": "debugpy",
23
+ "request": "launch",
24
+ "module": "scori",
25
+ "args": ["friction", "--path", ".", "--format", "table"],
26
+ "justMyCode": false
27
+ }
28
+ ]
29
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
3
+ "python.testing.pytestEnabled": true,
4
+ "python.testing.pytestArgs": ["tests"],
5
+ "[python]": {
6
+ "editor.defaultFormatter": "charliermarsh.ruff",
7
+ "editor.formatOnSave": true,
8
+ "editor.codeActionsOnSave": { "source.fixAll.ruff": "explicit" }
9
+ },
10
+ "mypy-type-checker.enabled": true,
11
+ "editor.rulers": [88],
12
+ "files.exclude": {
13
+ "**/__pycache__": true,
14
+ "**/.mypy_cache": true
15
+ },
16
+ "snyk.advanced.autoSelectOrganization": true
17
+ }
@@ -0,0 +1,40 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
5
+ semantic versioning [SemVer](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Added
10
+
11
+ - `scori update` command with three modes:
12
+ - `--dry-run`: shows a table of pending version bumps without touching files
13
+ - `--apply`: writes updated versions to manifest files and creates a backup
14
+ in `.scori-backup/`
15
+ - `--rollback`: restores manifest files from the last backup
16
+ - `--max-friction <label>`: limits updates to deps at or below the given
17
+ friction label (`low`, `medium`, `high`, `critical`)
18
+ - `scori monitor` command: shows only dependencies with available updates,
19
+ sorted by friction score (highest first); marks with ★ packages where
20
+ updating fixes known CVEs
21
+ - `--watch` flag on `scori monitor` for continuous polling (default interval:
22
+ 300 s, configurable via `--interval`)
23
+ - CVEs fixed by the latest release now contribute up to +15 pts to the
24
+ friction score (`+3` per fixed CVE, capped at 15); CVEs that persist in
25
+ the latest version do not affect the score
26
+ - `--ci` flag on `scori friction`: exits with code 1 if any dependency score
27
+ exceeds a configurable threshold (default: 75, override with `--threshold`)
28
+ - `CVEs` column in `scori friction` table showing known vulnerabilities per
29
+ version via the OSV API
30
+ - Installed version resolution for unpinned dependencies by inspecting the
31
+ project's local venv (`.venv/`, `venv/`, `env/`)
32
+
33
+ ## [0.1.0] - 2026-05-12
34
+
35
+ ### Added
36
+
37
+ - `scori scan`: reads requirements.txt, pyproject.toml, setup.cfg
38
+ - `scori friction`: computes friction score 0–100 per dependency
39
+ - Local cache in ~/.cache/scori/ with 1-hour TTL
40
+ - Output as table (CLI), JSON, and basic HTML
scori-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.4
2
+ Name: scori
3
+ Version: 0.1.0
4
+ Summary: Software Composition Risk Intelligence — score the real cost of updating a dependency
5
+ Project-URL: Homepage, https://github.com/pauloestevao795/scori
6
+ Project-URL: Repository, https://github.com/pauloestevao795/scori
7
+ Project-URL: Issues, https://github.com/pauloestevao795/scori/issues
8
+ Project-URL: Changelog, https://github.com/pauloestevao795/scori/blob/main/CHANGELOG.md
9
+ Author-email: Paulo Estevao <pestevao@scori.dev>
10
+ License-Expression: MIT
11
+ Keywords: dependencies,friction,risk,sca,score,security,update
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Security
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: packaging>=24.0
22
+ Requires-Dist: requests>=2.31
23
+ Requires-Dist: rich>=13.0
24
+ Description-Content-Type: text/markdown
25
+
26
+ # scori
27
+
28
+ **Software Composition Risk Intelligence** — *Know the cost before you update.*
29
+
30
+ [![PyPI](https://img.shields.io/pypi/v/scori.svg)](https://pypi.org/project/scori/)
31
+ [![Python](https://img.shields.io/pypi/pyversions/scori.svg)](https://pypi.org/project/scori/)
32
+ [![License](https://img.shields.io/pypi/l/scori.svg)](LICENSE)
33
+ [![CI](https://github.com/pauloestevao795/scori/actions/workflows/ci.yml/badge.svg)](https://github.com/pauloestevao795/scori/actions/workflows/ci.yml)
34
+
35
+ Free tools like `pip-audit`, OSV-Scanner, and Dependabot detect vulnerabilities and open update PRs — but none of them answer the question that matters: *is it worth updating this lib right now, or does the migration cost outweigh the risk of not doing it?* `scori` quantifies that friction as a single 0–100 score per dependency, using public data from PyPI, GitHub, and the OSV vulnerability database.
36
+
37
+ ## Install
38
+
39
+ ```bash
40
+ pip install scori
41
+ # or
42
+ uv add scori
43
+ ```
44
+
45
+ ## Usage
46
+
47
+ ```bash
48
+ # Show friction scores for every dependency
49
+ scori friction --path .
50
+ scori friction --path . --format json > report.json
51
+ scori friction --path . --format html # writes scori-report.html
52
+ scori friction --path . --ci # exit 1 if any score > 75
53
+ scori friction --path . --ci --threshold 50 # stricter gate
54
+
55
+ # Show only dependencies with updates available, sorted by friction
56
+ scori monitor --path .
57
+ scori monitor --path . --watch # re-check every 5 minutes
58
+ scori monitor --path . --watch --interval 60 # re-check every 60 s
59
+
60
+ # Preview and apply dependency version updates
61
+ scori update --path . --dry-run # show what would change
62
+ scori update --path . --apply # write changes + create backup
63
+ scori update --path . --apply --max-friction medium # only Low/Medium deps
64
+ scori update --path . --rollback # restore from last backup
65
+
66
+ # List all detected dependencies
67
+ scori scan --path .
68
+ ```
69
+
70
+ Example output (`scori friction --format table`, with color indicators):
71
+
72
+ ```text
73
+ scori — friction scores
74
+ ┌───────────┬─────────┬─────────┬───────┬───────┬──────────┬─────────┐
75
+ │ Package │ Current │ Latest │ Jump │ Score │ Label │ CVEs │
76
+ ├───────────┼─────────┼─────────┼───────┼───────┼──────────┼─────────┤
77
+ │ django │ 3.2.0 │ 5.1.0 │ major │ 78 │ Critical │ 3 → 0 ✓ │
78
+ │ nltk │ 3.8.1 │ 3.9.4 │ minor │ 35 │ Medium │ 9 → 0 ✓ │
79
+ │ requests │ 2.31.0 │ 2.32.3 │ patch │ 8 │ Low │ — │
80
+ └───────────┴─────────┴─────────┴───────┴───────┴──────────┴─────────┘
81
+ ```
82
+
83
+ The **CVEs** column shows known vulnerabilities in your current version and
84
+ whether they are fixed in the latest release:
85
+
86
+ - `9 → 0 ✓` — 9 CVEs in current, all fixed in latest (prioritize this update)
87
+ - `3` — 3 CVEs, still present in latest (update won't help with security)
88
+ - `—` — no known vulnerabilities in either version
89
+
90
+ `scori monitor` shows only the packages that have a newer release available,
91
+ sorted by friction score (highest first), and marks with ★ any package where
92
+ updating also fixes known CVEs.
93
+
94
+ ## How it works
95
+
96
+ The friction score is a weighted sum of five components (max 100):
97
+
98
+ | Component | Max weight | Logic |
99
+ |-------------------------------------|------------|-------------------------------------|
100
+ | Semantic version jump | 50 | patch=5, minor=25, major=50 |
101
+ | Breaking signals in changelog | 20 | +4 per keyword found (max 20) |
102
+ | Affected transitive dependencies | 15 | +3 per transitive dep (max 15) |
103
+ | CVEs fixed by updating | 15 | +3 per fixed CVE (max 15) |
104
+ | Months without updating in project | 10 | +1 per month (max 10) |
105
+ | Current version yanked | 5 | +5 if `yanked: true` in PyPI API |
106
+
107
+ Labels:
108
+
109
+ - 0–25 → **Low** → *Safe to update*
110
+ - 26–50 → **Medium** → *Update with tests*
111
+ - 51–75 → **High** → *Update in isolated branch*
112
+ - 76–100 → **Critical** → *Manual migration required*
113
+
114
+ CVE data is fetched from the [OSV database](https://osv.dev) (free, no auth required).
115
+ CVEs that are **fixed by updating** contribute up to +15 points to the
116
+ friction score — a dependency where updating resolves known vulnerabilities
117
+ will score higher, pushing it toward the top of your update queue. CVEs that
118
+ remain present in the latest version do not affect the score (updating won't
119
+ help with those).
120
+
121
+ ### Data sources
122
+
123
+ | Source | Data |
124
+ | --- | --- |
125
+ | `https://pypi.org/pypi/{pkg}/json` | Latest version, release dates, yanked status |
126
+ | `https://api.github.com/repos/{owner}/{repo}/releases` | Release notes for breaking signal detection |
127
+ | `https://api.osv.dev/v1/query` | Known CVEs per version |
128
+
129
+ Set `GITHUB_TOKEN` in your environment to raise the GitHub API rate limit from 60/h to 5000/h. PyPI and GitHub release data is cached in `~/.cache/scori/` for 1 hour. OSV results are cached in memory for the duration of a single run.
130
+
131
+ ### Version resolution
132
+
133
+ For pinned dependencies (`fastapi==0.115.8`), the pinned version is used directly. For unpinned dependencies (`uvicorn` with no version), scori looks up the installed version in the project's local venv (`.venv/`, `venv/`, or `env/`) before falling back to `0.0.0`.
134
+
135
+ ## Roadmap
136
+
137
+ - **v0.2** — `scori report`: rich HTML with charts and history
138
+ - **v0.3** — support for `poetry.lock` and `uv.lock` for real transitive tree
139
+
140
+ ## Contributing
141
+
142
+ PRs and issues are welcome. Local setup:
143
+
144
+ ```bash
145
+ git clone https://github.com/pauloestevao795/scori
146
+ cd scori
147
+ uv sync --group dev
148
+ uv run pre-commit install
149
+ uv run pytest
150
+ ```
151
+
152
+ ## License
153
+
154
+ MIT
scori-0.1.0/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # scori
2
+
3
+ **Software Composition Risk Intelligence** — *Know the cost before you update.*
4
+
5
+ [![PyPI](https://img.shields.io/pypi/v/scori.svg)](https://pypi.org/project/scori/)
6
+ [![Python](https://img.shields.io/pypi/pyversions/scori.svg)](https://pypi.org/project/scori/)
7
+ [![License](https://img.shields.io/pypi/l/scori.svg)](LICENSE)
8
+ [![CI](https://github.com/pauloestevao795/scori/actions/workflows/ci.yml/badge.svg)](https://github.com/pauloestevao795/scori/actions/workflows/ci.yml)
9
+
10
+ Free tools like `pip-audit`, OSV-Scanner, and Dependabot detect vulnerabilities and open update PRs — but none of them answer the question that matters: *is it worth updating this lib right now, or does the migration cost outweigh the risk of not doing it?* `scori` quantifies that friction as a single 0–100 score per dependency, using public data from PyPI, GitHub, and the OSV vulnerability database.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pip install scori
16
+ # or
17
+ uv add scori
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```bash
23
+ # Show friction scores for every dependency
24
+ scori friction --path .
25
+ scori friction --path . --format json > report.json
26
+ scori friction --path . --format html # writes scori-report.html
27
+ scori friction --path . --ci # exit 1 if any score > 75
28
+ scori friction --path . --ci --threshold 50 # stricter gate
29
+
30
+ # Show only dependencies with updates available, sorted by friction
31
+ scori monitor --path .
32
+ scori monitor --path . --watch # re-check every 5 minutes
33
+ scori monitor --path . --watch --interval 60 # re-check every 60 s
34
+
35
+ # Preview and apply dependency version updates
36
+ scori update --path . --dry-run # show what would change
37
+ scori update --path . --apply # write changes + create backup
38
+ scori update --path . --apply --max-friction medium # only Low/Medium deps
39
+ scori update --path . --rollback # restore from last backup
40
+
41
+ # List all detected dependencies
42
+ scori scan --path .
43
+ ```
44
+
45
+ Example output (`scori friction --format table`, with color indicators):
46
+
47
+ ```text
48
+ scori — friction scores
49
+ ┌───────────┬─────────┬─────────┬───────┬───────┬──────────┬─────────┐
50
+ │ Package │ Current │ Latest │ Jump │ Score │ Label │ CVEs │
51
+ ├───────────┼─────────┼─────────┼───────┼───────┼──────────┼─────────┤
52
+ │ django │ 3.2.0 │ 5.1.0 │ major │ 78 │ Critical │ 3 → 0 ✓ │
53
+ │ nltk │ 3.8.1 │ 3.9.4 │ minor │ 35 │ Medium │ 9 → 0 ✓ │
54
+ │ requests │ 2.31.0 │ 2.32.3 │ patch │ 8 │ Low │ — │
55
+ └───────────┴─────────┴─────────┴───────┴───────┴──────────┴─────────┘
56
+ ```
57
+
58
+ The **CVEs** column shows known vulnerabilities in your current version and
59
+ whether they are fixed in the latest release:
60
+
61
+ - `9 → 0 ✓` — 9 CVEs in current, all fixed in latest (prioritize this update)
62
+ - `3` — 3 CVEs, still present in latest (update won't help with security)
63
+ - `—` — no known vulnerabilities in either version
64
+
65
+ `scori monitor` shows only the packages that have a newer release available,
66
+ sorted by friction score (highest first), and marks with ★ any package where
67
+ updating also fixes known CVEs.
68
+
69
+ ## How it works
70
+
71
+ The friction score is a weighted sum of five components (max 100):
72
+
73
+ | Component | Max weight | Logic |
74
+ |-------------------------------------|------------|-------------------------------------|
75
+ | Semantic version jump | 50 | patch=5, minor=25, major=50 |
76
+ | Breaking signals in changelog | 20 | +4 per keyword found (max 20) |
77
+ | Affected transitive dependencies | 15 | +3 per transitive dep (max 15) |
78
+ | CVEs fixed by updating | 15 | +3 per fixed CVE (max 15) |
79
+ | Months without updating in project | 10 | +1 per month (max 10) |
80
+ | Current version yanked | 5 | +5 if `yanked: true` in PyPI API |
81
+
82
+ Labels:
83
+
84
+ - 0–25 → **Low** → *Safe to update*
85
+ - 26–50 → **Medium** → *Update with tests*
86
+ - 51–75 → **High** → *Update in isolated branch*
87
+ - 76–100 → **Critical** → *Manual migration required*
88
+
89
+ CVE data is fetched from the [OSV database](https://osv.dev) (free, no auth required).
90
+ CVEs that are **fixed by updating** contribute up to +15 points to the
91
+ friction score — a dependency where updating resolves known vulnerabilities
92
+ will score higher, pushing it toward the top of your update queue. CVEs that
93
+ remain present in the latest version do not affect the score (updating won't
94
+ help with those).
95
+
96
+ ### Data sources
97
+
98
+ | Source | Data |
99
+ | --- | --- |
100
+ | `https://pypi.org/pypi/{pkg}/json` | Latest version, release dates, yanked status |
101
+ | `https://api.github.com/repos/{owner}/{repo}/releases` | Release notes for breaking signal detection |
102
+ | `https://api.osv.dev/v1/query` | Known CVEs per version |
103
+
104
+ Set `GITHUB_TOKEN` in your environment to raise the GitHub API rate limit from 60/h to 5000/h. PyPI and GitHub release data is cached in `~/.cache/scori/` for 1 hour. OSV results are cached in memory for the duration of a single run.
105
+
106
+ ### Version resolution
107
+
108
+ For pinned dependencies (`fastapi==0.115.8`), the pinned version is used directly. For unpinned dependencies (`uvicorn` with no version), scori looks up the installed version in the project's local venv (`.venv/`, `venv/`, or `env/`) before falling back to `0.0.0`.
109
+
110
+ ## Roadmap
111
+
112
+ - **v0.2** — `scori report`: rich HTML with charts and history
113
+ - **v0.3** — support for `poetry.lock` and `uv.lock` for real transitive tree
114
+
115
+ ## Contributing
116
+
117
+ PRs and issues are welcome. Local setup:
118
+
119
+ ```bash
120
+ git clone https://github.com/pauloestevao795/scori
121
+ cd scori
122
+ uv sync --group dev
123
+ uv run pre-commit install
124
+ uv run pytest
125
+ ```
126
+
127
+ ## License
128
+
129
+ MIT
scori-0.1.0/ROADMAP.md ADDED
@@ -0,0 +1,166 @@
1
+ # scori Roadmap
2
+
3
+ > *Know the cost before you update.*
4
+
5
+ scori is a free, auth-free CLI for Python that quantifies the real cost of updating a dependency as a single friction score (0–100). It complements tools like `pip-audit`, OSV-Scanner, and Dependabot — which tell you *what* to update — by answering the harder question: *should you update it now, and how much will it hurt?* The friction score is a concept not yet present in open-source dependency tooling, and scori aims to make it a first-class signal in every Python project's maintenance workflow.
6
+
7
+ ---
8
+
9
+ ## Current status — v0.1.0 ✅
10
+
11
+ - [x] `scori scan`: reads `requirements.txt`, `pyproject.toml` (PEP 517/518), `setup.cfg`
12
+ - [x] `scori friction`: computes friction score 0–100 per dependency
13
+ - [x] Weighted scoring algorithm: version jump, breaking signals, transitive deps, months outdated, yanked status
14
+ - [x] Labels: Low / Medium / High / Critical with color-coded table output
15
+ - [x] CVEs column via [OSV API](https://osv.dev) — shown as `3 → 0 ✓`, separate from the score
16
+ - [x] Output formats: table (rich), JSON, HTML
17
+ - [x] Local cache in `~/.cache/scori/` with 1-hour TTL (PyPI + GitHub data)
18
+ - [x] `GITHUB_TOKEN` support to raise API rate limit from 60/h to 5000/h
19
+ - [x] Installed version resolution for unpinned deps via local venv inspection
20
+
21
+ **Known limitations in v0.1.0:**
22
+
23
+ - Unpinned dependencies without a local venv fall back to `0.0.0` (no conda/pyenv/Docker support yet)
24
+ - Transitive dependency count is always 0 — requires a lockfile parser (planned for v0.3)
25
+ - CVE count is informational only — not yet factored into the friction score
26
+ - `scori monitor`, `scori update`, and `scori report` are stubbed in the CLI but not implemented
27
+
28
+ ---
29
+
30
+ ## v0.2 — Full CLI surface
31
+
32
+ Complete the commands already declared in the CLI but not yet implemented.
33
+
34
+ ### `scori monitor` ✅
35
+
36
+ - [x] Poll PyPI for new releases on all project dependencies
37
+ - [x] Output a "updates available" table sorted by friction score (highest friction first)
38
+ - [x] `--watch` flag for continuous monitoring with a configurable interval
39
+ - [x] Highlight dependencies where a new release also fixes known CVEs (★ marker)
40
+
41
+ ### `scori update` ✅
42
+
43
+ - [x] `--dry-run`: show a diff of what would change in the manifest without applying
44
+ - [x] `--apply`: apply updates and create an automatic backup of the original manifest
45
+ - [x] `--rollback`: restore the most recent backup
46
+ - [x] `--max-friction <label>`: only update deps at or below a given friction label (e.g. `medium`)
47
+
48
+ ### `scori report`
49
+
50
+ - [ ] Standalone HTML report with a visual traffic-light indicator per dependency
51
+ - [ ] Structured JSON export suitable for CI/CD pipeline consumption
52
+ - [ ] `--ci` flag: exit with code 1 if any dependency exceeds a configurable score threshold
53
+
54
+ ---
55
+
56
+ ## v0.3 — Smarter scoring
57
+
58
+ Improve the accuracy and depth of the friction score algorithm.
59
+
60
+ ### Real transitive dependency counts
61
+
62
+ - [ ] Parse `poetry.lock` to count packages that depend on the package being updated
63
+ - [ ] Parse `uv.lock` for the same
64
+ - [ ] Use the resolved count in the score weight (currently always 0)
65
+
66
+ ### CVEs in the score
67
+
68
+ - [x] Incorporate OSV CVE count directly into the weighted algorithm (up to +15 pts)
69
+ - [ ] Weight CVSS ≥ 9.0 CVEs more heavily than lower-severity ones
70
+
71
+ ### Improved breaking signal detection
72
+
73
+ - [ ] Scan `CHANGELOG.md` from the GitHub repo in addition to release notes
74
+ - [ ] Detect `BREAKING CHANGE:` in Conventional Commits commit history
75
+ - [ ] Heuristic diff of `.pyi` type stub files between versions as an API-change signal
76
+
77
+ ### Broader version resolution
78
+
79
+ - [ ] Resolve unpinned versions via `conda list --json` when inside a conda environment
80
+ - [ ] Support pyenv shims as a version source
81
+ - [ ] Optional: detect version from Docker image labels (requires Docker CLI, off by default)
82
+
83
+ ---
84
+
85
+ ## v0.4 — Integrations
86
+
87
+ Bring scori into the workflows and tools developers already use.
88
+
89
+ ### GitHub Actions
90
+
91
+ - [ ] Official `scori-action` published to the GitHub Marketplace
92
+ - [ ] Automatic PR comment with a friction table for any changed dependencies
93
+ - [ ] Dynamic badge for `README.md` showing the project's average friction score
94
+
95
+ ### Pre-commit hook
96
+
97
+ - [ ] Official hook for `.pre-commit-config.yaml`
98
+ - [ ] Configurable threshold — block commit if any dep exceeds it
99
+
100
+ ### VSCode Extension *(stretch goal)*
101
+
102
+ - [ ] Inline decoration showing the friction score per line in `requirements.txt` / `pyproject.toml`
103
+ - [ ] CodeLens action: "Run scori friction on this package"
104
+
105
+ ---
106
+
107
+ ## v0.5 — Intelligence layer
108
+
109
+ Higher-level features that turn scori from a scoring tool into a maintenance advisor.
110
+
111
+ ### Score history
112
+
113
+ - [ ] Track friction scores over time per project in local storage
114
+ - [ ] Trend chart: surface dependencies that are becoming riskier over successive runs
115
+
116
+ ### Risk profiles
117
+
118
+ - [ ] Per-project `.scori.toml` configuration for custom thresholds and weights
119
+ - [ ] Built-in profiles: `conservative`, `balanced`, `aggressive`
120
+
121
+ ### Suggested update order
122
+
123
+ - [ ] Rank dependencies by update order to minimise total migration risk
124
+ - [ ] Detect conflicts between simultaneous updates (e.g. shared transitive dep with incompatible constraints)
125
+
126
+ ### LLM-assisted changelog summary *(opt-in)*
127
+
128
+ - [ ] Plain-language summary of what changes in a given update
129
+ - [ ] Supports local inference via Ollama or `OPENAI_API_KEY` — never required to use scori
130
+ - [ ] Off by default; enabled explicitly with `--summarise`
131
+
132
+ ---
133
+
134
+ ## Non-goals
135
+
136
+ scori has a deliberate scope. The following are explicitly out of scope:
137
+
138
+ - **Not a CVE scanner.** scori shows CVE counts as context, but `pip-audit` and OSV-Scanner do this properly. Use them alongside scori, not instead.
139
+ - **Not a package manager.** scori reads and optionally edits manifests, but it does not resolve or install packages.
140
+ - **Python only.** Supporting npm, cargo, or other ecosystems is out of scope. scori's scoring model is designed around the PyPI and GitHub release data available for Python packages.
141
+ - **No account required.** scori will never require a login, subscription, or mandatory API key. Optional tokens (e.g. `GITHUB_TOKEN`) may improve rate limits, but the tool is always fully functional without them.
142
+
143
+ ---
144
+
145
+ ## How to contribute
146
+
147
+ Contributions are welcome. See [`CONTRIBUTING.md`](CONTRIBUTING.md) (coming soon) for the full guide.
148
+
149
+ **Priority areas for external contributions:**
150
+
151
+ - Manifest parsers for additional formats (`conda.yml`, `Pipfile`, `Pipfile.lock`)
152
+ - Integration tests against well-known real-world projects
153
+ - CLI message internationalisation (i18n)
154
+
155
+ Issues labelled **`good first issue`** on GitHub are the recommended starting point for new contributors.
156
+
157
+ ---
158
+
159
+ ## Versioning policy
160
+
161
+ scori follows [Semantic Versioning](https://semver.org).
162
+
163
+ - Patch releases (`0.x.y`) fix bugs without changing behaviour.
164
+ - Minor releases (`0.x`) add features in a backwards-compatible way.
165
+ - Breaking changes to the CLI interface will only occur in major releases.
166
+ - The public API (`FrictionResult`, `Dependency`, `compute()`) is considered stable from v1.0 onwards. Until then, minor releases may include breaking changes to the Python API — the CLI surface is the stable interface.