codetruth 0.2.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.
Files changed (53) hide show
  1. codetruth-0.2.0/LICENSE +21 -0
  2. codetruth-0.2.0/PKG-INFO +215 -0
  3. codetruth-0.2.0/README.md +180 -0
  4. codetruth-0.2.0/codetruth/__init__.py +16 -0
  5. codetruth-0.2.0/codetruth/api.py +102 -0
  6. codetruth-0.2.0/codetruth/cli.py +183 -0
  7. codetruth-0.2.0/codetruth/core/__init__.py +0 -0
  8. codetruth-0.2.0/codetruth/core/cache.py +104 -0
  9. codetruth-0.2.0/codetruth/core/config.py +74 -0
  10. codetruth-0.2.0/codetruth/core/deletion.py +165 -0
  11. codetruth-0.2.0/codetruth/core/evidence.py +306 -0
  12. codetruth-0.2.0/codetruth/core/graph.py +44 -0
  13. codetruth-0.2.0/codetruth/core/models.py +193 -0
  14. codetruth-0.2.0/codetruth/core/plugin.py +88 -0
  15. codetruth-0.2.0/codetruth/core/report.py +107 -0
  16. codetruth-0.2.0/codetruth/core/scanner.py +228 -0
  17. codetruth-0.2.0/codetruth/languages/__init__.py +0 -0
  18. codetruth-0.2.0/codetruth/languages/go/__init__.py +1 -0
  19. codetruth-0.2.0/codetruth/languages/javascript/__init__.py +8 -0
  20. codetruth-0.2.0/codetruth/languages/javascript/edges.py +361 -0
  21. codetruth-0.2.0/codetruth/languages/javascript/extractor.py +402 -0
  22. codetruth-0.2.0/codetruth/languages/javascript/plugin.py +52 -0
  23. codetruth-0.2.0/codetruth/languages/javascript/rules.py +201 -0
  24. codetruth-0.2.0/codetruth/languages/python/__init__.py +0 -0
  25. codetruth-0.2.0/codetruth/languages/python/edges.py +474 -0
  26. codetruth-0.2.0/codetruth/languages/python/extractor.py +271 -0
  27. codetruth-0.2.0/codetruth/languages/python/plugin.py +49 -0
  28. codetruth-0.2.0/codetruth/languages/python/rules.py +332 -0
  29. codetruth-0.2.0/codetruth/mcp_server.py +138 -0
  30. codetruth-0.2.0/codetruth/rules/python/common_dynamic.yaml +70 -0
  31. codetruth-0.2.0/codetruth/rules/python/django.yaml +57 -0
  32. codetruth-0.2.0/codetruth/rules/python/fastapi.yaml +38 -0
  33. codetruth-0.2.0/codetruth/rules/python/orm_web.yaml +50 -0
  34. codetruth-0.2.0/codetruth/runtime/__init__.py +283 -0
  35. codetruth-0.2.0/codetruth.egg-info/PKG-INFO +215 -0
  36. codetruth-0.2.0/codetruth.egg-info/SOURCES.txt +51 -0
  37. codetruth-0.2.0/codetruth.egg-info/dependency_links.txt +1 -0
  38. codetruth-0.2.0/codetruth.egg-info/entry_points.txt +2 -0
  39. codetruth-0.2.0/codetruth.egg-info/requires.txt +17 -0
  40. codetruth-0.2.0/codetruth.egg-info/top_level.txt +1 -0
  41. codetruth-0.2.0/pyproject.toml +51 -0
  42. codetruth-0.2.0/setup.cfg +4 -0
  43. codetruth-0.2.0/tests/test_api_cli.py +51 -0
  44. codetruth-0.2.0/tests/test_cache.py +88 -0
  45. codetruth-0.2.0/tests/test_config_strict.py +115 -0
  46. codetruth-0.2.0/tests/test_deletion_plan.py +47 -0
  47. codetruth-0.2.0/tests/test_evidence.py +209 -0
  48. codetruth-0.2.0/tests/test_extractor.py +42 -0
  49. codetruth-0.2.0/tests/test_javascript.py +88 -0
  50. codetruth-0.2.0/tests/test_reporting.py +58 -0
  51. codetruth-0.2.0/tests/test_rule_packs.py +68 -0
  52. codetruth-0.2.0/tests/test_runtime.py +161 -0
  53. codetruth-0.2.0/tests/test_validation.py +78 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alaik Asif Sheik
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,215 @@
1
+ Metadata-Version: 2.4
2
+ Name: codetruth
3
+ Version: 0.2.0
4
+ Summary: A verification layer that lets AI agents safely delete code in large codebases
5
+ Author: Alaik Asif Sheik
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/AlaikAsif/CodeTruth
8
+ Project-URL: Repository, https://github.com/AlaikAsif/CodeTruth
9
+ Project-URL: Issues, https://github.com/AlaikAsif/CodeTruth/issues
10
+ Keywords: dead-code,static-analysis,ai-agents,mcp,deletion-safety
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Software Development :: Quality Assurance
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: networkx>=3.0
23
+ Requires-Dist: PyYAML>=6.0
24
+ Requires-Dist: tomli>=2.0; python_version < "3.11"
25
+ Provides-Extra: mcp
26
+ Requires-Dist: mcp>=1.2; extra == "mcp"
27
+ Provides-Extra: javascript
28
+ Requires-Dist: tree-sitter>=0.21; extra == "javascript"
29
+ Requires-Dist: tree-sitter-language-pack>=0.6; extra == "javascript"
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=7.0; extra == "dev"
32
+ Requires-Dist: tree-sitter>=0.21; extra == "dev"
33
+ Requires-Dist: tree-sitter-language-pack>=0.6; extra == "dev"
34
+ Dynamic: license-file
35
+
36
+ # CodeTruth
37
+
38
+ [![CI](https://github.com/AlaikAsif/CodeTruth/actions/workflows/ci.yml/badge.svg)](https://github.com/AlaikAsif/CodeTruth/actions/workflows/ci.yml)
39
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
40
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](pyproject.toml)
41
+
42
+ **A verification layer that lets AI agents safely delete code in large codebases.**
43
+
44
+ Agents hallucinate absence of usage. CodeTruth inverts the question — instead of
45
+ *"is this code used?"* it asks **"can we prove this code is used?"** — and only
46
+ surfaces a symbol for deletion when it fails to find *any* usage path: no call,
47
+ no import, no inheritance, no string reference, no reflection target, no
48
+ framework registration. Detection is deterministic; the agent only reads the
49
+ evidence and decides. It is a **risk assessor for code deletion**, not a dead
50
+ code detector.
51
+
52
+ ## Statuses
53
+
54
+ | Status | Meaning | Recommended action |
55
+ |---|---|---|
56
+ | `safe_to_delete` | zero usage paths found under every analysis rule, **and** the name verified absent from all repo text outside its own definition | `delete` |
57
+ | `likely_dead` | no usage found, but external exposure can't be ruled out (public API, module, test-only) | `review_required` |
58
+ | `uncertain_dynamic_risk` | weak evidence exists (string refs, reflection, dynamic module) | `review_required` |
59
+ | `definitely_used` | strong reference or framework entry point proven | `keep` |
60
+
61
+ ## Install
62
+
63
+ ```bash
64
+ pip install -e . # from this repo
65
+ pip install -e .[mcp] # with the MCP server
66
+ ```
67
+
68
+ ## MCP (the primary interface — for agents)
69
+
70
+ ```bash
71
+ claude mcp add codetruth -- codetruth mcp
72
+ ```
73
+
74
+ Tools exposed: `scan(repo_path, ...)` and `check_deletion_safety(repo_path, symbol)`.
75
+ The agent workflow: identify symbol → call `check_deletion_safety` → only delete
76
+ on `safe_to_delete`; everything else routes to human review.
77
+
78
+ ## CLI
79
+
80
+ ```bash
81
+ codetruth scan ./repo # review queue, strongest candidates first
82
+ codetruth scan ./repo -v --json out.json # full evidence
83
+ codetruth scan ./repo --app-mode # application (not library) repos:
84
+ # public symbols may be safe_to_delete
85
+ codetruth scan ./repo --strict # flag orphaned "useless clumps"
86
+ codetruth scan ./repo --min-rank 0.5 --group # trim the tail, group by file
87
+ codetruth scan ./repo --html report.html # self-contained HTML report
88
+ codetruth scan ./repo --ci # exit 1 if dead code exists (report gate)
89
+ codetruth check ./repo pkg.module:func # one symbol's evidence record
90
+ codetruth plan ./repo pkg.module:func # advisory deletion plan (never applied)
91
+ ```
92
+
93
+ The `--ci` gate is advisory like everything else: it *fails the build* so a
94
+ human looks at provably-dead code — it never deletes. Mark false alarms with
95
+ `# codetruth: keep` or a `.codetruth.toml` entrypoint.
96
+
97
+ ## Python API
98
+
99
+ ```python
100
+ from codetruth import scan, check_deletion_safety
101
+
102
+ result = scan("./repo")
103
+ for rec in result.candidates():
104
+ print(rec.status.value, rec.symbol, rec.evidence_against_deletion)
105
+ ```
106
+
107
+ ## Runtime evidence (v1.5)
108
+
109
+ Static analysis can't see cross-service usage (HTTP calls, queues, cron in
110
+ other repos). `@codetruth.track` logs real invocations in production:
111
+
112
+ ```python
113
+ import codetruth
114
+
115
+ @codetruth.track
116
+ def maybe_dead(): ...
117
+ ```
118
+
119
+ Or instrument a whole package with zero source edits:
120
+
121
+ ```python
122
+ import codetruth.runtime
123
+ codetruth.runtime.instrument_package("myapp") # or CODETRUTH_AUTOTRACK=myapp
124
+ ```
125
+
126
+ Then feed the trace back: `codetruth scan ./repo --runtime-log runtime.jsonl`.
127
+ Observed calls promote a symbol to `definitely_used`; *"0 calls over N days"*
128
+ becomes the strongest evidence tier for deletion.
129
+
130
+ Tracing is production-safe: each process writes its own `runtime-<pid>.jsonl`
131
+ (merged at read — no lock contention between workers), and a daemon thread
132
+ flushes counts every `$CODETRUTH_FLUSH_INTERVAL` seconds (default 60), so
133
+ long-running servers land evidence without a clean exit.
134
+
135
+ ## Finding useless clumps (strict reachability)
136
+
137
+ `codetruth scan ./repo --strict` asks a harder question: *is this code
138
+ reachable from any real entry point* (HTTP route, CLI command, `__main__`,
139
+ test, declared entrypoint)? Code that is internally well-connected — functions
140
+ calling each other — but never reached from an entry point surfaces as an
141
+ orphaned clump, with every member carrying a `cluster` field listing its
142
+ fellow members so the whole island can be reviewed (and deleted) as a group.
143
+ Dead-cluster grouping also applies in default mode whenever unreachable
144
+ symbols reference each other.
145
+
146
+ ## Configuration (`.codetruth.toml`)
147
+
148
+ Teach the scanner about usage it can't see:
149
+
150
+ ```toml
151
+ [codetruth]
152
+ app_mode = true # public symbols are internal (application)
153
+ entrypoints = [ # externally-reached symbols (cron, RPC, ...)
154
+ "jobs.nightly:run",
155
+ "services.handlers.*",
156
+ ]
157
+ ignore_paths = ["migrations/", "vendor/**"]
158
+ ```
159
+
160
+ Inline: a `# codetruth: keep` comment on (or above) a definition marks it as
161
+ an entry point.
162
+
163
+ ## Deletion plans (advisory)
164
+
165
+ `codetruth plan ./repo pkg.mod:symbol` (also the `plan_deletion` MCP tool, and
166
+ attached automatically to every `safe_to_delete` record) describes exactly what
167
+ a removal would involve: the decorator-to-end source span, imports that become
168
+ orphaned, and any `__all__` entry. CodeTruth **never applies** a plan — it is
169
+ information for whoever decides.
170
+
171
+ ## Review-queue ranking
172
+
173
+ Every record carries a `rank_score` in `[0, 1]` — a deterministic ordering
174
+ heuristic (not a calibrated probability; see PLAN.md §4). Higher means weaker
175
+ evidence of use, so `scan()` and the CLI surface the strongest deletion
176
+ targets first. Within `uncertain_dynamic_risk` it separates a lone
177
+ string-literal reference from forty fuzzy attribute-name matches, so a big
178
+ review queue is triageable instead of flat.
179
+
180
+ ## Performance
181
+
182
+ Scans are cached at `<repo>/.codetruth/index.json`, keyed by a fingerprint of
183
+ every source and config file's `(mtime, size)`. An unchanged repo returns the
184
+ cached result (≈15× faster on an 8k-symbol repo); any file change triggers a
185
+ full rescan. The cache never patches the graph incrementally — a stale
186
+ cross-file edge could mask a real usage path, so correctness always wins.
187
+ Bypass with `--no-cache` (CLI) or `force_rescan` (MCP). Add `.codetruth/` to
188
+ `.gitignore`.
189
+
190
+ ## Architecture
191
+
192
+ ```
193
+ Layer 1 Symbol Extraction codetruth/languages/python/extractor.py
194
+ Layer 2 Relationship Graph codetruth/languages/python/edges.py (strong/weak edges)
195
+ Layer 3 Semantic Rules codetruth/languages/python/rules.py + codetruth/rules/python/*.yaml
196
+ Layer 4 Evidence + Decision codetruth/core/evidence.py (4-way status)
197
+ ```
198
+
199
+ The core engine is language-agnostic (`codetruth/core/`, `LanguagePlugin`
200
+ interface). **Python** is the full v1 plugin (FastAPI, Django, Celery, click,
201
+ pytest, SQLAlchemy, Typer rule coverage). **JavaScript/TypeScript** is a beta
202
+ plugin (`pip install codetruth[javascript]`, then `scan --language javascript`):
203
+ tree-sitter extraction, ESM/CommonJS import resolution, package.json
204
+ entry points, string/config wiring, eval poisoning, and external-base cautions
205
+ — with the shared evidence, ranking, cluster, backstop, and cache layers
206
+ working unchanged. Go remains a stub.
207
+
208
+ ## Known limitations
209
+
210
+ - Cross-service usage is invisible to static analysis alone — runtime tracing
211
+ is the partial fix.
212
+ - 100% certainty is impossible; `safe_to_delete` means "no usage path found
213
+ under the defined rules," not a mathematical proof.
214
+ - Framework rule coverage (Layer 3) is a maintained knowledge base, never
215
+ finished. New rules go in `codetruth/rules/python/*.yaml` — no code changes.
@@ -0,0 +1,180 @@
1
+ # CodeTruth
2
+
3
+ [![CI](https://github.com/AlaikAsif/CodeTruth/actions/workflows/ci.yml/badge.svg)](https://github.com/AlaikAsif/CodeTruth/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
5
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](pyproject.toml)
6
+
7
+ **A verification layer that lets AI agents safely delete code in large codebases.**
8
+
9
+ Agents hallucinate absence of usage. CodeTruth inverts the question — instead of
10
+ *"is this code used?"* it asks **"can we prove this code is used?"** — and only
11
+ surfaces a symbol for deletion when it fails to find *any* usage path: no call,
12
+ no import, no inheritance, no string reference, no reflection target, no
13
+ framework registration. Detection is deterministic; the agent only reads the
14
+ evidence and decides. It is a **risk assessor for code deletion**, not a dead
15
+ code detector.
16
+
17
+ ## Statuses
18
+
19
+ | Status | Meaning | Recommended action |
20
+ |---|---|---|
21
+ | `safe_to_delete` | zero usage paths found under every analysis rule, **and** the name verified absent from all repo text outside its own definition | `delete` |
22
+ | `likely_dead` | no usage found, but external exposure can't be ruled out (public API, module, test-only) | `review_required` |
23
+ | `uncertain_dynamic_risk` | weak evidence exists (string refs, reflection, dynamic module) | `review_required` |
24
+ | `definitely_used` | strong reference or framework entry point proven | `keep` |
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ pip install -e . # from this repo
30
+ pip install -e .[mcp] # with the MCP server
31
+ ```
32
+
33
+ ## MCP (the primary interface — for agents)
34
+
35
+ ```bash
36
+ claude mcp add codetruth -- codetruth mcp
37
+ ```
38
+
39
+ Tools exposed: `scan(repo_path, ...)` and `check_deletion_safety(repo_path, symbol)`.
40
+ The agent workflow: identify symbol → call `check_deletion_safety` → only delete
41
+ on `safe_to_delete`; everything else routes to human review.
42
+
43
+ ## CLI
44
+
45
+ ```bash
46
+ codetruth scan ./repo # review queue, strongest candidates first
47
+ codetruth scan ./repo -v --json out.json # full evidence
48
+ codetruth scan ./repo --app-mode # application (not library) repos:
49
+ # public symbols may be safe_to_delete
50
+ codetruth scan ./repo --strict # flag orphaned "useless clumps"
51
+ codetruth scan ./repo --min-rank 0.5 --group # trim the tail, group by file
52
+ codetruth scan ./repo --html report.html # self-contained HTML report
53
+ codetruth scan ./repo --ci # exit 1 if dead code exists (report gate)
54
+ codetruth check ./repo pkg.module:func # one symbol's evidence record
55
+ codetruth plan ./repo pkg.module:func # advisory deletion plan (never applied)
56
+ ```
57
+
58
+ The `--ci` gate is advisory like everything else: it *fails the build* so a
59
+ human looks at provably-dead code — it never deletes. Mark false alarms with
60
+ `# codetruth: keep` or a `.codetruth.toml` entrypoint.
61
+
62
+ ## Python API
63
+
64
+ ```python
65
+ from codetruth import scan, check_deletion_safety
66
+
67
+ result = scan("./repo")
68
+ for rec in result.candidates():
69
+ print(rec.status.value, rec.symbol, rec.evidence_against_deletion)
70
+ ```
71
+
72
+ ## Runtime evidence (v1.5)
73
+
74
+ Static analysis can't see cross-service usage (HTTP calls, queues, cron in
75
+ other repos). `@codetruth.track` logs real invocations in production:
76
+
77
+ ```python
78
+ import codetruth
79
+
80
+ @codetruth.track
81
+ def maybe_dead(): ...
82
+ ```
83
+
84
+ Or instrument a whole package with zero source edits:
85
+
86
+ ```python
87
+ import codetruth.runtime
88
+ codetruth.runtime.instrument_package("myapp") # or CODETRUTH_AUTOTRACK=myapp
89
+ ```
90
+
91
+ Then feed the trace back: `codetruth scan ./repo --runtime-log runtime.jsonl`.
92
+ Observed calls promote a symbol to `definitely_used`; *"0 calls over N days"*
93
+ becomes the strongest evidence tier for deletion.
94
+
95
+ Tracing is production-safe: each process writes its own `runtime-<pid>.jsonl`
96
+ (merged at read — no lock contention between workers), and a daemon thread
97
+ flushes counts every `$CODETRUTH_FLUSH_INTERVAL` seconds (default 60), so
98
+ long-running servers land evidence without a clean exit.
99
+
100
+ ## Finding useless clumps (strict reachability)
101
+
102
+ `codetruth scan ./repo --strict` asks a harder question: *is this code
103
+ reachable from any real entry point* (HTTP route, CLI command, `__main__`,
104
+ test, declared entrypoint)? Code that is internally well-connected — functions
105
+ calling each other — but never reached from an entry point surfaces as an
106
+ orphaned clump, with every member carrying a `cluster` field listing its
107
+ fellow members so the whole island can be reviewed (and deleted) as a group.
108
+ Dead-cluster grouping also applies in default mode whenever unreachable
109
+ symbols reference each other.
110
+
111
+ ## Configuration (`.codetruth.toml`)
112
+
113
+ Teach the scanner about usage it can't see:
114
+
115
+ ```toml
116
+ [codetruth]
117
+ app_mode = true # public symbols are internal (application)
118
+ entrypoints = [ # externally-reached symbols (cron, RPC, ...)
119
+ "jobs.nightly:run",
120
+ "services.handlers.*",
121
+ ]
122
+ ignore_paths = ["migrations/", "vendor/**"]
123
+ ```
124
+
125
+ Inline: a `# codetruth: keep` comment on (or above) a definition marks it as
126
+ an entry point.
127
+
128
+ ## Deletion plans (advisory)
129
+
130
+ `codetruth plan ./repo pkg.mod:symbol` (also the `plan_deletion` MCP tool, and
131
+ attached automatically to every `safe_to_delete` record) describes exactly what
132
+ a removal would involve: the decorator-to-end source span, imports that become
133
+ orphaned, and any `__all__` entry. CodeTruth **never applies** a plan — it is
134
+ information for whoever decides.
135
+
136
+ ## Review-queue ranking
137
+
138
+ Every record carries a `rank_score` in `[0, 1]` — a deterministic ordering
139
+ heuristic (not a calibrated probability; see PLAN.md §4). Higher means weaker
140
+ evidence of use, so `scan()` and the CLI surface the strongest deletion
141
+ targets first. Within `uncertain_dynamic_risk` it separates a lone
142
+ string-literal reference from forty fuzzy attribute-name matches, so a big
143
+ review queue is triageable instead of flat.
144
+
145
+ ## Performance
146
+
147
+ Scans are cached at `<repo>/.codetruth/index.json`, keyed by a fingerprint of
148
+ every source and config file's `(mtime, size)`. An unchanged repo returns the
149
+ cached result (≈15× faster on an 8k-symbol repo); any file change triggers a
150
+ full rescan. The cache never patches the graph incrementally — a stale
151
+ cross-file edge could mask a real usage path, so correctness always wins.
152
+ Bypass with `--no-cache` (CLI) or `force_rescan` (MCP). Add `.codetruth/` to
153
+ `.gitignore`.
154
+
155
+ ## Architecture
156
+
157
+ ```
158
+ Layer 1 Symbol Extraction codetruth/languages/python/extractor.py
159
+ Layer 2 Relationship Graph codetruth/languages/python/edges.py (strong/weak edges)
160
+ Layer 3 Semantic Rules codetruth/languages/python/rules.py + codetruth/rules/python/*.yaml
161
+ Layer 4 Evidence + Decision codetruth/core/evidence.py (4-way status)
162
+ ```
163
+
164
+ The core engine is language-agnostic (`codetruth/core/`, `LanguagePlugin`
165
+ interface). **Python** is the full v1 plugin (FastAPI, Django, Celery, click,
166
+ pytest, SQLAlchemy, Typer rule coverage). **JavaScript/TypeScript** is a beta
167
+ plugin (`pip install codetruth[javascript]`, then `scan --language javascript`):
168
+ tree-sitter extraction, ESM/CommonJS import resolution, package.json
169
+ entry points, string/config wiring, eval poisoning, and external-base cautions
170
+ — with the shared evidence, ranking, cluster, backstop, and cache layers
171
+ working unchanged. Go remains a stub.
172
+
173
+ ## Known limitations
174
+
175
+ - Cross-service usage is invisible to static analysis alone — runtime tracing
176
+ is the partial fix.
177
+ - 100% certainty is impossible; `safe_to_delete` means "no usage path found
178
+ under the defined rules," not a mathematical proof.
179
+ - Framework rule coverage (Layer 3) is a maintained knowledge base, never
180
+ finished. New rules go in `codetruth/rules/python/*.yaml` — no code changes.
@@ -0,0 +1,16 @@
1
+ """CodeTruth — a verification layer that lets AI agents safely delete code.
2
+
3
+ from codetruth import scan, check_deletion_safety, track
4
+ """
5
+ from .api import check_deletion_safety, plan_deletion, scan
6
+ from .core.models import (Action, Edge, EvidenceRecord, RiskLevel, Status,
7
+ Symbol)
8
+ from .runtime import track
9
+
10
+ __version__ = "0.2.0"
11
+
12
+ __all__ = [
13
+ "scan", "check_deletion_safety", "plan_deletion", "track",
14
+ "Status", "RiskLevel", "Action", "Symbol", "Edge", "EvidenceRecord",
15
+ "__version__",
16
+ ]
@@ -0,0 +1,102 @@
1
+ """Programmatic API — what the MCP server and scripts call.
2
+
3
+ from codetruth import scan, check_deletion_safety, plan_deletion
4
+ """
5
+ from __future__ import annotations
6
+
7
+ from pathlib import Path
8
+ from typing import Optional
9
+
10
+ from .core.deletion import build_deletion_plan
11
+ from .core.plugin import get_plugin
12
+ from .core.scanner import ScanResult, scan_repo
13
+
14
+
15
+ def scan(repo_path: str | Path, language: str = "python",
16
+ treat_public_as_api: Optional[bool] = None,
17
+ runtime_log: Optional[str | Path] = None,
18
+ use_cache: bool = True,
19
+ reachability: str = "default") -> ScanResult:
20
+ """Run all four layers over a repository and return the evidence set.
21
+
22
+ treat_public_as_api: True (conservative, the default when neither the
23
+ caller nor .codetruth.toml says otherwise) caps unreferenced public
24
+ symbols at `likely_dead` because a library's consumers are invisible.
25
+ False for application code; None defers to `app_mode` in .codetruth.toml.
26
+
27
+ reachability: "default", or "strict" to detect useless clumps — code
28
+ that is internally connected but never reached from any real entry point
29
+ (route, CLI command, __main__, test, declared entrypoint). Strict-mode
30
+ findings surface in the review queue with cluster grouping.
31
+
32
+ use_cache=True reuses a persisted result (<repo>/.codetruth/index.json)
33
+ when no source or config file has changed since the last scan.
34
+ """
35
+ return scan_repo(repo_path, language=language,
36
+ treat_public_as_api=treat_public_as_api,
37
+ runtime_log=runtime_log, use_cache=use_cache,
38
+ reachability=reachability)
39
+
40
+
41
+ def check_deletion_safety(repo_path: str | Path, symbol: str,
42
+ result: Optional[ScanResult] = None,
43
+ **scan_kwargs) -> dict:
44
+ """The agent-facing question: 'may I delete this symbol?'
45
+
46
+ Returns the evidence record(s) for the symbol, or candidate matches if
47
+ the name is ambiguous. The agent should only act on `safe_to_delete`.
48
+ """
49
+ if result is None:
50
+ result = scan(repo_path, **scan_kwargs)
51
+ matches = result.find(symbol)
52
+ if not matches:
53
+ return {
54
+ "found": False, "symbol": symbol,
55
+ "message": "Symbol not found in the scanned repository. "
56
+ "Do NOT delete based on this response — verify the "
57
+ "symbol id (format: 'pkg.module:Qual.name').",
58
+ }
59
+ if len(matches) > 1:
60
+ return {
61
+ "found": True, "ambiguous": True, "symbol": symbol,
62
+ "message": f"{len(matches)} symbols match — re-query with an exact id.",
63
+ "candidates": [m.to_dict() for m in matches[:20]],
64
+ }
65
+ record = matches[0]
66
+ return {"found": True, "ambiguous": False, "record": record.to_dict()}
67
+
68
+
69
+ def plan_deletion(repo_path: str | Path, symbol: str,
70
+ language: str = "python",
71
+ result: Optional[ScanResult] = None,
72
+ **scan_kwargs) -> dict:
73
+ """Advisory plan for removing one symbol: exact span, orphaned imports,
74
+ __all__ entry. Works for any status — the response carries the verdict so
75
+ the reader knows whether acting on the plan is advised. CodeTruth never
76
+ applies the plan.
77
+ """
78
+ safety = check_deletion_safety(repo_path, symbol, result=result,
79
+ **scan_kwargs)
80
+ if not safety.get("found") or safety.get("ambiguous"):
81
+ return safety
82
+
83
+ record = safety["record"]
84
+ if record.get("deletion_plan"):
85
+ plan = record["deletion_plan"]
86
+ else:
87
+ repo = Path(repo_path).resolve()
88
+ plugin = get_plugin(language)
89
+ modules, _warnings = plugin.extract(repo)
90
+ sym = next((s for m in modules for s in m.symbols
91
+ if s.id == record["symbol"]), None)
92
+ plan = build_deletion_plan(repo, sym) if sym is not None else None
93
+
94
+ return {
95
+ "found": True, "symbol": record["symbol"],
96
+ "status": record["status"],
97
+ "recommended_action": record["recommended_action"],
98
+ "plan": plan,
99
+ "warning": None if record["status"] == "safe_to_delete" else
100
+ f"status is {record['status']} — this plan is informational; "
101
+ "review is required before anyone acts on it",
102
+ }