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
3.1.0: the level-4 points-to DDG tier now depends on --external-calls; a plain -a 4 loses 276 edges #240
Is your feature request related to a problem? Please describe.
In 3.1.0 the level-4 points-to dependence tier is only computed when --external-calls is passed. Before 3.1.0 it was unconditional.
Four runs over the same daytrader8 tree, same -a 4, only the flag varying:
run
ddg
prov == ["points-to"]
3.0.3 -a 4
10,430
1,134
3.1.0 -a 4
10,154
858
3.1.0 -a 4 --external-calls
10,430
1,134
3.1.0 --emit neo4j
10,430
1,134
276 points-to edges disappear from a plain -a 4 run at 3.1.0 that were present at 3.0.3.
Describe the solution you'd like
Not stated in the original issue.
Describe alternatives you've considered
Not stated in the original issue.
Additional context
Why it looks like a defect rather than a design change
--external-calls is documented as controlling whether out-of-project call targets are homed — that is, whether external_symbols is populated. Nothing in its description suggests it gates a dependence-analysis tier. A caller who wants points-to dataflow has no reason to think they need a flag about external symbol resolution, and the two runs report the same max_level either way, so nothing in the output says a tier is missing.
Downstream effect, already observable
--emit neo4j forces --external-calls, and python-sdk's in-process backend never passes it. So on 3.1.0 the graph is a strict superset of the JSON payload by exactly those 276 edges, and the same value slice reaches further over Neo4j than in process — for the same project, at the same analysis level. Three python-sdk parity tests had to move from equality to containment as a result.
That asymmetry did not exist at 3.0.3, and it is the kind that is hard to notice: both answers look plausible, and neither is empty.
Expected
Either the points-to tier is computed at -a 4 regardless of --external-calls, or — if the coupling is deliberate — the flag's documentation says so and the payload records which tiers were computed, so a consumer can tell a missing tier from an absent dependence.
Repro
codeanalyzer -i <project> -a 4 -o out-plain
codeanalyzer -i <project> -a 4 --external-calls -o out-flag
Count ddg entries whose prov is ["points-to"] in each analysis.json.
Environment
codeanalyzer-java 3.0.3 and 3.1.0, PyPI wheels with the bundled JVM, macOS 15 arm64. Measured while taking 3.1.0 up in python-sdk (#369).
Fixed in 3.1.1. Verified against the released wheel, same tree, same command as the original report:
run
ddg
points-to
3.0.3 -a 4
10,430
1,134
3.1.0 -a 4
10,154
858
3.1.1 -a 4 (no --external-calls)
10,420
1,134
So the plain -a 4 payload carries the full points-to tier again, and it agrees with what --emit neo4j projects. The downstream asymmetry this caused is gone with it: python-sdk's live suite had three parity assertions weakened from equality to containment because the graph was a strict superset of the payload by 276 points-to edges, and those are going back to equality.
(The 10,420 against 3.0.3's 10,430 is a separate and expected 10 edges, not a regression of this issue — the two releases resolve a few calls differently, which moves the level-4 port vertices with them.)
Closing unless you would rather keep it open for the documentation half — the flag's description still does not say what it does and does not gate, which is what made this hard to spot in the first place.
Correcting one number in my previous comment: the 3.1.1 plain -a 4 payload has 10,430ddg edges, not 10,420. The conclusion is unchanged and in fact stronger.
I had counted with a hand-written walk that recursed into nested types but missed types declared inside callables — the same defective-walk trap that has bitten this project before. Re-counted through the SDK's own flattened index: 10,430, and the payload's edge set is now exactly equal to the graph's, set for set, not merely the same size.
So 3.1.1 restores full parity between -a 4 and --emit neo4j:
run
ddg
points-to
3.0.3 -a 4
10,430
1,134
3.1.0 -a 4
10,154
858
3.1.1 -a 4
10,430
1,134
python-sdk's three parity assertions are back to equality, and the tolerance that carried them for one release is deleted rather than left loose. One of them had a tripwire asserting the gap still existed, which is what flagged that the workaround was obsolete.
Activity
rahlk commentedon Sep 8, 2026
Fixed in 3.1.1. Verified against the released wheel, same tree, same command as the original report:
ddgpoints-to-a 4-a 4-a 4(no--external-calls)So the plain
-a 4payload carries the full points-to tier again, and it agrees with what--emit neo4jprojects. The downstream asymmetry this caused is gone with it: python-sdk's live suite had three parity assertions weakened from equality to containment because the graph was a strict superset of the payload by 276points-toedges, and those are going back to equality.(The 10,420 against 3.0.3's 10,430 is a separate and expected 10 edges, not a regression of this issue — the two releases resolve a few calls differently, which moves the level-4 port vertices with them.)
Closing unless you would rather keep it open for the documentation half — the flag's description still does not say what it does and does not gate, which is what made this hard to spot in the first place.
rahlk commentedon Sep 8, 2026
Correcting one number in my previous comment: the 3.1.1 plain
-a 4payload has 10,430ddgedges, not 10,420. The conclusion is unchanged and in fact stronger.I had counted with a hand-written walk that recursed into nested types but missed types declared inside callables — the same defective-walk trap that has bitten this project before. Re-counted through the SDK's own flattened index: 10,430, and the payload's edge set is now exactly equal to the graph's, set for set, not merely the same size.
So 3.1.1 restores full parity between
-a 4and--emit neo4j:ddgpoints-to-a 4-a 4-a 4python-sdk's three parity assertions are back to equality, and the tolerance that carried them for one release is deleted rather than left loose. One of them had a tripwire asserting the gap still existed, which is what flagged that the workaround was obsolete.