You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Java at -a 4 without compiled classes returns a declared-only graph and still reports max_level 4 #341
AnalysisLevel.system_dependency_graph on a Java project whose classes are not compiled returns a call graph containing only prov=["declared"] edges, while the envelope still reports max_level: 4. Nothing tells the caller that the points-to half of the analysis did not happen.
Measured on daytrader8-1.2 (the repo's own fixture), through the SDK, at -a 4:
environment
edges
provenance
Maven on PATH (analyzer auto-builds, target/classes produced)
1862
declared+rta 1378, rta 375, declared 109
no Maven on PATH (build cannot run)
1391
all declared
Both runs report max_level: 4 and both exit 0. The 471-edge difference is the entire RTA contribution, which is the reason to ask for L4 in the first place.
The trigger is the auto-build failing or being skipped, not the analyzer version or the runtime: it reproduces identically on the bundled-jar path and on the codeanalyzer-java wheel, and with JAVA_HOME set or unset.
Scope boundary
In scope: the SDK noticing that a requested level was not actually achieved and saying so. The natural signal is already in the payload — a -a 4 run that produced no rta provenance on any edge, and/or an analyzer log line about the build. Deciding between a raise, a Diagnostic on the result, and a documented warning is the design question.
Out of scope: making the SDK compile the project itself, and any change to the analyzer's degrade-rather-than-fail behaviour, which is deliberate and correct for the analyzer.
Goals
A requested L4 that silently yields a declared-only graph is distinguishable from a genuine declared-only graph, without the caller inspecting provenance by hand
The signal names the cause (no compiled classes, so RTA had nothing to walk) and the remedy (build the project, or pass a build command)
max_level in the SDK's view reflects what was achieved, or the discrepancy is surfaced explicitly
Caveats and known risks
A project can legitimately have zero rta edges (nothing reachable), so "no rta provenance" alone is not proof of degradation; it needs the analyzer's own build signal to be conclusive. Check what the analyzer reports before choosing the predicate — guessing here produces a false alarm on small projects.
This is the same class of defect as an ambiguous empty (leg-1 D7): the answer is not wrong so much as indistinguishable from a different, correct answer.
Definition of done
A test that runs L4 with no compiled classes and asserts the signal, and one that runs L4 with classes and asserts silence
The behaviour is documented in the agent reference next to the analysis levels
RTA call graph unavailable (NullPointerException: null); emitting declared edges only
L4 semantic ddg unavailable (WALA build failed); emitting the derived SDG vertices and param edges only
Two consequences for the fix:
The analyzer's own words are the signal, and they are better than anything the SDK could infer: they name the missing capability and the fallback. The payload cannot be used as the primary predicate, since a project may legitimately have no points-to edges; the DDG-provenance and param_in deltas above are useful only to corroborate a recorded verdict.
The verdict has to be persisted next to the cache. A cache hit does not re-invoke the analyzer and therefore has no log, so a captured warning that lives only in process memory answers the question exactly once and then forgets it.
That gives three states which must stay distinguishable: degradation reported, no degradation reported, and no verdict recorded (a cache written before this change, or a payload obtained elsewhere). Reporting the third as clean would reproduce this same defect one level up, so it is reported as unknown.
Being fixed now on the leg-3a branch alongside #339, as a report rather than a raise: a declared-only graph is still a useful answer, and raising would break callers who only ever wanted L2 data.
Also correcting the issue text: AnalysisLevel.call_graph is L2 and yields the declared-only 1391 edges by design, so it is not where the RTA half lives. The comparison that matters is L4 with compiled classes against L4 without them, which is the table above.
Activity
rahlk commentedon Sep 6, 2026
Measured the two cases to find a predicate that is not a guess. The analyzer declares the degradation itself, but only on its log.
Two runs of codeanalyzer-java 3.0.2 at
-a 4on the same daytrader8 tree withtarget/deleted, differing only in whether Maven was onPATH:schema_version,language,max_level,analyzer)applicationkeysdeclared+rta1378,rta375,declared109)declaredpoints-to1220,ssa4160ssa4160 onlyparam_in/param_outThe log lines, at WARN:
Two consequences for the fix:
points-toedges; the DDG-provenance andparam_indeltas above are useful only to corroborate a recorded verdict.That gives three states which must stay distinguishable: degradation reported, no degradation reported, and no verdict recorded (a cache written before this change, or a payload obtained elsewhere). Reporting the third as clean would reproduce this same defect one level up, so it is reported as unknown.
Being fixed now on the leg-3a branch alongside #339, as a report rather than a raise: a declared-only graph is still a useful answer, and raising would break callers who only ever wanted L2 data.
Also correcting the issue text:
AnalysisLevel.call_graphis L2 and yields the declared-only 1391 edges by design, so it is not where the RTA half lives. The comparison that matters is L4 with compiled classes against L4 without them, which is the table above.fix(java): report the analyzer's own L3/L4 degradation instead of ret…
fix(java): report the analyzer's own L3/L4 degradation instead of ret…
fix(java): report the analyzer's own L3/L4 degradation instead of ret…