Skip to content

#175: Kotlin bench scopes cut at every type, trace selection walks once per root, and an unbalanced annotation costs only its line - #197

Merged
devmaxxx merged 2 commits into
mainfrom
fix/175-jvm-bench-selection
Oct 17, 2026
Merged

devmaxxx merged 2 commits into
mainfrom
fix/175-jvm-bench-selection

Conversation

@devmaxxx

Copy link
Copy Markdown
Owner

Summary

  • Closes JVM bench selection residuals carried over from #133 #175.
  • Kotlin call-graph owners. di_call_graph used to cut Kotlin files at each class line, and only after a short list of modifiers. That missed object, interface, and enum, value and private classes, and it charged every file-level function after a class to that class. Kotlin scopes now come from blanked text (kotlin_scopes). Each named type owns its lines up to the point where its brackets close. After a nested type ends, the lines that follow belong to the enclosing type again. A companion object belongs to its class, which is how the store reads it. A type named only in a comment or a string opens no scope. Other languages keep the existing cut through DiReader.cls.
  • Names that two scopes share. The graph now also returns shared: every name that more than one scope declares, nested types included. select_jvm_cases drops a trace whose end or via hop is one of those names and counts it under trace_name_two_scopes_share. The reason: the graph merges both classes' calls under one name, and member_chain only checks the file that declared kept.
  • One BFS per root. shortest_paths(graph, src) gives every destination the exact path that shortest_path(graph, src, dst) returns, and trace selection now runs one walk per root instead of one per pair.
  • Unbalanced annotation brackets. In Java, an annotation argument list that never closed used to blank the rest of the file. In Kotlin, its open ( stopped every later declaration from being read. blank_java and blank_kotlin now cut such a list back to the end of its own line, so declarations and declaration_end both recover. A closing bracket of the wrong kind no longer closes the list. Balanced annotations and Kotlin labels (return@forEach, this@A) are unchanged.

Test plan

  • New tests failed before the fix and pass after it:
    • KotlinCallScopes (3 tests)
    • ShortestPaths: every pair across 42 graphs (a diamond, a chain longer than the hop limit, and 40 seeded random graphs) against shortest_path
    • UnbalancedAnnotations (4 tests)
    • SharedNames in test_select_jvm_cases.py (2 tests)
  • python3 -m unittest discover -s bench/compare: 242 tests OK
  • python3 -m unittest discover -s bench/probe: 148 tests OK
  • python3 -m unittest discover -s bench/history: 56 tests OK
  • The one-walk selection matches the per-pair version: with only that change applied, select() from origin/main and from this branch gave byte-identical blast.jsonl, truth.json and summaries on ten fixtures (SHOP, the split-method fixture, and eight seeded 24-class Java/Kotlin corpora with up to 173 trace candidates).
  • Pinned beauty-crm fixture (126 .kt files): the truth for all 10 graded trace cases in bench/blast.jsonl and bench/corpora/beauty-crm-mobile/blast.jsonl is unchanged. The annotation bound changes the blanked text of no file. The Kotlin edges that moved are corrections: library calls (List.*, Map.*, JsonObject.*) that the old cut charged to the wrong class, plus private and value classes that the old cut missed.

The JVM bench selection carried three residuals in the harness.

Kotlin call-graph owners were cut at `class` only, with a short modifier
list, so an `object`, an `interface`, an `enum`/`value`/`private` class
and every file-level function after a class were read as that class's
calls. Kotlin scopes now come from blanked text: every named type owns
its lines up to where its brackets close, a nested type's lines return
to the enclosing type after it ends, and a companion object belongs to
its class, as the store reads it. The graph also reports `shared`, the
names more than one scope declares, and the JVM trace selection drops a
path whose end or via hop is one of them, counted under
`trace_name_two_scopes_share`.

Trace selection ran one breadth-first walk per pair. `shortest_paths`
answers every destination from one walk per root; a test checks it
against `shortest_path` for every pair of 42 graphs, and the selector's
outputs on ten fixtures are byte-identical to the per-pair version.

An annotation argument list that never closed blanked the rest of a
Java file, and in Kotlin its open `(` stopped every later declaration
from being read. Both blankers now cut such a list back to the end of
its own line; balanced annotations and Kotlin labels are untouched.
A default lambda in the constructor (`onClick: () -> Unit = {}`) counted
as the body opening, so a header whose supertype list carried on to the
next line ended on its first line and its body had no owner.
@devmaxxx devmaxxx added this to the 0.6.1 milestone Oct 17, 2026
@devmaxxx
devmaxxx merged commit b01a20d into main Oct 17, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JVM bench selection residuals carried over from #133

1 participant