vibecodedshit 0.0.0-stage → 0.3.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 +73 -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 +11 -0
- package/dist/card/previous.js +38 -0
- package/dist/card/render.js +71 -0
- package/dist/cli.js +138 -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 +28 -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/interactive/after-scan.js +121 -0
- package/dist/interactive/docker-setup.js +97 -0
- package/dist/interactive/prompt.js +17 -0
- package/dist/interactive/system.js +10 -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 +10 -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,266 @@
|
|
|
1
|
+
dimension:
|
|
2
|
+
id: 3
|
|
3
|
+
key: architecture_boundaries
|
|
4
|
+
name: Architecture & boundaries
|
|
5
|
+
question: Can you change one part without reading the rest?
|
|
6
|
+
agent_relevance: >-
|
|
7
|
+
An agent works inside a limited context window. Enforced boundaries
|
|
8
|
+
limit how much of the codebase one change can affect, so the agent only
|
|
9
|
+
needs to read the module it is changing and that module's public entry
|
|
10
|
+
points.
|
|
11
|
+
|
|
12
|
+
presets:
|
|
13
|
+
description: >-
|
|
14
|
+
When a repository declares no import rules, the scan uses the preset for
|
|
15
|
+
the detected framework (presets/*.yaml). When it declares rules (see
|
|
16
|
+
3.1), its rules replace the preset. Detection order: nextjs, express,
|
|
17
|
+
django, fastapi, generic. Each workspace package gets its own preset.
|
|
18
|
+
files:
|
|
19
|
+
- presets/nextjs.yaml
|
|
20
|
+
- presets/express.yaml
|
|
21
|
+
- presets/django.yaml
|
|
22
|
+
- presets/fastapi.yaml
|
|
23
|
+
- presets/generic.yaml
|
|
24
|
+
|
|
25
|
+
parameters:
|
|
26
|
+
- id: "3.1"
|
|
27
|
+
key: boundaries_declared
|
|
28
|
+
name: Boundaries declared and enforced
|
|
29
|
+
layer: static
|
|
30
|
+
weight: 15
|
|
31
|
+
requires: []
|
|
32
|
+
pooling: unit_weighted
|
|
33
|
+
raw:
|
|
34
|
+
unit: level
|
|
35
|
+
definition: >-
|
|
36
|
+
Whether the repository declares import rules in a supported rules
|
|
37
|
+
file, and whether CI runs them.
|
|
38
|
+
when_empty: 0
|
|
39
|
+
scoring:
|
|
40
|
+
method: levels
|
|
41
|
+
levels:
|
|
42
|
+
- level: none
|
|
43
|
+
score: 0
|
|
44
|
+
descriptor: No import rules are declared.
|
|
45
|
+
- level: declared
|
|
46
|
+
score: 50
|
|
47
|
+
descriptor: >-
|
|
48
|
+
A rules file declares at least one direction rule, but CI does
|
|
49
|
+
not run it.
|
|
50
|
+
- level: enforced
|
|
51
|
+
score: 100
|
|
52
|
+
descriptor: The rules are declared and CI runs them on pull requests.
|
|
53
|
+
measure:
|
|
54
|
+
typescript_javascript: >-
|
|
55
|
+
Rules file: .dependency-cruiser.{js,cjs,mjs,json}. Declared means at
|
|
56
|
+
least one forbidden or allowed rule whose from and to paths name
|
|
57
|
+
different directories. Enforced means a CI file invokes depcruise,
|
|
58
|
+
directly or through a package script or make target (up to 3 levels).
|
|
59
|
+
python: >-
|
|
60
|
+
Rules file: .importlinter, [importlinter] in setup.cfg, or
|
|
61
|
+
[tool.importlinter] in pyproject.toml. Declared means at least one
|
|
62
|
+
layers, forbidden or independence contract. Enforced means a CI file
|
|
63
|
+
invokes lint-imports, directly or through a script or make target.
|
|
64
|
+
ci_files: >-
|
|
65
|
+
.github/workflows/*, .gitlab-ci.yml, .circleci/config.yml,
|
|
66
|
+
bitbucket-pipelines.yml, azure-pipelines.yml.
|
|
67
|
+
not_applicable_when: null
|
|
68
|
+
rationale: >-
|
|
69
|
+
An architecture that exists only in people's heads is not visible to
|
|
70
|
+
an agent and erodes with each change. A rules file states the
|
|
71
|
+
architecture in a form a tool can check. Running it in CI is what stops
|
|
72
|
+
new violations.
|
|
73
|
+
sources:
|
|
74
|
+
- "dependency-cruiser rules reference. https://github.com/sverweij/dependency-cruiser/blob/main/doc/rules-reference.md"
|
|
75
|
+
- "import-linter contract types. https://import-linter.readthedocs.io/en/stable/contract_types.html"
|
|
76
|
+
|
|
77
|
+
- id: "3.2"
|
|
78
|
+
key: boundary_violations
|
|
79
|
+
name: Boundary violations
|
|
80
|
+
layer: static
|
|
81
|
+
weight: 30
|
|
82
|
+
requires: []
|
|
83
|
+
pooling: ratio
|
|
84
|
+
raw:
|
|
85
|
+
unit: violations per 1,000 imports
|
|
86
|
+
definition: >-
|
|
87
|
+
Import edges that break a rule, divided by all internal import edges
|
|
88
|
+
/ 1,000. Rules come from the repository's declared rules file, or
|
|
89
|
+
from the preset when none is declared. Rules with severity error or
|
|
90
|
+
warn count; info is ignored. Each violating edge counts once, even
|
|
91
|
+
when it breaks several rules. Imports from test files are excluded.
|
|
92
|
+
Type-only imports are included, except where a preset rule says
|
|
93
|
+
otherwise.
|
|
94
|
+
when_empty: 100
|
|
95
|
+
scoring:
|
|
96
|
+
method: piecewise_linear
|
|
97
|
+
anchors:
|
|
98
|
+
- raw: 0
|
|
99
|
+
score: 100
|
|
100
|
+
descriptor: Every import respects the architecture.
|
|
101
|
+
- raw: 2
|
|
102
|
+
score: 75
|
|
103
|
+
descriptor: A few known shortcuts.
|
|
104
|
+
- raw: 10
|
|
105
|
+
score: 50
|
|
106
|
+
descriptor: The layers exist in name only in places.
|
|
107
|
+
- raw: 30
|
|
108
|
+
score: 0
|
|
109
|
+
descriptor: Anything imports anything.
|
|
110
|
+
measure:
|
|
111
|
+
typescript_javascript: dependency-cruiser with the declared rules or the preset converted to dependency-cruiser rules.
|
|
112
|
+
python: grimp builds the import graph; import-linter checks the declared contracts or the preset converted to contracts.
|
|
113
|
+
not_applicable_when: null
|
|
114
|
+
rationale: >-
|
|
115
|
+
Each violation is a dependency a reader would not expect from the
|
|
116
|
+
directory structure. The count is normalized per 1,000 imports so
|
|
117
|
+
repositories of different sizes are comparable.
|
|
118
|
+
sources:
|
|
119
|
+
- "Martin, R. C. Clean Architecture. Prentice Hall, 2017 (the Dependency Rule)."
|
|
120
|
+
- "Cockburn, A. Hexagonal Architecture (Ports and Adapters), 2005. https://alistair.cockburn.us/hexagonal-architecture/"
|
|
121
|
+
|
|
122
|
+
- id: "3.3"
|
|
123
|
+
key: import_cycles
|
|
124
|
+
name: Import cycles
|
|
125
|
+
layer: static
|
|
126
|
+
weight: 25
|
|
127
|
+
requires: []
|
|
128
|
+
pooling: ratio
|
|
129
|
+
raw:
|
|
130
|
+
unit: percent
|
|
131
|
+
definition: >-
|
|
132
|
+
Logic files that belong to an import cycle / all logic files. A cycle
|
|
133
|
+
is a strongly connected component of two or more files in the graph
|
|
134
|
+
of module-level static imports. Type-only imports, dynamic imports,
|
|
135
|
+
imports inside functions and imports under
|
|
136
|
+
"if TYPE_CHECKING:" are excluded.
|
|
137
|
+
when_empty: 100
|
|
138
|
+
scoring:
|
|
139
|
+
method: piecewise_linear
|
|
140
|
+
anchors:
|
|
141
|
+
- raw: 0
|
|
142
|
+
score: 100
|
|
143
|
+
descriptor: The import graph has no cycles.
|
|
144
|
+
- raw: 2
|
|
145
|
+
score: 75
|
|
146
|
+
descriptor: One or two small cycles.
|
|
147
|
+
- raw: 5
|
|
148
|
+
score: 50
|
|
149
|
+
descriptor: Cycles connect several areas.
|
|
150
|
+
- raw: 15
|
|
151
|
+
score: 0
|
|
152
|
+
descriptor: Large parts of the code depend on each other.
|
|
153
|
+
measure:
|
|
154
|
+
typescript_javascript: dependency-cruiser cycle detection on the filtered graph.
|
|
155
|
+
python: grimp import graph, filtered as defined, then strongly connected components.
|
|
156
|
+
not_applicable_when: null
|
|
157
|
+
rationale: >-
|
|
158
|
+
Files in a cycle cannot be understood, tested or changed one at a time.
|
|
159
|
+
Cycles also cause import-order bugs at runtime, especially in Python.
|
|
160
|
+
Type-only imports are excluded because they have no runtime effect.
|
|
161
|
+
sources:
|
|
162
|
+
- "Martin, R. C. Agile Software Development: Principles, Patterns, and Practices. Prentice Hall, 2002 (the Acyclic Dependencies Principle)."
|
|
163
|
+
|
|
164
|
+
- id: "3.4"
|
|
165
|
+
key: public_entry_discipline
|
|
166
|
+
name: Public-entry discipline
|
|
167
|
+
layer: static
|
|
168
|
+
weight: 15
|
|
169
|
+
requires: []
|
|
170
|
+
pooling: ratio
|
|
171
|
+
raw:
|
|
172
|
+
unit: percent
|
|
173
|
+
definition: >-
|
|
174
|
+
Imports that cross from one module into another and land on that
|
|
175
|
+
module's public entry / all imports that cross between modules.
|
|
176
|
+
Modules are defined by the preset (or by the independence or layer
|
|
177
|
+
contracts in the declared rules). The public entry is index.* in
|
|
178
|
+
TypeScript and JavaScript, and __init__.py in Python.
|
|
179
|
+
when_empty: 100
|
|
180
|
+
scoring:
|
|
181
|
+
method: piecewise_linear
|
|
182
|
+
anchors:
|
|
183
|
+
- raw: 50
|
|
184
|
+
score: 0
|
|
185
|
+
descriptor: Other modules reach into internals as often as not.
|
|
186
|
+
- raw: 75
|
|
187
|
+
score: 50
|
|
188
|
+
descriptor: Entry points exist and are often bypassed.
|
|
189
|
+
- raw: 90
|
|
190
|
+
score: 75
|
|
191
|
+
descriptor: Entry points are mostly used.
|
|
192
|
+
- raw: 100
|
|
193
|
+
score: 100
|
|
194
|
+
descriptor: Every cross-module import goes through the entry point.
|
|
195
|
+
measure:
|
|
196
|
+
typescript_javascript: Import graph from dependency-cruiser; module roots from the preset.
|
|
197
|
+
python: >-
|
|
198
|
+
grimp import graph; module roots from the preset. In Django apps,
|
|
199
|
+
models, services and selectors are also public entries.
|
|
200
|
+
not_applicable_when: >-
|
|
201
|
+
The repository has fewer than two modules as defined by the preset or
|
|
202
|
+
the declared rules. Splitting code into modules is a design choice the
|
|
203
|
+
methodology does not score.
|
|
204
|
+
rationale: >-
|
|
205
|
+
A public entry point is a small interface the next person can read
|
|
206
|
+
instead of the whole module. When other modules import internals
|
|
207
|
+
directly, every internal file becomes part of the interface and cannot
|
|
208
|
+
be changed safely.
|
|
209
|
+
sources:
|
|
210
|
+
- "HackSoft Django Styleguide. https://github.com/HackSoftware/Django-Styleguide"
|
|
211
|
+
|
|
212
|
+
- id: "3.5"
|
|
213
|
+
key: domain_purity
|
|
214
|
+
name: Domain purity
|
|
215
|
+
layer: static
|
|
216
|
+
weight: 15
|
|
217
|
+
requires: []
|
|
218
|
+
pooling: ratio
|
|
219
|
+
raw:
|
|
220
|
+
unit: percent
|
|
221
|
+
definition: >-
|
|
222
|
+
Files in the domain layer that import a framework, database, network
|
|
223
|
+
or filesystem package, or an infrastructure directory / all files in
|
|
224
|
+
the domain layer.
|
|
225
|
+
when_empty: 100
|
|
226
|
+
scoring:
|
|
227
|
+
method: piecewise_linear
|
|
228
|
+
anchors:
|
|
229
|
+
- raw: 0
|
|
230
|
+
score: 100
|
|
231
|
+
descriptor: Domain logic is plain code that runs and tests without infrastructure.
|
|
232
|
+
- raw: 5
|
|
233
|
+
score: 75
|
|
234
|
+
descriptor: A few domain files touch infrastructure.
|
|
235
|
+
- raw: 15
|
|
236
|
+
score: 50
|
|
237
|
+
descriptor: Domain logic regularly reaches for the database or the network.
|
|
238
|
+
- raw: 40
|
|
239
|
+
score: 0
|
|
240
|
+
descriptor: The domain layer is a directory name.
|
|
241
|
+
measure:
|
|
242
|
+
domain_layer: >-
|
|
243
|
+
Files under a directory named domain, or files in a layer named
|
|
244
|
+
domain in the declared rules.
|
|
245
|
+
typescript_javascript: >-
|
|
246
|
+
Forbidden imports: next, react, react-dom, express, @prisma/client,
|
|
247
|
+
drizzle-orm, pg, mysql2, mongoose, redis, ioredis, axios, node-fetch,
|
|
248
|
+
fs, node:fs, http, node:http, https, node:https. A call to the global
|
|
249
|
+
fetch also counts.
|
|
250
|
+
python: >-
|
|
251
|
+
Forbidden imports: django, fastapi, flask, starlette, sqlalchemy,
|
|
252
|
+
requests, httpx, aiohttp, boto3, psycopg, psycopg2, redis, pymongo.
|
|
253
|
+
A call to the builtin open also counts.
|
|
254
|
+
infrastructure_directories: infrastructure, infra, db, adapters.
|
|
255
|
+
not_applicable_when: >-
|
|
256
|
+
The repository declares no domain layer. Choosing a layered or
|
|
257
|
+
domain-driven design is a design choice the methodology does not score.
|
|
258
|
+
rationale: >-
|
|
259
|
+
This is the deterministic part of domain-driven design alignment. Pure
|
|
260
|
+
domain code can be tested without a database or network and changed
|
|
261
|
+
without reading infrastructure code. The methodology does not judge
|
|
262
|
+
whether the domain model is good; it checks that the repository keeps
|
|
263
|
+
the boundary it declared.
|
|
264
|
+
sources:
|
|
265
|
+
- "Evans, E. Domain-Driven Design. Addison-Wesley, 2003."
|
|
266
|
+
- "Cockburn, A. Hexagonal Architecture (Ports and Adapters), 2005. https://alistair.cockburn.us/hexagonal-architecture/"
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
dimension:
|
|
2
|
+
id: 4
|
|
3
|
+
key: complexity_maintainability
|
|
4
|
+
name: Complexity & maintainability
|
|
5
|
+
question: How much does someone have to read to make one change correctly?
|
|
6
|
+
agent_relevance: >-
|
|
7
|
+
Every line an agent reads uses context. Long files, complex functions,
|
|
8
|
+
duplicated logic and dead code all increase how much it must read, and
|
|
9
|
+
duplicated logic is where an agent fixes one copy and misses the other.
|
|
10
|
+
|
|
11
|
+
parameters:
|
|
12
|
+
- id: "4.1"
|
|
13
|
+
key: complex_functions
|
|
14
|
+
name: Complex functions
|
|
15
|
+
layer: static
|
|
16
|
+
weight: 30
|
|
17
|
+
requires: []
|
|
18
|
+
pooling: ratio
|
|
19
|
+
raw:
|
|
20
|
+
unit: percent
|
|
21
|
+
definition: >-
|
|
22
|
+
Functions with cognitive complexity strictly greater than 15 / all
|
|
23
|
+
functions in logic files, as enumerated by the tool.
|
|
24
|
+
when_empty: 100
|
|
25
|
+
scoring:
|
|
26
|
+
method: piecewise_linear
|
|
27
|
+
anchors:
|
|
28
|
+
- raw: 0
|
|
29
|
+
score: 100
|
|
30
|
+
descriptor: Every function can be read in one pass.
|
|
31
|
+
- raw: 3
|
|
32
|
+
score: 75
|
|
33
|
+
descriptor: A few hard functions.
|
|
34
|
+
- raw: 8
|
|
35
|
+
score: 50
|
|
36
|
+
descriptor: Hard functions in most areas.
|
|
37
|
+
- raw: 20
|
|
38
|
+
score: 0
|
|
39
|
+
descriptor: Logic is concentrated in functions nobody wants to touch.
|
|
40
|
+
measure:
|
|
41
|
+
typescript_javascript: eslint-plugin-sonarjs cognitive-complexity rule, threshold 15.
|
|
42
|
+
python: complexipy, threshold 15.
|
|
43
|
+
not_applicable_when: null
|
|
44
|
+
rationale: >-
|
|
45
|
+
Cognitive complexity counts nesting and breaks in linear flow, which
|
|
46
|
+
is closer to how hard a function is to read than cyclomatic
|
|
47
|
+
complexity. 15 is the default threshold in SonarQube, eslint-plugin-sonarjs
|
|
48
|
+
and complexipy. Counting the share of functions over the threshold,
|
|
49
|
+
instead of the mean, keeps many small functions from hiding a few
|
|
50
|
+
large ones.
|
|
51
|
+
sources:
|
|
52
|
+
- "Campbell, G. A. Cognitive Complexity: A new way of measuring understandability. SonarSource, 2018. https://www.sonarsource.com/docs/CognitiveComplexity.pdf"
|
|
53
|
+
- "SonarQube rule S3776 (Cognitive Complexity of functions should not be too high), default threshold 15."
|
|
54
|
+
- "McCabe, T. J. A Complexity Measure. IEEE Transactions on Software Engineering, 1976 (cyclomatic complexity, threshold 10)."
|
|
55
|
+
|
|
56
|
+
- id: "4.2"
|
|
57
|
+
key: large_files
|
|
58
|
+
name: Lines in large files
|
|
59
|
+
layer: static
|
|
60
|
+
weight: 20
|
|
61
|
+
requires: []
|
|
62
|
+
pooling: ratio
|
|
63
|
+
raw:
|
|
64
|
+
unit: percent
|
|
65
|
+
definition: >-
|
|
66
|
+
Logic lines in logic files with more than 500 logic lines / all logic
|
|
67
|
+
lines.
|
|
68
|
+
when_empty: 100
|
|
69
|
+
scoring:
|
|
70
|
+
method: piecewise_linear
|
|
71
|
+
anchors:
|
|
72
|
+
- raw: 0
|
|
73
|
+
score: 100
|
|
74
|
+
descriptor: Every file fits in one read.
|
|
75
|
+
- raw: 10
|
|
76
|
+
score: 75
|
|
77
|
+
descriptor: A few large files.
|
|
78
|
+
- raw: 25
|
|
79
|
+
score: 50
|
|
80
|
+
descriptor: A quarter of the code lives in large files.
|
|
81
|
+
- raw: 50
|
|
82
|
+
score: 0
|
|
83
|
+
descriptor: Most of the code lives in files too large to read whole.
|
|
84
|
+
measure:
|
|
85
|
+
typescript_javascript: Logic line count per file (scope.yaml).
|
|
86
|
+
python: Logic line count per file (scope.yaml); docstrings do not count.
|
|
87
|
+
not_applicable_when: null
|
|
88
|
+
rationale: >-
|
|
89
|
+
A large file has to be read in parts, so changes to it are made with
|
|
90
|
+
partial context. The threshold of 500 logic lines is more lenient than
|
|
91
|
+
ESLint's max-lines default (300 physical lines) and stricter than
|
|
92
|
+
Pylint's max-module-lines default (1,000). The raw value is a share of
|
|
93
|
+
lines, not of files, so one 5,000-line file weighs more than one
|
|
94
|
+
501-line file.
|
|
95
|
+
sources:
|
|
96
|
+
- "ESLint max-lines rule, default 300. https://eslint.org/docs/latest/rules/max-lines"
|
|
97
|
+
- "Pylint too-many-lines (C0302), max-module-lines default 1000."
|
|
98
|
+
|
|
99
|
+
- id: "4.3"
|
|
100
|
+
key: duplication
|
|
101
|
+
name: Duplication
|
|
102
|
+
layer: static
|
|
103
|
+
weight: 25
|
|
104
|
+
requires: []
|
|
105
|
+
pooling: ratio
|
|
106
|
+
raw:
|
|
107
|
+
unit: percent
|
|
108
|
+
definition: Duplicated lines / all lines in logic files, as reported by jscpd.
|
|
109
|
+
when_empty: 100
|
|
110
|
+
scoring:
|
|
111
|
+
method: piecewise_linear
|
|
112
|
+
anchors:
|
|
113
|
+
- raw: 3
|
|
114
|
+
score: 100
|
|
115
|
+
descriptor: Duplication is incidental.
|
|
116
|
+
- raw: 5
|
|
117
|
+
score: 75
|
|
118
|
+
descriptor: Some copied blocks.
|
|
119
|
+
- raw: 10
|
|
120
|
+
score: 50
|
|
121
|
+
descriptor: Copy and paste is a common way to add features.
|
|
122
|
+
- raw: 20
|
|
123
|
+
score: 0
|
|
124
|
+
descriptor: Large parts of the logic exist in several copies.
|
|
125
|
+
measure:
|
|
126
|
+
typescript_javascript: jscpd, min-tokens 50, min-lines 5, logic files only.
|
|
127
|
+
python: jscpd, same settings.
|
|
128
|
+
not_applicable_when: null
|
|
129
|
+
rationale: >-
|
|
130
|
+
A bug fixed in one copy stays in the others. This is a common agent
|
|
131
|
+
mistake: the agent finds one copy, fixes it, and its tests pass. 3% is
|
|
132
|
+
the default duplication limit in SonarQube's quality gate.
|
|
133
|
+
sources:
|
|
134
|
+
- "SonarQube default quality gate (Sonar way): duplicated lines on new code at most 3%."
|
|
135
|
+
- "jscpd. https://github.com/kucherenko/jscpd"
|
|
136
|
+
|
|
137
|
+
- id: "4.4"
|
|
138
|
+
key: dead_code
|
|
139
|
+
name: Unused exports and files
|
|
140
|
+
layer: static
|
|
141
|
+
weight: 25
|
|
142
|
+
requires: []
|
|
143
|
+
pooling: ratio
|
|
144
|
+
raw:
|
|
145
|
+
unit: percent
|
|
146
|
+
definition: >-
|
|
147
|
+
(Unused exported symbols + exported symbols in unused files) / all
|
|
148
|
+
exported symbols in logic files. Exported types count. Library entry
|
|
149
|
+
points (package.json exports and main, Python __all__ of a
|
|
150
|
+
distributed package) count as used.
|
|
151
|
+
when_empty: 100
|
|
152
|
+
scoring:
|
|
153
|
+
method: piecewise_linear
|
|
154
|
+
anchors:
|
|
155
|
+
- raw: 0
|
|
156
|
+
score: 100
|
|
157
|
+
descriptor: Everything exported is used.
|
|
158
|
+
- raw: 3
|
|
159
|
+
score: 75
|
|
160
|
+
descriptor: A little dead code.
|
|
161
|
+
- raw: 8
|
|
162
|
+
score: 50
|
|
163
|
+
descriptor: Dead code is common.
|
|
164
|
+
- raw: 20
|
|
165
|
+
score: 0
|
|
166
|
+
descriptor: A large share of the code is never called.
|
|
167
|
+
measure:
|
|
168
|
+
typescript_javascript: knip (unused files, exports and types), with framework plugins enabled.
|
|
169
|
+
python: >-
|
|
170
|
+
vulture with min-confidence 60 for unused functions, classes and
|
|
171
|
+
methods; decorated definitions are treated as used. A method is
|
|
172
|
+
also treated as used when its class, directly or through base
|
|
173
|
+
classes defined in the repository, has a base class defined
|
|
174
|
+
outside the repository (standard library or third party), or when
|
|
175
|
+
a base class defined in the repository has a method of the same
|
|
176
|
+
name; object and Generic do not count as bases. Unused modules:
|
|
177
|
+
modules no other module imports, excluding entry modules (__main__,
|
|
178
|
+
manage.py, wsgi, asgi, settings, conftest, targets of
|
|
179
|
+
[project.scripts], Django convention modules such as models, admin,
|
|
180
|
+
apps, urls, views, and FastAPI main.py).
|
|
181
|
+
not_applicable_when: null
|
|
182
|
+
rationale: >-
|
|
183
|
+
Dead code costs reading time and looks like a place to make a change.
|
|
184
|
+
An agent that edits an unused function gets no test failure and no
|
|
185
|
+
effect. Decorated Python definitions are treated as used because
|
|
186
|
+
frameworks register them by decorator (routes, fixtures, signals).
|
|
187
|
+
Methods that override a base class are treated as used for the same
|
|
188
|
+
reason: frameworks and the standard library call hooks such as
|
|
189
|
+
do_GET, setUp or emit by name, which vulture cannot see.
|
|
190
|
+
sources:
|
|
191
|
+
- "knip. https://knip.dev"
|
|
192
|
+
- "vulture. https://github.com/jendrikseipp/vulture"
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
dimension:
|
|
2
|
+
id: 5
|
|
3
|
+
key: dependency_security_hygiene
|
|
4
|
+
name: Dependency & security hygiene
|
|
5
|
+
question: Is the code built on parts that are known, current and safe?
|
|
6
|
+
agent_relevance: >-
|
|
7
|
+
An agent adds dependencies and copies patterns from what it finds. An
|
|
8
|
+
undeclared dependency, a stale major version or a committed secret gets
|
|
9
|
+
copied into new code the same way good patterns do.
|
|
10
|
+
|
|
11
|
+
as_of_date: >-
|
|
12
|
+
Parameters 5.1 and 5.2 are evaluated at the run's as-of date: advisories
|
|
13
|
+
published on or before that date count, and the latest version of a
|
|
14
|
+
package is the latest published on or before that date.
|
|
15
|
+
|
|
16
|
+
parameters:
|
|
17
|
+
- id: "5.1"
|
|
18
|
+
key: known_vulnerabilities
|
|
19
|
+
name: Known vulnerabilities in production dependencies
|
|
20
|
+
layer: static
|
|
21
|
+
weight: 30
|
|
22
|
+
requires: []
|
|
23
|
+
pooling: ratio
|
|
24
|
+
raw:
|
|
25
|
+
unit: severity points
|
|
26
|
+
definition: >-
|
|
27
|
+
Sum of severity points over advisories affecting resolved production
|
|
28
|
+
dependencies (direct and transitive). Critical 10, high 5, moderate 2,
|
|
29
|
+
low 0.5. Each advisory counts once per package; aliases are
|
|
30
|
+
deduplicated. Withdrawn advisories are excluded.
|
|
31
|
+
when_empty: 100
|
|
32
|
+
scoring:
|
|
33
|
+
method: piecewise_linear
|
|
34
|
+
anchors:
|
|
35
|
+
- raw: 0
|
|
36
|
+
score: 100
|
|
37
|
+
descriptor: No known vulnerabilities.
|
|
38
|
+
- raw: 2
|
|
39
|
+
score: 75
|
|
40
|
+
descriptor: One moderate, or a few low.
|
|
41
|
+
- raw: 10
|
|
42
|
+
score: 50
|
|
43
|
+
descriptor: A critical, or several highs.
|
|
44
|
+
- raw: 30
|
|
45
|
+
score: 0
|
|
46
|
+
descriptor: Several criticals. Nobody is watching.
|
|
47
|
+
measure:
|
|
48
|
+
typescript_javascript: osv-scanner on the lockfile, against the OSV snapshot for the as-of date. Production dependencies only.
|
|
49
|
+
python: osv-scanner on the lockfile, against the OSV snapshot for the as-of date. Production dependencies only.
|
|
50
|
+
severity: >-
|
|
51
|
+
The GitHub Security Advisory severity label when present. Otherwise
|
|
52
|
+
the CVSS v3.1 base score band (critical 9.0-10.0, high 7.0-8.9,
|
|
53
|
+
moderate 4.0-6.9, low 0.1-3.9). Otherwise moderate.
|
|
54
|
+
not_applicable_when: null
|
|
55
|
+
rationale: >-
|
|
56
|
+
Severity points stop one critical advisory from scoring the same as
|
|
57
|
+
one low one. The count is not normalized by repository size, because
|
|
58
|
+
a vulnerability's risk does not shrink as the codebase grows.
|
|
59
|
+
Development-only dependencies are reported separately and not scored.
|
|
60
|
+
sources:
|
|
61
|
+
- "OSV schema (published, withdrawn, aliases). https://ossf.github.io/osv-schema/"
|
|
62
|
+
- "FIRST. CVSS v3.1 Specification, qualitative severity rating scale. https://www.first.org/cvss/v3.1/specification-document"
|
|
63
|
+
|
|
64
|
+
- id: "5.2"
|
|
65
|
+
key: major_versions_behind
|
|
66
|
+
name: Dependencies a major version behind
|
|
67
|
+
layer: static
|
|
68
|
+
weight: 20
|
|
69
|
+
requires: []
|
|
70
|
+
pooling: ratio
|
|
71
|
+
raw:
|
|
72
|
+
unit: percent
|
|
73
|
+
definition: >-
|
|
74
|
+
Direct dependencies (production and development) whose resolved
|
|
75
|
+
version is at least one major version behind the highest stable,
|
|
76
|
+
non-yanked version published on or before the as-of date / all direct
|
|
77
|
+
dependencies. For 0.x versions, a minor version bump counts as major.
|
|
78
|
+
when_empty: 100
|
|
79
|
+
scoring:
|
|
80
|
+
method: piecewise_linear
|
|
81
|
+
anchors:
|
|
82
|
+
- raw: 0
|
|
83
|
+
score: 100
|
|
84
|
+
descriptor: Every direct dependency is on its current major.
|
|
85
|
+
- raw: 10
|
|
86
|
+
score: 75
|
|
87
|
+
descriptor: A few dependencies are behind.
|
|
88
|
+
- raw: 25
|
|
89
|
+
score: 50
|
|
90
|
+
descriptor: A quarter of dependencies are behind.
|
|
91
|
+
- raw: 50
|
|
92
|
+
score: 0
|
|
93
|
+
descriptor: Upgrades have stopped.
|
|
94
|
+
measure:
|
|
95
|
+
typescript_javascript: npm registry publish times from the registry snapshot.
|
|
96
|
+
python: PyPI release upload times from the registry snapshot.
|
|
97
|
+
not_applicable_when: null
|
|
98
|
+
rationale: >-
|
|
99
|
+
Each major version behind is a migration someone will have to do, and
|
|
100
|
+
an agent writing code against current documentation will use APIs the
|
|
101
|
+
installed version does not have. Development dependencies are included
|
|
102
|
+
because outdated tooling affects every change.
|
|
103
|
+
sources:
|
|
104
|
+
- "Semantic Versioning 2.0.0, item 4 (major version zero). https://semver.org"
|
|
105
|
+
|
|
106
|
+
- id: "5.3"
|
|
107
|
+
key: lockfile
|
|
108
|
+
name: Lockfile
|
|
109
|
+
layer: static
|
|
110
|
+
weight: 15
|
|
111
|
+
requires: []
|
|
112
|
+
pooling: unit_weighted
|
|
113
|
+
raw:
|
|
114
|
+
unit: level
|
|
115
|
+
definition: Whether a lockfile exists and matches the manifest.
|
|
116
|
+
when_empty: 0
|
|
117
|
+
scoring:
|
|
118
|
+
method: levels
|
|
119
|
+
levels:
|
|
120
|
+
- level: none
|
|
121
|
+
score: 0
|
|
122
|
+
descriptor: No lockfile. Every install can resolve different versions.
|
|
123
|
+
- level: out_of_sync
|
|
124
|
+
score: 40
|
|
125
|
+
descriptor: A lockfile exists but does not match the manifest.
|
|
126
|
+
- level: in_sync
|
|
127
|
+
score: 100
|
|
128
|
+
descriptor: The lockfile matches the manifest.
|
|
129
|
+
measure:
|
|
130
|
+
typescript_javascript: >-
|
|
131
|
+
package-lock.json, npm-shrinkwrap.json, pnpm-lock.yaml, yarn.lock or
|
|
132
|
+
bun.lock. In sync means every dependency declared in package.json is
|
|
133
|
+
present in the lockfile with a version that satisfies its range.
|
|
134
|
+
python: >-
|
|
135
|
+
uv.lock, poetry.lock, pdm.lock, Pipfile.lock, or requirements files
|
|
136
|
+
with every requirement pinned with == and --hash. In sync means
|
|
137
|
+
every dependency declared in pyproject.toml (or Pipfile) is in the
|
|
138
|
+
lockfile with a version that satisfies its specifier, or for
|
|
139
|
+
uv.lock and poetry.lock, the lockfile's recorded manifest hash
|
|
140
|
+
matches.
|
|
141
|
+
not_applicable_when: null
|
|
142
|
+
rationale: >-
|
|
143
|
+
Without a lockfile, two installs of the same commit can produce
|
|
144
|
+
different code. Results stop being reproducible, including this
|
|
145
|
+
methodology's results.
|
|
146
|
+
sources:
|
|
147
|
+
- "npm ci documentation. https://docs.npmjs.com/cli/commands/npm-ci"
|
|
148
|
+
|
|
149
|
+
- id: "5.4"
|
|
150
|
+
key: secrets_in_tree
|
|
151
|
+
name: Secrets in the working tree
|
|
152
|
+
layer: static
|
|
153
|
+
weight: 20
|
|
154
|
+
requires: []
|
|
155
|
+
pooling: unit_weighted
|
|
156
|
+
raw:
|
|
157
|
+
unit: count
|
|
158
|
+
definition: >-
|
|
159
|
+
Secrets found by the pinned gitleaks default ruleset in every
|
|
160
|
+
tracked file at the scanned commit. .healthignore does not apply.
|
|
161
|
+
.gitleaksignore applies and is part of the ignore set.
|
|
162
|
+
when_empty: 100
|
|
163
|
+
scoring:
|
|
164
|
+
method: piecewise_linear
|
|
165
|
+
anchors:
|
|
166
|
+
- raw: 0
|
|
167
|
+
score: 100
|
|
168
|
+
descriptor: No secrets in the code.
|
|
169
|
+
- raw: 1
|
|
170
|
+
score: 0
|
|
171
|
+
descriptor: At least one secret is in the code.
|
|
172
|
+
measure:
|
|
173
|
+
all_languages: gitleaks dir on the checkout, default ruleset of the pinned version.
|
|
174
|
+
not_applicable_when: null
|
|
175
|
+
rationale: >-
|
|
176
|
+
One committed secret is enough to cause a breach, so the parameter is
|
|
177
|
+
binary. Secrets in git history are reported but not scored, because
|
|
178
|
+
the fix is rotating the key, which cannot be seen in the code.
|
|
179
|
+
sources:
|
|
180
|
+
- "CWE-798: Use of Hard-coded Credentials. https://cwe.mitre.org/data/definitions/798.html"
|
|
181
|
+
- "gitleaks. https://github.com/gitleaks/gitleaks"
|
|
182
|
+
|
|
183
|
+
- id: "5.5"
|
|
184
|
+
key: declaration_errors
|
|
185
|
+
name: Dependency declaration errors
|
|
186
|
+
layer: static
|
|
187
|
+
weight: 15
|
|
188
|
+
requires: []
|
|
189
|
+
pooling: ratio
|
|
190
|
+
raw:
|
|
191
|
+
unit: percent
|
|
192
|
+
definition: >-
|
|
193
|
+
(Declared dependencies that are never imported + imported packages
|
|
194
|
+
that are not declared) / declared direct dependencies.
|
|
195
|
+
when_empty: 100
|
|
196
|
+
scoring:
|
|
197
|
+
method: piecewise_linear
|
|
198
|
+
anchors:
|
|
199
|
+
- raw: 0
|
|
200
|
+
score: 100
|
|
201
|
+
descriptor: The manifest matches the code.
|
|
202
|
+
- raw: 5
|
|
203
|
+
score: 75
|
|
204
|
+
descriptor: A few stale or missing entries.
|
|
205
|
+
- raw: 15
|
|
206
|
+
score: 50
|
|
207
|
+
descriptor: The manifest and the code have drifted apart.
|
|
208
|
+
- raw: 30
|
|
209
|
+
score: 0
|
|
210
|
+
descriptor: Nobody maintains the manifest.
|
|
211
|
+
measure:
|
|
212
|
+
typescript_javascript: knip unused dependencies plus unlisted dependencies.
|
|
213
|
+
python: >-
|
|
214
|
+
deptry DEP001 (missing), DEP002 (unused) and DEP003 (transitive
|
|
215
|
+
imported directly). DEP004 (development dependency used in
|
|
216
|
+
production code) is not counted.
|
|
217
|
+
not_applicable_when: null
|
|
218
|
+
rationale: >-
|
|
219
|
+
An undeclared import works until the transitive dependency that
|
|
220
|
+
provides it changes. An unused declaration adds install time and
|
|
221
|
+
attack surface. Both mislead a reader about what the code depends on.
|
|
222
|
+
sources:
|
|
223
|
+
- "deptry rules. https://deptry.com/rules-violations/"
|