Skip to content

Commit c125d48

Browse files
authored
Merge pull request #432 from codellm-devkit/release/2.0
Release/2.0
2 parents f79d617 + 15c3cde commit c125d48

51 files changed

Lines changed: 8033 additions & 306 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CHANGELOG.md‎

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,143 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [v2.0.0] - 2026-10-15
9+
10+
CLDK 2.0 gives Python, Java and TypeScript one agent-facing query surface — addressing, per-callable
11+
control and data flow, slices, call-graph and value-flow predicates, entrypoints and the
12+
repository-artifact layer — answered identically from an `analysis.json` or an attached Neo4j graph.
13+
No code changes since `v2.0.0-rc.8` except the README split into a user page, `docs/architecture.md`
14+
and `docs/citations.md` (#416). The rc sections below are the full record; this section lists what
15+
breaks for code written against **1.5.0**, each with its migration step.
16+
17+
### Breaking (since 1.5.0)
18+
19+
- **C support is removed** (`CLDK.c()`, `cldk.analysis.c`, `cldk.models.c`; rc.2). There is no
20+
replacement; pin `cldk<2` if you need it.
21+
- **Java needs the `java` extra.** The analyzer ships as the `codeanalyzer-java` wheel with its own
22+
JVM, not a jar in this repo (rc.3). Install with `pip install "cldk[java]"`.
23+
- **Every Neo4j graph must be re-emitted, into a wiped database.** The `can://` id grammar now puts the
24+
application outermost (`can://<app>/<lang>/...`, rc.4), and each backend refuses a graph below its
25+
floor at attach with `GraphSchemaMismatch`, rather than answering with zero rows. The floors are
26+
`codeanalyzer-python` 1.5.0, `codeanalyzer-typescript` 1.5.2 and `codeanalyzer-java` 3.2.0 (rc.6).
27+
Re-emit with the pinned analyzer (`--emit neo4j`); there is no in-place upgrade.
28+
- **Java and TypeScript models mirror schema v2** (rc.3). A 1.x `analysis.json` is refused rather than
29+
parsed: re-run the analysis with the pinned analyzer. For Java, `get_call_graph()` nodes are
30+
`"<type fqn>.<signature>"` strings rather than `(signature, klass)` tuples — read the class from
31+
`cg.nodes[key]["method_detail"].klass`. Local and anonymous class names carry their declaring callable
32+
— take class keys from `get_all_classes()` rather than composing them. `JGraphEdges` is
33+
`{src, dst, prov, weight}`. For TypeScript, `TSCallable` and `TSModule` lost their per-file fields (v2
34+
keys modules by path).
35+
- **Java's single-file `source_code` mode is gone** (rc.3). Analyze the project directory.
36+
- **`PyCallableOverview.path` is repo-relative**, not an absolute path (rc.2). Stop stripping a
37+
project-root prefix off it.
38+
- **Accessors that only ever raised `NotImplementedError` are removed**: fifteen on `PythonAnalysis`
39+
(rc.2) and `get_entry_point_methods` / `get_service_entry_point_methods` on `TypeScriptAnalysis`
40+
(rc.3). Use `get_entrypoints()` / `get_entrypoint_classes()`.
41+
42+
### Analyzer pins
43+
44+
`codeanalyzer-python==1.5.3`, `codeanalyzer-typescript==1.6.0`, `codeanalyzer-java==3.3.3` (extra).
45+
46+
## [v2.0.0-rc.8] - 2026-09-16
47+
48+
### Fixed
49+
50+
- **`locate` places a position on a decorator line on the decorated callable, on both Python
51+
backends** (`python-sdk#408`). `PyCallable.start_line` is the `def` line (`ast.FunctionDef.lineno`)
52+
and Python's AST puts decorators above it, so `@http.route(...)` sat inside no callable span and
53+
came back as `module_scope`. Both backends now read where the decorator is *applied*:
54+
`_find_innermost` admits the callable whose `decorators[].span` starts at or before the line and
55+
above its `def`; `_LOCATE_QUERY` gains one `EXISTS` disjunct over `PY_DECORATED_BY.start_line`,
56+
which codeanalyzer-python 1.5.2 emits. Ranking is unchanged (the def-based width), so a decorator
57+
on a nested callable resolves to the nested one. Three things deliberately stay as they were: a
58+
position between two callables with no decorator over it is still `module_scope` (this is not a
59+
nearest-callable fallback); a **class** decorator is still `module_scope` (a result with `type`
60+
set and `callable` unset is a new shape and needs its own decision); and an analysis or graph from
61+
codeanalyzer-python 1.5.1 or earlier, which records no decorator span, answers exactly as before.
62+
Measured on odoo-slim-19 re-emitted by 1.5.3, 40 positions, median of 5, same graph both ways:
63+
71.0 ms placing 20/40 → 70.2 ms placing 40/40; the plan still seeks `pysymbol_id`.
64+
65+
### Changed
66+
67+
- `codeanalyzer-python` pin `1.5.2` → **`1.5.3`** (`dependencies` and `[tool.backend-versions]`,
68+
`python-sdk#410`). Two analyzer fixes, neither moving the schema (`schema_version` and the graph
69+
`SCHEMA_VERSION` stay `2.0.0`; `PyNeo4jBackend._ANALYZER_FLOOR` stays `1.5.0`):
70+
- the analyzer no longer ingests its own output (codeanalyzer-python#207). `discover_artifacts`
71+
had no idea where the run writes, so an output or cache directory inside the input made run N
72+
inventory run N-1's `analysis.json` and embed it whole. This SDK's default `cache_dir` is
73+
`<project>/.codeanalyzer`, inside the input, so every local run was exposed.
74+
- one body node per call site when two calls share a start position (codeanalyzer-python#215).
75+
`getattr(o, n)(x)` starts the outer application and the inner `getattr` at the same column, and
76+
the position-keyed `body` kept the inner one. Keys now carry a `/2`, `/3` disambiguator,
77+
outermost first; `body_key_column` already splits on `/` and needed no change. A key that used
78+
to collide now names the **outer** call, and a call whose callee is itself a call carries
79+
`callee_signature: null` with `method_name: "<unknown>"`.
80+
81+
### Verification
82+
83+
The Python tier offline (`tests/analysis/python`, mocked Neo4j and the in-process analyzer):
84+
482 passed, 168 skipped, on 1.5.2 and on 1.5.3 alike — every skip is a live-Neo4j tier. No fixture
85+
expectation moved.
86+
87+
## [v2.0.0-rc.7] - 2026-09-11
88+
89+
The Java facade learns the view layer codeanalyzer-java 3.3.0–3.3.2 added, and the 2.0 line takes up
90+
everything rc.6 shipped from `main` (the 3.2.0 text model and the sibling-analyzer pins) — this is
91+
the first release cut from `release/2.0` that contains rc.6.
92+
93+
### Added
94+
95+
**Java view dispatches** (`python-sdk#404`, spec `codellm-devkit/.github`
96+
`docs/design/specs/2026-09-11-java-view-templates-and-dispatch.md`). JSP, Facelets and Thymeleaf
97+
templates are artifacts with `roles: ["view-template"]`, and the analyzer now says which code reaches
98+
one. Three accessors on `JavaAnalysis`, both backends:
99+
100+
- `get_view_dispatches(view=None) -> List[JViewDispatch]` — every resolved dispatch: the body node
101+
that hands the request over (a `forward` / `include` / `sendRedirect` call, a `ModelAndView`
102+
construction or `setViewName`, or a Spring controller's `return`) and the artifact it reaches,
103+
with `via` naming the mechanism and `prov` the tier. `literal` and `dataflow` mean exactly one
104+
target; `table` (3.3.1) is a may-dispatch over a static string table, one edge per entry, from
105+
the same site. `view` filters by a segment-aligned suffix of the artifact's path.
106+
- `get_view_dispatchers(path) -> List[JCallableOverview]` — the same edges resolved to the callables
107+
that own the dispatching sites.
108+
- `get_unresolved_view_dispatches() -> List[JViewDispatchUnresolved]` — what closed on nothing (a
109+
variable target, a servlet URL, a view name matching two templates), with its reason and the tiers
110+
attempted. JSON-only: the graph has no node for a target that resolved to nothing, so the Neo4j
111+
backend refuses this one rather than answering `[]`.
112+
113+
Two models, `JViewDispatch` and `JViewDispatchUnresolved`, on `JApplication.view_dispatches` /
114+
`.view_dispatches_unresolved`; the Neo4j backend reads `J_DISPATCHES_TO` back into the former.
115+
116+
One rule stated because it is the only one of its kind: **this layer is gated on the analyzer
117+
generation.** The 3.1.0 config trio is probed by an always-present sibling key; 3.3.x added none —
118+
both lists are written only when non-empty and the edge type is declared only once an edge exists —
119+
so a pre-3.3.0 analysis is refused from `analyzer.version` (wire) / `analyzer_version` (graph) instead,
120+
because `[]` off a 3.2.0 analysis would say "reaches no view" where the truth is that nothing looked.
121+
122+
Measured on daytrader8 with 3.3.3: 37 edges at level 1–2 (3 `literal`, 34 `table`), 54 at level 4,
123+
19 of 23 JSPs reached; the `TradeConfig.webUI` table's 17 on-disk pages all reached.
124+
125+
### Changed
126+
127+
- `codeanalyzer-java` pin `3.2.0` → **`3.3.3`** (the `java` extra and `[tool.backend-versions]`).
128+
3.3.0 adds the view-template role, `J_DISPATCHES_TO`, and `argument_expr` on `return` body nodes;
129+
3.3.1 the table tier; 3.3.2 narrows the Jakarta entrypoint finder to lifecycle methods, so
130+
helpers taking servlet-typed parameters are no longer entrypoints and the interprocedural
131+
config-use and view-dispatch tiers bind their parameters (daytrader8 entrypoint marks
132+
135 → 196: 21 helpers dropped, 82 `init`/`destroy`/`doFilter`/`onMessage` gained); 3.3.3 fixes
133+
the `NullPointerException` 3.3.0–3.3.2 threw on any unbuilt project with a dispatch call, which
134+
this SDK's `test_java_degradation.py` was the first to hit (codeanalyzer-java#265).
135+
- `release/2.0` absorbed `main` at rc.6.
136+
137+
### Verification
138+
139+
The Java suite offline on both backends over a1 with the layer injected (edges, suffix filter,
140+
dispatcher resolution, the JSON-only refusal on the graph, the pre-3.3.0 refusal, the empty answer
141+
on a 3.3.x payload that reaches nothing, and the answered-once check across backends); the public
142+
surface pins the three signatures; e2e against the 3.3.3 wheel on daytrader8 at level 1 and 2
143+
asserts the 37 edges, the 19 views, the three unresolved URLs and the 38 view-template artifacts.
144+
8145
## [v2.0.0-rc.6] - 2026-09-10
9146

10147
The Java Neo4j backend stops being the lossy one about source text. Until now a graph-backed Java

‎CLAUDE.md‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,25 @@ artifact six, and the J-7 leaf accessors (`get_interfaces`/`get_enums`/`get_enum
2525
`get_records`, names shared with TypeScript). Both backends answer identically, including the miss
2626
paths; the policy lives once on `JavaAnalysisBackend` because `JNeo4jBackend` rebuilds the canonical
2727
`JApplication` and answers from it. Four things Java says rather than answering, each measured:
28-
`slice_forward` / `paths_between` / `flows_to_call` / `flows_to_argument` raise (the analyzer's L4
29-
port lattice carries no dependence edge, codeanalyzer-java#227); `get_entrypoint_coverage` reports
28+
`slice_forward` / `paths_between` / `flows_to_call` / `flows_to_argument` raise **when the attached
29+
analysis has no dependence edge leaving a `formal_in`** (codeanalyzer-java#227) — the probe reads the
30+
data, never a version, so a graph re-emitted by >= 3.0.3 answers instead: measured on daytrader8,
31+
`_ports_carry_dependence` is `True` and none of the four refuses there; `get_entrypoint_coverage` reports
3032
`entrypoint_report_unavailable` and the three config-read accessors raise on an analysis older than
3133
codeanalyzer-java 3.1.0, which is the release that added both overlays (the probe is the entrypoint
3234
report's presence, measured from the data, never a version string); `get_external_symbols` raises
3335
off a local run (`--external-calls` is opt-in and `--emit neo4j` forces it); the CRUD accessors
3436
still raise. `docs/agent-api-reference.md` has the full lossiness list.
3537

38+
**All three languages, since leg 4b (#382):** `taint(sources, sinks, sanitizers=(), *, depth=None,
39+
max_paths=10)` on every facade — m sources against n sinks in one traversal, with `TaintResult`
40+
adding `exhausted` (pairs searched to exhaustion: the refutation `paths_between` cannot give),
41+
`roots`, `resolved` and `unresolved`. Three rules the docstrings carry and the tests pin: an explicit
42+
`depth` empties `exhausted` by rule; `complete` is the batch's flag and one blocked pair voids every
43+
absence claim in the result; `max_paths` caps per pair, never per call. The source/sink/sanitizer
44+
vocabulary is the caller's — no framework catalogue ships. Java shares the `formal_in` dependence
45+
probe above, so `taint` refuses on the same analyses the four verbs do.
46+
3647
The legacy `CLDK(language="<lang>").analysis(...)` entry still works as a compat shim. Adding a
3748
language means a new factory method + facade + backend ABC/impl(s) + models + tests — **update this
3849
table in the same change**.

‎CONTRIBUTING.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ We welcome PRs across all our repositories! When submitting:
2121

2222
## Development Guidelines
2323

24+
### Repository layout
25+
- See [docs/architecture.md](docs/architecture.md) for how the SDK's models, backends, and shared result types fit together
26+
2427
### Code Quality
2528
- Follow the repository's established patterns
2629
- Include appropriate documentation

0 commit comments

Comments
 (0)