vibecodedshit 0.0.0-stage → 0.2.0
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.
- package/LICENSE +95 -0
- package/README.md +64 -2
- package/assets/fonts/NotoEmoji-OFL.txt +93 -0
- package/assets/fonts/NotoEmoji-Poop.ttf +0 -0
- package/assets/fonts/SpaceGrotesk-Bold.ttf +0 -0
- package/assets/fonts/SpaceGrotesk-OFL.txt +93 -0
- package/dist/bin.js +8 -0
- package/dist/card/previous.js +38 -0
- package/dist/card/render.js +71 -0
- package/dist/cli.js +121 -0
- package/dist/commands/card.js +69 -0
- package/dist/commands/common.js +1 -0
- package/dist/commands/diff.js +54 -0
- package/dist/commands/footer.js +25 -0
- package/dist/commands/report.js +49 -0
- package/dist/commands/route.js +62 -0
- package/dist/commands/submit.js +125 -0
- package/dist/commands/summary.js +77 -0
- package/dist/diff/compare.js +73 -0
- package/dist/diff/conditions.js +87 -0
- package/dist/diff/format.js +23 -0
- package/dist/exec/docker.js +158 -0
- package/dist/exec/findings.js +73 -0
- package/dist/exec/plan.js +50 -0
- package/dist/exec/reports.js +90 -0
- package/dist/exec/roots.js +49 -0
- package/dist/exec/run.js +182 -0
- package/dist/exec/steps/build.js +45 -0
- package/dist/exec/steps/coverage-install.js +12 -0
- package/dist/exec/steps/install.js +41 -0
- package/dist/exec/steps/knip.js +28 -0
- package/dist/exec/steps/lint.js +25 -0
- package/dist/exec/steps/lockfiles.js +25 -0
- package/dist/exec/steps/test.js +17 -0
- package/dist/exec/steps/typecheck.js +40 -0
- package/dist/exec/test-reports/coverage-py.js +23 -0
- package/dist/exec/test-reports/coverage-ranges.js +65 -0
- package/dist/exec/test-reports/coverage-summary.js +23 -0
- package/dist/exec/test-reports/jest-json.js +31 -0
- package/dist/exec/test-reports/junit.js +24 -0
- package/dist/exec/test-reports/mocha-json.js +18 -0
- package/dist/exec/test-reports/vitest-json.js +5 -0
- package/dist/exec/test-runners/detect.js +99 -0
- package/dist/exec/test-runners/index.js +6 -0
- package/dist/exec/test-runners/jest.js +27 -0
- package/dist/exec/test-runners/mocha.js +28 -0
- package/dist/exec/test-runners/node-test.js +24 -0
- package/dist/exec/test-runners/pytest.js +18 -0
- package/dist/exec/test-runners/script.js +48 -0
- package/dist/exec/test-runners/spec.js +1 -0
- package/dist/exec/test-runners/vitest.js +28 -0
- package/dist/exec/tests.js +120 -0
- package/dist/exec/types.js +1 -0
- package/dist/manifest/package-json.js +36 -0
- package/dist/manifest/python.js +106 -0
- package/dist/measure/d3/index.js +45 -0
- package/dist/measure/d3/presets.js +100 -0
- package/dist/measure/d3/py/adapter.js +67 -0
- package/dist/measure/d3/py/config.js +80 -0
- package/dist/measure/d3/py/contracts.js +57 -0
- package/dist/measure/d3/py/domain.js +57 -0
- package/dist/measure/d3/py/graph.js +214 -0
- package/dist/measure/d3/py/interpreter.js +31 -0
- package/dist/measure/d3/py/layers.js +120 -0
- package/dist/measure/d3/py/roots.js +58 -0
- package/dist/measure/d3/py/types.js +1 -0
- package/dist/measure/d3/scc.js +64 -0
- package/dist/measure/d3/ts/adapter.js +371 -0
- package/dist/measure/d3/ts/classify.js +107 -0
- package/dist/measure/d3/ts/config.js +318 -0
- package/dist/measure/d3/ts/domain.js +23 -0
- package/dist/measure/d3/ts/rules.js +65 -0
- package/dist/measure/d3/types.js +5 -0
- package/dist/measure/deps/cvss.js +66 -0
- package/dist/measure/deps/declared.js +195 -0
- package/dist/measure/deps/files.js +40 -0
- package/dist/measure/deps/lockfiles.js +308 -0
- package/dist/measure/deps/osv.js +122 -0
- package/dist/measure/deps/registry.js +142 -0
- package/dist/measure/deps/resolved.js +78 -0
- package/dist/measure/deps/units.js +5 -0
- package/dist/measure/eslint/health-plugin.js +19 -0
- package/dist/measure/ops/docs-commands.js +73 -0
- package/dist/measure/ops/docs-resolve.js +217 -0
- package/dist/measure/ops/entry-points.js +49 -0
- package/dist/measure/ops/env-example.js +20 -0
- package/dist/measure/ops/env-reads.js +46 -0
- package/dist/measure/ops/runtime.js +73 -0
- package/dist/measure/p1-1.js +8 -0
- package/dist/measure/p1-2.js +8 -0
- package/dist/measure/p1-3.js +8 -0
- package/dist/measure/p1-4.js +41 -0
- package/dist/measure/p1-5.js +59 -0
- package/dist/measure/p2-1.js +8 -0
- package/dist/measure/p2-2.js +44 -0
- package/dist/measure/p2-3.js +81 -0
- package/dist/measure/p2-4.js +288 -0
- package/dist/measure/p2-5.js +8 -0
- package/dist/measure/p3-1.js +16 -0
- package/dist/measure/p3-2.js +26 -0
- package/dist/measure/p3-3.js +37 -0
- package/dist/measure/p3-4.js +26 -0
- package/dist/measure/p3-5.js +26 -0
- package/dist/measure/p4-1.js +184 -0
- package/dist/measure/p4-2.js +27 -0
- package/dist/measure/p4-3.js +106 -0
- package/dist/measure/p4-4.js +309 -0
- package/dist/measure/p5-1.js +117 -0
- package/dist/measure/p5-2.js +80 -0
- package/dist/measure/p5-3.js +21 -0
- package/dist/measure/p5-4.js +161 -0
- package/dist/measure/p5-5.js +158 -0
- package/dist/measure/p6-1.js +20 -0
- package/dist/measure/p6-2.js +20 -0
- package/dist/measure/p6-3.js +40 -0
- package/dist/measure/p6-4.js +31 -0
- package/dist/measure/p6-5.js +60 -0
- package/dist/measure/p6-6.js +54 -0
- package/dist/measure/py/typecheck-config.js +95 -0
- package/dist/measure/registry.js +31 -0
- package/dist/measure/safety/py-tests.js +124 -0
- package/dist/measure/safety/ts-barrels.js +68 -0
- package/dist/measure/safety/ts-cases.js +111 -0
- package/dist/measure/safety/ts-credits.js +101 -0
- package/dist/measure/safety/ts-imports.js +63 -0
- package/dist/measure/safety/ts-resolve.js +43 -0
- package/dist/measure/ts/directives.js +37 -0
- package/dist/measure/ts/exports.js +60 -0
- package/dist/measure/ts/tsconfig.js +179 -0
- package/dist/measure/types.js +1 -0
- package/dist/measure/units.js +41 -0
- package/dist/methodology/load.js +159 -0
- package/dist/methodology/schema.js +105 -0
- package/dist/python/deadcode.js +27 -0
- package/dist/python/env.js +13 -0
- package/dist/python/helper.js +24 -0
- package/dist/python/imports.js +40 -0
- package/dist/python/nox.js +16 -0
- package/dist/python/scope.js +35 -0
- package/dist/python/tests.js +19 -0
- package/dist/python/typing.js +27 -0
- package/dist/report/escape.js +5 -0
- package/dist/report/format.js +75 -0
- package/dist/report/render.js +213 -0
- package/dist/report/roadmap.js +58 -0
- package/dist/report/scares.js +83 -0
- package/dist/report/style.js +27 -0
- package/dist/report-only/hotspots.js +48 -0
- package/dist/route/check.js +37 -0
- package/dist/route/files.js +74 -0
- package/dist/route/order.js +22 -0
- package/dist/route/select.js +114 -0
- package/dist/route/write.js +13 -0
- package/dist/run/read.js +89 -0
- package/dist/run/recompute.js +19 -0
- package/dist/run/scan.js +196 -0
- package/dist/run/schema.js +1 -0
- package/dist/run/score-run.js +42 -0
- package/dist/run/write.js +4 -0
- package/dist/scope/build.js +173 -0
- package/dist/scope/packages.js +87 -0
- package/dist/scope/rules.js +21 -0
- package/dist/scope/tracked.js +34 -0
- package/dist/scope/ts-lines.js +63 -0
- package/dist/scope/types.js +7 -0
- package/dist/scoring/aggregate.js +38 -0
- package/dist/scoring/pool.js +65 -0
- package/dist/scoring/score.js +81 -0
- package/dist/scoring/what-if.js +38 -0
- package/dist/scripts/checks.js +53 -0
- package/dist/scripts/ci.js +139 -0
- package/dist/scripts/entry-points/find.js +31 -0
- package/dist/scripts/entry-points/index.js +18 -0
- package/dist/scripts/entry-points/justfile.js +62 -0
- package/dist/scripts/entry-points/makefile.js +66 -0
- package/dist/scripts/entry-points/nox.js +29 -0
- package/dist/scripts/entry-points/package-json.js +21 -0
- package/dist/scripts/entry-points/pyproject.js +73 -0
- package/dist/scripts/entry-points/tox.js +130 -0
- package/dist/scripts/expand.js +300 -0
- package/dist/scripts/triggers.js +151 -0
- package/dist/scripts/types.js +1 -0
- package/dist/submit/constants.js +9 -0
- package/dist/submit/payload.js +42 -0
- package/dist/submit/repo-identity.js +46 -0
- package/dist/submit/send.js +29 -0
- package/dist/tools/catalog.js +46 -0
- package/dist/tools/image.js +180 -0
- package/dist/tools/kit.js +71 -0
- package/dist/tools/knip.js +169 -0
- package/dist/tools/outcome.js +21 -0
- package/dist/tools/resolve.js +66 -0
- package/dist/tools/workcopy.js +27 -0
- package/dist/util/ini.js +37 -0
- package/dist/util/pep440.js +163 -0
- package/dist/util/toml.js +27 -0
- package/docker/Dockerfile +142 -0
- package/docker/bin/health-capture +5 -0
- package/docker/bin/health-coverage-install +5 -0
- package/docker/bin/health-eslint +66 -0
- package/docker/bin/health-pytest +10 -0
- package/docker/bin/health-tsc +10 -0
- package/docker/bin/health-venv +11 -0
- package/docker/config/eslint.config.mjs +4 -0
- package/docker/config/eslint.rules.mjs +65 -0
- package/docker/config/eslint.untyped.config.mjs +4 -0
- package/docker/config/knip.json +1 -0
- package/docker/config/ruff.toml +7 -0
- package/methodology/LICENSE +396 -0
- package/methodology/v1.0/METHODOLOGY.md +1176 -0
- package/methodology/v1.0/dimensions/1-safety-net.yaml +240 -0
- package/methodology/v1.0/dimensions/2-type-static-rigor.yaml +289 -0
- package/methodology/v1.0/dimensions/3-architecture-boundaries.yaml +266 -0
- package/methodology/v1.0/dimensions/4-complexity-maintainability.yaml +192 -0
- package/methodology/v1.0/dimensions/5-dependency-security-hygiene.yaml +223 -0
- package/methodology/v1.0/dimensions/6-operability-feedback-loop.yaml +279 -0
- package/methodology/v1.0/methodology.yaml +242 -0
- package/methodology/v1.0/presets/django.yaml +43 -0
- package/methodology/v1.0/presets/express.yaml +47 -0
- package/methodology/v1.0/presets/fastapi.yaml +52 -0
- package/methodology/v1.0/presets/generic.yaml +41 -0
- package/methodology/v1.0/presets/nextjs.yaml +50 -0
- package/methodology/v1.0/scope.yaml +115 -0
- package/package.json +61 -4
- package/python/dead_code_helper.py +265 -0
- package/python/env_helper.py +71 -0
- package/python/graph_helper.py +277 -0
- package/python/imports_helper.py +132 -0
- package/python/nox_helper.py +79 -0
- package/python/scope_helper.py +96 -0
- package/python/tests_helper.py +171 -0
- package/python/typing_helper.py +235 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
dimension:
|
|
2
|
+
id: 1
|
|
3
|
+
key: safety_net
|
|
4
|
+
name: Safety net
|
|
5
|
+
question: Will a change break something without anyone noticing?
|
|
6
|
+
agent_relevance: >-
|
|
7
|
+
An agent cannot remember how the system is supposed to behave. The test
|
|
8
|
+
suite is the only record of that behaviour it can check its change
|
|
9
|
+
against.
|
|
10
|
+
|
|
11
|
+
parameters:
|
|
12
|
+
- id: "1.1"
|
|
13
|
+
key: suite_pass_rate
|
|
14
|
+
name: Suite pass rate
|
|
15
|
+
layer: execution
|
|
16
|
+
weight: 20
|
|
17
|
+
requires: [install, test_run]
|
|
18
|
+
pooling: ratio
|
|
19
|
+
raw:
|
|
20
|
+
unit: percent
|
|
21
|
+
definition: >-
|
|
22
|
+
passed / (passed + failed + errored) test cases. Skipped and
|
|
23
|
+
expected-failure tests are excluded from both numerator and
|
|
24
|
+
denominator. A test file that fails to load or collect counts as one
|
|
25
|
+
failed test case.
|
|
26
|
+
when_empty: 0
|
|
27
|
+
scoring:
|
|
28
|
+
method: piecewise_linear
|
|
29
|
+
anchors:
|
|
30
|
+
- raw: 80
|
|
31
|
+
score: 0
|
|
32
|
+
descriptor: The suite is red. Nobody can use it to check a change.
|
|
33
|
+
- raw: 95
|
|
34
|
+
score: 50
|
|
35
|
+
descriptor: Mostly green, with known failures people have learned to ignore.
|
|
36
|
+
- raw: 100
|
|
37
|
+
score: 100
|
|
38
|
+
descriptor: Green. A new failure means the change broke something.
|
|
39
|
+
measure:
|
|
40
|
+
typescript_javascript: >-
|
|
41
|
+
vitest, jest, mocha or node:test, detected from package.json
|
|
42
|
+
dependencies and the test script. Run once with a JSON reporter.
|
|
43
|
+
Playwright and Cypress suites are not run.
|
|
44
|
+
python: >-
|
|
45
|
+
pytest (also runs unittest suites), with
|
|
46
|
+
--continue-on-collection-errors and a JSON or JUnit report.
|
|
47
|
+
not_applicable_when: null
|
|
48
|
+
rationale: >-
|
|
49
|
+
A suite with known failures stops working as a check: a new failure
|
|
50
|
+
looks the same as the old ones. The curve is steep on purpose. 95% of a
|
|
51
|
+
200-test suite is 10 failing tests, which is already enough for people
|
|
52
|
+
to stop reading the output.
|
|
53
|
+
sources: []
|
|
54
|
+
|
|
55
|
+
- id: "1.2"
|
|
56
|
+
key: line_coverage
|
|
57
|
+
name: Line coverage
|
|
58
|
+
layer: execution
|
|
59
|
+
weight: 25
|
|
60
|
+
requires: [install, test_run]
|
|
61
|
+
pooling: ratio
|
|
62
|
+
raw:
|
|
63
|
+
unit: percent
|
|
64
|
+
definition: >-
|
|
65
|
+
Covered lines / coverable lines across all logic files, including
|
|
66
|
+
logic files no test loads. A file no test loads counts as 0%
|
|
67
|
+
covered. For TypeScript and JavaScript the coverable lines are
|
|
68
|
+
health's code lines (lines with at least one token). A line counts as
|
|
69
|
+
covered when the innermost statement or function containing it ran.
|
|
70
|
+
when_empty: 0
|
|
71
|
+
scoring:
|
|
72
|
+
method: piecewise_linear
|
|
73
|
+
anchors:
|
|
74
|
+
- raw: 10
|
|
75
|
+
score: 0
|
|
76
|
+
descriptor: No safety net.
|
|
77
|
+
- raw: 40
|
|
78
|
+
score: 50
|
|
79
|
+
descriptor: Happy paths only.
|
|
80
|
+
- raw: 60
|
|
81
|
+
score: 75
|
|
82
|
+
descriptor: Acceptable.
|
|
83
|
+
- raw: 80
|
|
84
|
+
score: 100
|
|
85
|
+
descriptor: Well covered. No extra credit above this.
|
|
86
|
+
measure:
|
|
87
|
+
typescript_javascript: >-
|
|
88
|
+
v8 or istanbul coverage with the json-summary and json reporters
|
|
89
|
+
(vitest coverage.include, jest collectCoverageFrom over logic files, c8
|
|
90
|
+
for mocha and node:test). Lines are counted by health from the json
|
|
91
|
+
report's statement and function ranges, not taken from the tool, so
|
|
92
|
+
the same code gives the same count under every runner. Repository
|
|
93
|
+
coverage thresholds are disabled so they cannot fail the run.
|
|
94
|
+
python: >-
|
|
95
|
+
coverage.py through pytest-cov, with --cov set to every first-party
|
|
96
|
+
package so files no test imports are included.
|
|
97
|
+
not_applicable_when: null
|
|
98
|
+
rationale: >-
|
|
99
|
+
Coverage shows which code no test executes. It does not show that the
|
|
100
|
+
executed code is checked, which is why 1.5 exists. The 60% anchor
|
|
101
|
+
matches Google's "acceptable" level. The 100 anchor is 80%, which is
|
|
102
|
+
the coverage SonarQube's default quality gate requires on new code and
|
|
103
|
+
sits between Google's "commendable" (75%) and "exemplary" (90%).
|
|
104
|
+
Above 80% the methodology gives no extra credit, because the remaining
|
|
105
|
+
code is often glue that costs more to test than it returns.
|
|
106
|
+
sources:
|
|
107
|
+
- "Arguelles, Ivanković, Bender. Code Coverage Best Practices. Google Testing Blog, 2020. https://testing.googleblog.com/2020/08/code-coverage-best-practices.html"
|
|
108
|
+
- "SonarQube default quality gate (Sonar way): coverage on new code at least 80%."
|
|
109
|
+
|
|
110
|
+
- id: "1.3"
|
|
111
|
+
key: branch_coverage
|
|
112
|
+
name: Branch coverage
|
|
113
|
+
layer: execution
|
|
114
|
+
weight: 15
|
|
115
|
+
requires: [install, test_run]
|
|
116
|
+
pooling: ratio
|
|
117
|
+
raw:
|
|
118
|
+
unit: percent
|
|
119
|
+
definition: Covered branches / total branches across all logic files, including files no test loads.
|
|
120
|
+
when_empty: 0
|
|
121
|
+
scoring:
|
|
122
|
+
method: piecewise_linear
|
|
123
|
+
anchors:
|
|
124
|
+
- raw: 5
|
|
125
|
+
score: 0
|
|
126
|
+
descriptor: Only one path through each decision is ever run.
|
|
127
|
+
- raw: 30
|
|
128
|
+
score: 50
|
|
129
|
+
descriptor: Error and edge paths are mostly untested.
|
|
130
|
+
- raw: 50
|
|
131
|
+
score: 75
|
|
132
|
+
descriptor: Main error paths are tested.
|
|
133
|
+
- raw: 70
|
|
134
|
+
score: 100
|
|
135
|
+
descriptor: Most decisions are tested both ways.
|
|
136
|
+
measure:
|
|
137
|
+
typescript_javascript: >-
|
|
138
|
+
Same coverage run as 1.2; branch totals from json-summary. They come
|
|
139
|
+
from the runner's coverage tool and can differ slightly between
|
|
140
|
+
runners on the same code.
|
|
141
|
+
python: Same run as 1.2 with --cov-branch.
|
|
142
|
+
not_applicable_when: null
|
|
143
|
+
rationale: >-
|
|
144
|
+
Tests written quickly cover the happy path. Line coverage can be high
|
|
145
|
+
while every error branch is untested. Branch coverage shows that gap.
|
|
146
|
+
Branch percentages are lower than line percentages on the same code,
|
|
147
|
+
so the anchors sit about 10 points lower than 1.2's.
|
|
148
|
+
sources: []
|
|
149
|
+
|
|
150
|
+
- id: "1.4"
|
|
151
|
+
key: modules_with_tests
|
|
152
|
+
name: Modules with tests
|
|
153
|
+
layer: static
|
|
154
|
+
weight: 25
|
|
155
|
+
requires: []
|
|
156
|
+
pooling: ratio
|
|
157
|
+
raw:
|
|
158
|
+
unit: percent
|
|
159
|
+
definition: >-
|
|
160
|
+
Logic files directly imported by at least one test file / all logic
|
|
161
|
+
files. Imports are followed through barrel files and Python
|
|
162
|
+
__init__.py re-exports to the file that defines the imported name.
|
|
163
|
+
Transitive imports do not count.
|
|
164
|
+
when_empty: 0
|
|
165
|
+
scoring:
|
|
166
|
+
method: piecewise_linear
|
|
167
|
+
anchors:
|
|
168
|
+
- raw: 10
|
|
169
|
+
score: 0
|
|
170
|
+
descriptor: Almost nothing has a test.
|
|
171
|
+
- raw: 40
|
|
172
|
+
score: 50
|
|
173
|
+
descriptor: Some modules have tests; most do not.
|
|
174
|
+
- raw: 70
|
|
175
|
+
score: 75
|
|
176
|
+
descriptor: Most modules have a test.
|
|
177
|
+
- raw: 90
|
|
178
|
+
score: 100
|
|
179
|
+
descriptor: Nearly every module has a test.
|
|
180
|
+
measure:
|
|
181
|
+
typescript_javascript: >-
|
|
182
|
+
AST import graph from test files (static imports, require and dynamic
|
|
183
|
+
import with a literal path).
|
|
184
|
+
python: AST import graph from test files (import and from-import statements).
|
|
185
|
+
not_applicable_when: null
|
|
186
|
+
rationale: >-
|
|
187
|
+
This is the static counterpart to coverage. It still works when the
|
|
188
|
+
suite does not run, so a repository with tests that are broken gets
|
|
189
|
+
partial credit, and "make the existing tests run" shows up as a gain
|
|
190
|
+
in 1.1 to 1.3. Only direct imports count; otherwise one test that
|
|
191
|
+
imports the app entry point would mark every file as tested.
|
|
192
|
+
sources: []
|
|
193
|
+
|
|
194
|
+
- id: "1.5"
|
|
195
|
+
key: asserting_tests
|
|
196
|
+
name: Tests that assert something
|
|
197
|
+
layer: static
|
|
198
|
+
weight: 15
|
|
199
|
+
requires: []
|
|
200
|
+
pooling: ratio
|
|
201
|
+
raw:
|
|
202
|
+
unit: percent
|
|
203
|
+
definition: >-
|
|
204
|
+
Test cases containing at least one assertion / all test cases. An
|
|
205
|
+
assertion inside a helper function defined in the same file and
|
|
206
|
+
called by the test counts (one level deep).
|
|
207
|
+
when_empty: 0
|
|
208
|
+
scoring:
|
|
209
|
+
method: piecewise_linear
|
|
210
|
+
anchors:
|
|
211
|
+
- raw: 50
|
|
212
|
+
score: 0
|
|
213
|
+
descriptor: Many tests run code without checking anything.
|
|
214
|
+
- raw: 80
|
|
215
|
+
score: 50
|
|
216
|
+
descriptor: A noticeable share of tests check nothing.
|
|
217
|
+
- raw: 95
|
|
218
|
+
score: 75
|
|
219
|
+
descriptor: A few tests check nothing.
|
|
220
|
+
- raw: 100
|
|
221
|
+
score: 100
|
|
222
|
+
descriptor: Every test checks something.
|
|
223
|
+
measure:
|
|
224
|
+
typescript_javascript: >-
|
|
225
|
+
Test case: a call to it, test or their .each/.only/.concurrent
|
|
226
|
+
variants. Assertion: expect(...), assert(...), assert.*,
|
|
227
|
+
expectTypeOf(...), t.assert* / t.is / t.deepEqual (node:test and
|
|
228
|
+
ava contexts).
|
|
229
|
+
python: >-
|
|
230
|
+
Test case: a test_* function in a test module, or a test_* method of
|
|
231
|
+
a unittest.TestCase subclass. Assertion: an assert statement,
|
|
232
|
+
self.assert*, pytest.raises, pytest.warns, or a mock method call
|
|
233
|
+
starting with assert_.
|
|
234
|
+
not_applicable_when: null
|
|
235
|
+
rationale: >-
|
|
236
|
+
A test without an assertion raises coverage and checks nothing. This is
|
|
237
|
+
the cheapest way to game 1.2 and 1.3, and it is common in generated
|
|
238
|
+
tests. The anchors are strict because writing a test without an
|
|
239
|
+
assertion is almost never intentional.
|
|
240
|
+
sources: []
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
dimension:
|
|
2
|
+
id: 2
|
|
3
|
+
key: type_static_rigor
|
|
4
|
+
name: Type & static rigor
|
|
5
|
+
question: Does the code tell you what it expects before you run it?
|
|
6
|
+
agent_relevance: >-
|
|
7
|
+
Type errors and lint findings are the fastest feedback an agent gets. A
|
|
8
|
+
strict typechecker catches a wrong change in seconds, before any test
|
|
9
|
+
runs, and the types document what each function accepts and returns.
|
|
10
|
+
|
|
11
|
+
parameters:
|
|
12
|
+
- id: "2.1"
|
|
13
|
+
key: typecheck_errors
|
|
14
|
+
name: Typecheck errors
|
|
15
|
+
layer: execution
|
|
16
|
+
weight: 25
|
|
17
|
+
requires: [install, typecheck_run]
|
|
18
|
+
pooling: ratio
|
|
19
|
+
raw:
|
|
20
|
+
unit: errors per 1,000 source lines
|
|
21
|
+
definition: >-
|
|
22
|
+
Typechecker errors located in in-scope files (logic and test), divided
|
|
23
|
+
by source lines / 1,000. Errors in excluded files and in dependencies
|
|
24
|
+
are ignored. Warnings are ignored.
|
|
25
|
+
when_empty: 100
|
|
26
|
+
scoring:
|
|
27
|
+
method: piecewise_linear
|
|
28
|
+
anchors:
|
|
29
|
+
- raw: 0
|
|
30
|
+
score: 100
|
|
31
|
+
descriptor: Clean. A new error means the change introduced it.
|
|
32
|
+
- raw: 1
|
|
33
|
+
score: 75
|
|
34
|
+
descriptor: A few known errors.
|
|
35
|
+
- raw: 5
|
|
36
|
+
score: 50
|
|
37
|
+
descriptor: Errors are routine and people work around them.
|
|
38
|
+
- raw: 20
|
|
39
|
+
score: 0
|
|
40
|
+
descriptor: The typechecker is ignored.
|
|
41
|
+
measure:
|
|
42
|
+
typescript_javascript: >-
|
|
43
|
+
tsc --noEmit with the repository's tsconfig.json (each tsconfig that
|
|
44
|
+
a workspace package declares). JavaScript-only repositories without a
|
|
45
|
+
tsconfig or jsconfig are checked with a default config: allowJs,
|
|
46
|
+
checkJs, strict false.
|
|
47
|
+
python: >-
|
|
48
|
+
pyright with the repository's configuration (pyrightconfig.json or
|
|
49
|
+
[tool.pyright]). If only mypy is configured, mypy with its
|
|
50
|
+
configuration. If both are configured, pyright. If neither,
|
|
51
|
+
pyright in basic mode.
|
|
52
|
+
not_applicable_when: null
|
|
53
|
+
rationale: >-
|
|
54
|
+
The repository's own config is used so the count reflects what its
|
|
55
|
+
developers see. A config error, or a checker that cannot start, is a
|
|
56
|
+
repository failure and scores 0. Untyped code is checked with a
|
|
57
|
+
default config on purpose, so "add types" is visible as a score change.
|
|
58
|
+
sources:
|
|
59
|
+
- "TypeScript: Type checking JavaScript files (checkJs). https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html"
|
|
60
|
+
- "Pyright configuration: typeCheckingMode. https://microsoft.github.io/pyright/#/configuration"
|
|
61
|
+
|
|
62
|
+
- id: "2.2"
|
|
63
|
+
key: declared_strictness
|
|
64
|
+
name: Declared strictness
|
|
65
|
+
layer: static
|
|
66
|
+
weight: 20
|
|
67
|
+
requires: []
|
|
68
|
+
pooling: unit_weighted
|
|
69
|
+
raw:
|
|
70
|
+
unit: level
|
|
71
|
+
definition: >-
|
|
72
|
+
The strictness the repository's typechecker configuration declares,
|
|
73
|
+
read from the config files without running anything.
|
|
74
|
+
when_empty: 0
|
|
75
|
+
scoring:
|
|
76
|
+
method: levels
|
|
77
|
+
levels:
|
|
78
|
+
typescript_javascript:
|
|
79
|
+
- level: none
|
|
80
|
+
score: 0
|
|
81
|
+
descriptor: >-
|
|
82
|
+
No strict-family flag is enabled, or JavaScript without
|
|
83
|
+
checkJs.
|
|
84
|
+
- level: partial
|
|
85
|
+
score: 40
|
|
86
|
+
descriptor: >-
|
|
87
|
+
Some strict-family flags are enabled, or strict is true with
|
|
88
|
+
one or more strict-family flags turned back off.
|
|
89
|
+
- level: strict
|
|
90
|
+
score: 75
|
|
91
|
+
descriptor: strict is true and no strict-family flag is turned off.
|
|
92
|
+
- level: strict_plus
|
|
93
|
+
score: 100
|
|
94
|
+
descriptor: strict plus noUncheckedIndexedAccess.
|
|
95
|
+
python:
|
|
96
|
+
- level: none
|
|
97
|
+
score: 0
|
|
98
|
+
descriptor: No pyright or mypy configuration.
|
|
99
|
+
- level: basic
|
|
100
|
+
score: 40
|
|
101
|
+
descriptor: pyright typeCheckingMode basic, or mypy with default settings.
|
|
102
|
+
- level: standard
|
|
103
|
+
score: 75
|
|
104
|
+
descriptor: >-
|
|
105
|
+
pyright typeCheckingMode standard (pyright's default when a
|
|
106
|
+
config exists), or mypy with disallow_untyped_defs and
|
|
107
|
+
check_untyped_defs.
|
|
108
|
+
- level: strict
|
|
109
|
+
score: 100
|
|
110
|
+
descriptor: pyright typeCheckingMode strict, or mypy strict = true.
|
|
111
|
+
measure:
|
|
112
|
+
typescript_javascript: >-
|
|
113
|
+
tsconfig.json with extends resolved. Strict-family flags: noImplicitAny,
|
|
114
|
+
strictNullChecks, strictFunctionTypes, strictBindCallApply,
|
|
115
|
+
strictPropertyInitialization, noImplicitThis, useUnknownInCatchVariables,
|
|
116
|
+
alwaysStrict.
|
|
117
|
+
python: >-
|
|
118
|
+
pyrightconfig.json, [tool.pyright] or [tool.basedpyright] in
|
|
119
|
+
pyproject.toml; mypy.ini, .mypy.ini, setup.cfg [mypy] or [tool.mypy]
|
|
120
|
+
in pyproject.toml. When both are configured, pyright's level is used.
|
|
121
|
+
not_applicable_when: null
|
|
122
|
+
rationale: >-
|
|
123
|
+
2.1 counts errors under whatever config the repository chose. Without
|
|
124
|
+
2.2, turning strictness off would raise the score. Strict null checks
|
|
125
|
+
catch access to null and undefined values, a common runtime error in
|
|
126
|
+
both languages. noUncheckedIndexedAccess
|
|
127
|
+
makes array and record lookups return possibly undefined values, which
|
|
128
|
+
is where strict TypeScript still lets runtime errors through.
|
|
129
|
+
sources:
|
|
130
|
+
- "TypeScript TSConfig reference: strict. https://www.typescriptlang.org/tsconfig#strict"
|
|
131
|
+
- "TypeScript TSConfig reference: noUncheckedIndexedAccess. https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess"
|
|
132
|
+
- "Pyright configuration: typeCheckingMode. https://microsoft.github.io/pyright/#/configuration"
|
|
133
|
+
- "mypy command line: --strict. https://mypy.readthedocs.io/en/stable/command_line.html"
|
|
134
|
+
|
|
135
|
+
- id: "2.3"
|
|
136
|
+
key: escape_hatches
|
|
137
|
+
name: Escape hatches
|
|
138
|
+
layer: static
|
|
139
|
+
weight: 20
|
|
140
|
+
requires: []
|
|
141
|
+
pooling: ratio
|
|
142
|
+
raw:
|
|
143
|
+
unit: escape hatches per 1,000 logic lines
|
|
144
|
+
definition: >-
|
|
145
|
+
Points where code opts out of the typechecker, counted in logic
|
|
146
|
+
files, divided by logic lines / 1,000. A file-level opt-out counts
|
|
147
|
+
as 10.
|
|
148
|
+
when_empty: 100
|
|
149
|
+
scoring:
|
|
150
|
+
method: piecewise_linear
|
|
151
|
+
anchors:
|
|
152
|
+
- raw: 0
|
|
153
|
+
score: 100
|
|
154
|
+
descriptor: The types are trusted everywhere.
|
|
155
|
+
- raw: 2
|
|
156
|
+
score: 75
|
|
157
|
+
descriptor: A few documented exceptions.
|
|
158
|
+
- raw: 5
|
|
159
|
+
score: 50
|
|
160
|
+
descriptor: Casts are a common way to make errors go away.
|
|
161
|
+
- raw: 15
|
|
162
|
+
score: 0
|
|
163
|
+
descriptor: The types say little about what the code does.
|
|
164
|
+
measure:
|
|
165
|
+
typescript_javascript: >-
|
|
166
|
+
Each counts 1: an explicit any type; an as assertion (as const is
|
|
167
|
+
excluded; each as in "as unknown as T" counts separately); an
|
|
168
|
+
angle-bracket assertion <T>x; a non-null assertion x!; a definite
|
|
169
|
+
assignment assertion x!: T; @ts-ignore; @ts-expect-error. Counts 10:
|
|
170
|
+
@ts-nocheck.
|
|
171
|
+
python: >-
|
|
172
|
+
Each counts 1: Any in an annotation; typing.cast(...); # type: ignore
|
|
173
|
+
on a line; # pyright: ignore on a line. Counts 10: # type: ignore
|
|
174
|
+
before the first statement of a module; # mypy: ignore-errors.
|
|
175
|
+
not_applicable_when: null
|
|
176
|
+
rationale: >-
|
|
177
|
+
Each escape hatch is a place where the typechecker cannot help the next
|
|
178
|
+
person. A change that breaks a contract passes the typechecker silently
|
|
179
|
+
at that point. The typescript-eslint no-unsafe-* rules are not used in
|
|
180
|
+
2.5, so the same problem is not counted twice.
|
|
181
|
+
sources: []
|
|
182
|
+
|
|
183
|
+
- id: "2.4"
|
|
184
|
+
key: typed_public_surface
|
|
185
|
+
name: Typed public surface
|
|
186
|
+
layer: static
|
|
187
|
+
weight: 15
|
|
188
|
+
requires: []
|
|
189
|
+
pooling: ratio
|
|
190
|
+
raw:
|
|
191
|
+
unit: percent
|
|
192
|
+
definition: >-
|
|
193
|
+
Typed slots / all slots on the public surface of logic files. In
|
|
194
|
+
TypeScript and JavaScript a slot is a parameter. In Python a slot is
|
|
195
|
+
a parameter or a return type.
|
|
196
|
+
when_empty: 100
|
|
197
|
+
scoring:
|
|
198
|
+
method: piecewise_linear
|
|
199
|
+
anchors:
|
|
200
|
+
- raw: 20
|
|
201
|
+
score: 0
|
|
202
|
+
descriptor: The public surface is untyped.
|
|
203
|
+
- raw: 50
|
|
204
|
+
score: 50
|
|
205
|
+
descriptor: Half of what callers use is typed.
|
|
206
|
+
- raw: 80
|
|
207
|
+
score: 75
|
|
208
|
+
descriptor: Most of what callers use is typed.
|
|
209
|
+
- raw: 100
|
|
210
|
+
score: 100
|
|
211
|
+
descriptor: Every public function says what it accepts.
|
|
212
|
+
measure:
|
|
213
|
+
typescript_javascript: >-
|
|
214
|
+
Public surface: exported functions, exported arrow functions and
|
|
215
|
+
function expressions, default exports, and public methods of
|
|
216
|
+
exported classes. A parameter is typed if it has a type annotation,
|
|
217
|
+
a default value, a contextual type (for example a callback passed to
|
|
218
|
+
a typed function), or a JSDoc @param type in a file checked with
|
|
219
|
+
checkJs.
|
|
220
|
+
python: >-
|
|
221
|
+
Public surface: module-level functions and classes whose names do not
|
|
222
|
+
start with _, and their methods whose names do not start with _
|
|
223
|
+
(dunder methods are included). If __all__ is defined, it decides
|
|
224
|
+
what is public. Modules whose names start with _ are excluded. self
|
|
225
|
+
and cls are not slots. __init__ needs no return annotation.
|
|
226
|
+
not_applicable_when: null
|
|
227
|
+
rationale: >-
|
|
228
|
+
The public surface is what the next person calls without reading the
|
|
229
|
+
body. In TypeScript, inferred return types are reliable, so only
|
|
230
|
+
parameters are counted. In Python, an unannotated return is Any, so
|
|
231
|
+
both are counted. Untyped JavaScript and untyped Python score low on
|
|
232
|
+
purpose.
|
|
233
|
+
sources:
|
|
234
|
+
- "PEP 484: Type Hints. https://peps.python.org/pep-0484/"
|
|
235
|
+
|
|
236
|
+
- id: "2.5"
|
|
237
|
+
key: baseline_lint
|
|
238
|
+
name: Baseline lint findings
|
|
239
|
+
layer: execution
|
|
240
|
+
weight: 20
|
|
241
|
+
requires: [install, lint_run]
|
|
242
|
+
pooling: ratio
|
|
243
|
+
raw:
|
|
244
|
+
unit: findings per 1,000 source lines
|
|
245
|
+
definition: >-
|
|
246
|
+
Findings from the methodology's pinned correctness ruleset in
|
|
247
|
+
in-scope files (logic and test), divided by source lines / 1,000.
|
|
248
|
+
The repository's own lint config is not used. A file that cannot be
|
|
249
|
+
parsed counts as one finding.
|
|
250
|
+
when_empty: 100
|
|
251
|
+
scoring:
|
|
252
|
+
method: piecewise_linear
|
|
253
|
+
anchors:
|
|
254
|
+
- raw: 0
|
|
255
|
+
score: 100
|
|
256
|
+
descriptor: No known bug patterns.
|
|
257
|
+
- raw: 2
|
|
258
|
+
score: 75
|
|
259
|
+
descriptor: A few.
|
|
260
|
+
- raw: 5
|
|
261
|
+
score: 50
|
|
262
|
+
descriptor: Bug patterns are common.
|
|
263
|
+
- raw: 20
|
|
264
|
+
score: 0
|
|
265
|
+
descriptor: The code has never been linted for correctness.
|
|
266
|
+
measure:
|
|
267
|
+
typescript_javascript: >-
|
|
268
|
+
ESLint with the pinned ruleset. Core rules: no-unreachable,
|
|
269
|
+
no-dupe-keys, no-self-compare, no-unsafe-finally, no-fallthrough,
|
|
270
|
+
no-cond-assign, use-isnan, valid-typeof, no-unsafe-optional-chaining,
|
|
271
|
+
no-dupe-else-if, no-duplicate-case, no-self-assign, getter-return,
|
|
272
|
+
no-async-promise-executor, no-constant-binary-expression,
|
|
273
|
+
no-unused-vars (or @typescript-eslint/no-unused-vars on TypeScript
|
|
274
|
+
files). Type-aware rules on TypeScript files only:
|
|
275
|
+
@typescript-eslint/no-floating-promises, no-misused-promises,
|
|
276
|
+
await-thenable. TypeScript files outside every tsconfig are linted
|
|
277
|
+
without the type-aware rules. react-hooks/rules-of-hooks when react is
|
|
278
|
+
a dependency.
|
|
279
|
+
python: ruff with the rule sets F (Pyflakes), B (flake8-bugbear) and E9 (syntax and IO errors).
|
|
280
|
+
not_applicable_when: null
|
|
281
|
+
rationale: >-
|
|
282
|
+
Each rule in the set catches a real bug pattern, such as an
|
|
283
|
+
unawaited promise or an unreachable branch. Style rules are excluded,
|
|
284
|
+
so formatting choices do not affect the score. The ruleset is pinned
|
|
285
|
+
so every repository is judged by the same rules, and so turning rules
|
|
286
|
+
off in the repository's own config does not raise the score.
|
|
287
|
+
sources:
|
|
288
|
+
- "typescript-eslint rules. https://typescript-eslint.io/rules/"
|
|
289
|
+
- "Ruff rules. https://docs.astral.sh/ruff/rules/"
|