sourcecode 2.1.0__py3-none-any.whl → 2.3.0__py3-none-any.whl

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.
@@ -122,9 +122,17 @@ class TransactionBoundary:
122
122
  class TransactionBoundaryIndex:
123
123
  """Index of all @Transactional boundaries in a repository."""
124
124
 
125
- # FQN → boundary (both class-level and method-level)
125
+ # FQN → boundary (both class-level and method-level). Keyed by FQN for
126
+ # effective_boundary() call-graph lookups; OVERLOADED methods share an FQN
127
+ # (e.g. findAll() and findAll(Pageable) → Repo#findAll) so this dict collapses
128
+ # them — do NOT count from it (see all_declared / A1 field-validation fix).
126
129
  by_symbol: dict[str, TransactionBoundary] = field(default_factory=dict)
127
130
 
131
+ # Every declared @Transactional boundary, one entry per annotation site.
132
+ # Unlike by_symbol this does NOT collapse overloaded methods, so it is the
133
+ # authoritative source for counts/stats.
134
+ all_declared: list[TransactionBoundary] = field(default_factory=list)
135
+
128
136
  # class FQN → list of method-level boundaries declared on that class
129
137
  by_class: dict[str, list[TransactionBoundary]] = field(default_factory=dict)
130
138
 
@@ -152,17 +160,19 @@ class TransactionBoundaryIndex:
152
160
  return list(self.by_symbol.values())
153
161
 
154
162
  def stats(self) -> dict:
163
+ # Count from all_declared (one entry per annotation site) so overloaded
164
+ # @Transactional methods are not collapsed by the FQN-keyed by_symbol.
155
165
  n_class = len(self.class_level)
156
- n_method = sum(1 for b in self.by_symbol.values() if b.scope == "method")
166
+ n_method = sum(1 for b in self.all_declared if b.scope == "method")
157
167
  propagations: dict[str, int] = {}
158
- for b in self.by_symbol.values():
168
+ for b in self.all_declared:
159
169
  propagations[b.propagation] = propagations.get(b.propagation, 0) + 1
160
170
  return {
161
- "total": len(self.by_symbol),
171
+ "total": len(self.all_declared),
162
172
  "class_level": n_class,
163
173
  "method_level": n_method,
164
174
  "propagations": propagations,
165
- "read_only_count": sum(1 for b in self.by_symbol.values() if b.read_only),
175
+ "read_only_count": sum(1 for b in self.all_declared if b.read_only),
166
176
  }
167
177
 
168
178
 
@@ -353,6 +363,9 @@ def build_tx_index(cir: "CanonicalRepositoryIR") -> TransactionBoundaryIndex:
353
363
  boundary = _build_boundary(fqn, scope, raw_args, source_file, modifiers)
354
364
 
355
365
  index.by_symbol[fqn] = boundary
366
+ # Authoritative per-site list — overloaded methods share an FQN and would
367
+ # collapse in by_symbol; all_declared keeps one entry per annotation site.
368
+ index.all_declared.append(boundary)
356
369
 
357
370
  if scope == "class":
358
371
  index.class_level[fqn] = boundary
@@ -194,8 +194,12 @@ class _TX001ProxyBypass:
194
194
  model: Optional[SpringSemanticModel] = None,
195
195
  ) -> list[SpringFinding]:
196
196
  findings: list[SpringFinding] = []
197
-
198
- for boundary in tx_index.all_boundaries():
197
+ # A1-RESIDUAL: iterate all_declared (one entry per annotation site), not the
198
+ # FQN-keyed all_boundaries which collapses overloads — a public overload
199
+ # overwriting a private one would hide the proxy-bypass risk. Dedupe by
200
+ # finding id (symbol-keyed) so two risky overloads of the same FQN yield one.
201
+ _seen_ids: set[str] = set()
202
+ for boundary in tx_index.all_declared:
199
203
  if boundary.scope != "method":
200
204
  continue
201
205
  if not boundary.is_proxy_bypass_risk:
@@ -209,10 +213,14 @@ class _TX001ProxyBypass:
209
213
  if problematic_modifier == "private"
210
214
  else "Spring CGLIB proxy cannot override final methods"
211
215
  )
216
+ _fid = SpringFinding.make_id(self.pattern_id, boundary.symbol)
217
+ if _fid in _seen_ids:
218
+ continue
219
+ _seen_ids.add(_fid)
212
220
  simple_name = boundary.symbol.rsplit(".", 1)[-1].replace("#", ".")
213
221
 
214
222
  findings.append(SpringFinding(
215
- id=SpringFinding.make_id(self.pattern_id, boundary.symbol),
223
+ id=_fid,
216
224
  pattern_id=self.pattern_id,
217
225
  category="tx",
218
226
  severity=self.severity,
@@ -550,8 +558,11 @@ class _TX005ExceptionSwallowing:
550
558
  return []
551
559
 
552
560
  findings: list[SpringFinding] = []
553
-
554
- for boundary in tx_index.all_boundaries():
561
+ # A1-RESIDUAL: iterate all_declared so a write overload that swallows is not
562
+ # hidden by a read_only overload of the same FQN winning the by_symbol slot
563
+ # (the read_only gate below would skip the whole FQN). Dedupe by finding id.
564
+ _seen_ids: set[str] = set()
565
+ for boundary in tx_index.all_declared:
555
566
  if boundary.scope != "method":
556
567
  continue
557
568
  if not boundary.source_file:
@@ -573,9 +584,13 @@ class _TX005ExceptionSwallowing:
573
584
  if not self._has_swallowed_exception(source, boundary.symbol):
574
585
  continue
575
586
 
587
+ _fid = SpringFinding.make_id(self.pattern_id, boundary.symbol)
588
+ if _fid in _seen_ids:
589
+ continue
590
+ _seen_ids.add(_fid)
576
591
  simple_name = boundary.symbol.rsplit(".", 1)[-1].replace("#", ".")
577
592
  findings.append(SpringFinding(
578
- id=SpringFinding.make_id(self.pattern_id, boundary.symbol),
593
+ id=_fid,
579
594
  pattern_id=self.pattern_id,
580
595
  category="tx",
581
596
  severity=self.severity,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 2.1.0
3
+ Version: 2.3.0
4
4
  Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
5
5
  License-File: LICENSE
6
6
  Keywords: agents,ai,codebase,context,developer-tools,llm
@@ -38,11 +38,11 @@ Description-Content-Type: text/markdown
38
38
 
39
39
  # ASK Engine
40
40
 
41
- > **Persistent structural intelligence for AI coding agents.**
41
+ > **ASK — Actionable Software Knowledge.** Persistent structural intelligence for AI coding agents.
42
42
 
43
43
  **Context · Impact · Migration · Architecture · Review — everything from one structural model.**
44
44
 
45
- ![Version](https://img.shields.io/badge/version-2.1.0-blue)
45
+ ![Version](https://img.shields.io/badge/version-2.3.0-blue)
46
46
  ![Python](https://img.shields.io/badge/python-3.9%2B-green)
47
47
 
48
48
  > **ASK Engine** is the product. The CLI command is **`ask`**. The legacy **`sourcecode`**
@@ -84,7 +84,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
84
84
  # pip / pipx
85
85
  pipx install sourcecode # or: pip install sourcecode
86
86
 
87
- ask version # ask 2.1.0
87
+ ask version # ask 2.3.0
88
88
  ```
89
89
 
90
90
  > **Package vs. command.** The install package is named `sourcecode` this release
@@ -1,14 +1,16 @@
1
- sourcecode/__init__.py,sha256=6IP6ug5fLqU_NKOIzfMwRs-jSKYDBb21TLg1tIzLWAk,308
1
+ sourcecode/__init__.py,sha256=_9_i7ziVcM1wLhG9oULnIMnZhX9H1T1qmnmsiNwXBmg,308
2
2
  sourcecode/adaptive_scanner.py,sha256=XffluXKzJUXrMtjEiAOnSNPZnztdIcts17T9ouHeID0,10521
3
+ sourcecode/archetype.py,sha256=ezeyCR4E0VeZUUBPwmsWUUPAhIlqwwkc8qDieUx2JWA,31087
3
4
  sourcecode/architecture_analyzer.py,sha256=6_wC4TYuBYxaqckZS0I1vBSMRPeH2vzlDB48gXwOOd4,46627
4
- sourcecode/architecture_summary.py,sha256=UaxmUU77oTlWxttMU3c6PxHrU-Q6q5N31TeU_NWWTdU,24297
5
+ sourcecode/architecture_summary.py,sha256=pkl6lIOnSy-poa9EzW43U0MkXhx2FDfAFh8pDXLpcTo,26630
5
6
  sourcecode/ast_extractor.py,sha256=FEsYTsMCXbJfSYQZRk1k-I-PjUNGnKqO1IxMftsgA5U,51351
6
7
  sourcecode/cache.py,sha256=1V3vsaODAa2UBJAC0xpvxpmRdriCezQx5Q8JCcfgziE,31892
7
8
  sourcecode/call_surface.py,sha256=fiqYfHooxN1fX9oQoysq1LS3LoZcobhyUNjAGEZKpwk,4148
9
+ sourcecode/caller_metrics.py,sha256=HG8RCOkpzzsEGdnMRob6byrwjoj5__t0TEsBj4yR7ks,2574
8
10
  sourcecode/canonical_ir.py,sha256=U69m8Vkr0p407xF1q5y1KguHXWEAubYw8NFHR9hDNJk,29178
9
11
  sourcecode/cir_graphs.py,sha256=9G0HHj1kw2325IDyzo2OpX73BNswEckecf4MZUXB4JM,12078
10
- sourcecode/classifier.py,sha256=YTTCoRdcLEFRVcql9Ow1dE7eYQj0jq2rgx32bRDnb1k,13852
11
- sourcecode/cli.py,sha256=PksGF5DiVcPU0SUHw0vKwQA-9w934ZMKCix1K4WX8Rs,289590
12
+ sourcecode/classifier.py,sha256=RhLMDR031FAiUcT3bsf2EL3KrFwl7KsWh_wXXR_Bumo,18729
13
+ sourcecode/cli.py,sha256=rK4umQmgajbQwuwmhhm6q898X-xaniHuRpXbUnW1WUk,296904
12
14
  sourcecode/code_notes_analyzer.py,sha256=EJemNCNc9Dn-1RZYu-aNbK0ELzmsyC4s6FdHi3XyNEI,9392
13
15
  sourcecode/confidence_analyzer.py,sha256=_jckZSxksV-OU38vbkxfVNBnWCtlCq8Vwfg23x1uspA,19054
14
16
  sourcecode/context_graph.py,sha256=8MVDu06bPhvRDTgUqWEvRME2fOw34bFLf4OUILZd13I,43527
@@ -21,17 +23,19 @@ sourcecode/dependency_analyzer.py,sha256=fQCaWQ7_BNcVgZv8gweJCwJ1CGlXsz8nw_tqN3a
21
23
  sourcecode/doc_analyzer.py,sha256=05bjTUbDbmnbajD_cgRnACzS8T7xxBKVX4CjkJlhZg8,24411
22
24
  sourcecode/dynamic_argument_surface.py,sha256=iRzrJhs57UXrGvLhNPiTA-e_sdO6ka-wNqc0wIiegiM,2554
23
25
  sourcecode/endpoint_literals.py,sha256=Qf4gTZzvNSFDGDuOvF0YRL9NvaYKKj24klhR5LIOaXc,3263
26
+ sourcecode/endpoint_metrics.py,sha256=wkAonXe34ItHlvlGur3YRFUrcZfg6GdiiwiE4bMa21Y,2590
24
27
  sourcecode/entrypoint_classifier.py,sha256=jhTYlyqDJH2AtdEcLVaRU3lYRTJuF8DkxVzl4-W3zWE,5322
25
28
  sourcecode/env_analyzer.py,sha256=aNTyYgQk5noJDfJU6FmasmESOHfiomyJw5EvZqjy6qc,22213
26
29
  sourcecode/error_schema.py,sha256=uwosfNaSujtYm11_732Hu92z5ITV040fQDaIyefSvR4,1683
27
30
  sourcecode/evidence_provider.py,sha256=GSSL44JEaouO5AHks2sB3d1YvC9xIKIld1yBYxZpXxo,4277
28
- sourcecode/explain.py,sha256=DyGRH7DXvtuioE1TF7kq8xwprrSSHRXErm840RJ9pIc,21055
31
+ sourcecode/explain.py,sha256=bo4sy8qkEstIF3sIefECKRYJBK97C6cMjyzRa8USCdI,21189
29
32
  sourcecode/file_chunker.py,sha256=3vkM3mDQ5eE_yTPvUgjyjpGFBIjkW6_mrBmIbrylnA8,16444
30
33
  sourcecode/file_classifier.py,sha256=A0fEABqtfVu1MfoaxnPAvGpZgneGgVXlJDhT74NYXxE,15314
31
34
  sourcecode/format_contract.py,sha256=1cTNqwP8geA2hbQoBHUPgX3_vSh3l8guJT_jmgEnFF8,3466
32
35
  sourcecode/fqn_utils.py,sha256=XLU7zDkNBXz_RZkIUNfpPmp1nekWtqP-fxV92tDV1vg,2158
33
36
  sourcecode/git_analyzer.py,sha256=JStxTQXNjBWi_wLdwhsZs9mT-v50cSJIz4Agzn6Kh9I,13362
34
37
  sourcecode/graph_analyzer.py,sha256=lp0eB1PWC20BYF-GpPhAyegRpKrUKgOmXZIcZSIX_Ks,65777
38
+ sourcecode/graph_evidence.py,sha256=rENNsYRZeNstX_ExNCLlbHJAruFQwxo5d00x6wO3xwI,15030
35
39
  sourcecode/hibernate_strat.py,sha256=h0leIhlWvSjYq3F99LxvLIDLrJ-xPYxWAREG4LkqZ-4,61190
36
40
  sourcecode/jdk_exports.py,sha256=fCrlwNAXUT9gge_joq6kMnY3zJxYB2pxqy-0w3o3MJI,874
37
41
  sourcecode/license.py,sha256=keFuwNxdAtvK2Ds91Wl79GMYxuxWYnN5Wbw1qBpaoUI,24896
@@ -40,7 +44,7 @@ sourcecode/metrics_analyzer.py,sha256=m0ENgtqKeBL17kUIK3fmGkgo7UfXBNHxCMj0H_Y5K7
40
44
  sourcecode/migrate_check.py,sha256=HJhvHuvXDGTJSRQU9_AMx0L94h2TImC1DCGs3m3RTu0,108199
41
45
  sourcecode/openapi_surface.py,sha256=BTt0K-woZbkbWTN77IkqeBm_Okag9owR0848fmot8sk,16207
42
46
  sourcecode/output_budget.py,sha256=Js9yUlfQtPhqBl9R6wn_9UHVjjJc3GtLcqyfjf5t50Q,9869
43
- sourcecode/path_filters.py,sha256=VnaD9jxZVNzluackNSTCdIddwzAqIseuSCs_A-gpCDM,6898
47
+ sourcecode/path_filters.py,sha256=T1y0SJsmUJBju2Hh_-z40kURAowUEq42FpPgWLbOaY0,6931
44
48
  sourcecode/pr_comment_renderer.py,sha256=KmcjMruhR44gjzMDJwjBSkWP9QEvh8xWBLyxzxoRbj0,14542
45
49
  sourcecode/pr_impact.py,sha256=dCDVw83EDbyVf6F9ZmEQmsFz8ruVH7d4mpeKQCIZHM0,16805
46
50
  sourcecode/prepare_context.py,sha256=PYygAKL_jwz8gGElgM9mroUSih18UKSSjv08ndfl4aA,222877
@@ -50,7 +54,7 @@ sourcecode/redactor.py,sha256=SB4hwIvg8h-hvcqKcDWaZvA-aSyn-at-BIRwa0tUv5E,3227
50
54
  sourcecode/relevance_scorer.py,sha256=0AgEt4KrV73nioMqBgjhGjtY7L2C7L7cSyKtj3IKcrw,9408
51
55
  sourcecode/rename_refactor.py,sha256=h6dNFlB9aZ_3q6heeHBkgXQeXaT03nvPSsYH6P8qxFg,12965
52
56
  sourcecode/repo_classifier.py,sha256=FG1vaWKdWXsWdl-S8hjVMiTqcwgaRXkDyvK4rPcOGtQ,22681
53
- sourcecode/repository_ir.py,sha256=mMmEAcs5aTS-eHv48tVUQToLylONPRoBAsM_VM3mAmQ,281526
57
+ sourcecode/repository_ir.py,sha256=3DONydNhy-UU1R_1l-caePlBiUlZxkk9X5h92VXsQ34,284195
54
58
  sourcecode/ris.py,sha256=aG2D4159gtpg968yD3PylYbIXhGFOwIlFBI0DSr84yY,20412
55
59
  sourcecode/runtime_classifier.py,sha256=uTAD6BDCiBLUZEDRfqk718kM4RTT_vAbfkcOI2_Xx58,18432
56
60
  sourcecode/scanner.py,sha256=WdOQ78mMzjR1NjmKTlbxdgwinnCTfAhxCVLBEFQiFHU,8899
@@ -59,16 +63,16 @@ sourcecode/security_config.py,sha256=_m8oQAy2gP7Ho2I-IIMTFFjFVWbJIGlLEOiAWK2TDjs
59
63
  sourcecode/security_posture.py,sha256=CAJw4oJD0aAW2yRewvd_fonkzi9_HpUjBZlIDZle00s,26034
60
64
  sourcecode/semantic_analyzer.py,sha256=bpgdC6m0_ftVtRf3rSdwhbhWjnZnGxRXaZVcfe4BbcQ,95414
61
65
  sourcecode/semantic_impact_engine.py,sha256=HpgjenY6DLPHPomP7Hw850zA-EBokf1S4O2sh8NegdI,20351
62
- sourcecode/semantic_integration_engine.py,sha256=cUJFZaBfgzsYpj9hRa9CZjo3U9VSfIQV1k2SQYM5HZw,14524
66
+ sourcecode/semantic_integration_engine.py,sha256=rxoCuP-uM_Y4-ELeBN0sz1a88e2eI1XTJDgsS57IOLI,15513
63
67
  sourcecode/semantic_services.py,sha256=AO_p7PRfjc-AUh6ThvLMfm4iUGi0issL_frCf8sxGlI,10637
64
- sourcecode/serializer.py,sha256=_3aLX3iFbHlqVDx_IlmOBQUI6QLPrL_XX2jxF6gL_No,129094
68
+ sourcecode/serializer.py,sha256=FmQo7eojA_z3ptLW-Vgze5mrEJ6FabcZqiwbQWWTgFI,130056
65
69
  sourcecode/spring_event_topology.py,sha256=5_ON_21Le5zbG-1GRc5GLIi5HJfy_QjcXLVPC5WeUGQ,18055
66
70
  sourcecode/spring_findings.py,sha256=EX7kLZLN74CFyR9iZPm3CI115BfFKNd4WRPuErNljZM,5729
67
71
  sourcecode/spring_impact.py,sha256=1Eu1vkdwTVsw92iBEJDe_i_FaSf4uGH9Rb0eSgIAAZc,57542
68
72
  sourcecode/spring_model.py,sha256=zOAgFmrRbG4a6KLm1TJl55aWMyPNsz3OS3FSczqPG6A,16594
69
73
  sourcecode/spring_security_audit.py,sha256=Rk-aSohezdc7YDYbSoJquVnwpkDB8ty1BCD-4Hc4R5A,22832
70
- sourcecode/spring_semantic.py,sha256=O1nKSGVzlukuxLHQVuCPxc-XrcrMFxwlHA20_dmEGgM,13307
71
- sourcecode/spring_tx_analyzer.py,sha256=iH9mK0Tgvhgy_Ee2r13KA_RMf8HKN-pjCKQGuyCCBjM,33812
74
+ sourcecode/spring_semantic.py,sha256=jteQ1PkY9ArFJv0embg_jBIdbOxqrk9mQ2Xz8OF_FKA,14214
75
+ sourcecode/spring_tx_analyzer.py,sha256=QMXkxa_hrqDVN3D8WJsd0nT7vfdZCT1E8ZWNoFFbvgU,34692
72
76
  sourcecode/summarizer.py,sha256=ByfFxIGVRrGrf3paQPuDOg1rVj78LyzXN_EXBkfbCLU,23582
73
77
  sourcecode/tree_utils.py,sha256=8GAkIfQAsvtEudIeW1l4ooH_oRtrWR8cpJQJsEa_Pfw,2093
74
78
  sourcecode/type_usage_surface.py,sha256=51IrKRQoIoRnlsiDjHnqpJBn2rc6E59aRhgS0HTzAF0,4428
@@ -85,7 +89,7 @@ sourcecode/detectors/elixir.py,sha256=jCpvt5Yi6jvplc80ovRtWh17q-11ZGo9qX7o8b57TJ
85
89
  sourcecode/detectors/go.py,sha256=2r66uRQfeTWsqxr4HDhT6vExZErby0t46QXLHVBRv9w,2782
86
90
  sourcecode/detectors/heuristic.py,sha256=7cRxrip4yIaggYzZJB6ef8yHKh-gHgiH_pXMFcjlyFU,3723
87
91
  sourcecode/detectors/hybrid.py,sha256=IGFRUVsAZ1ooRlFdznCeJAV6vy1yVDx-VyghvLtddXc,9101
88
- sourcecode/detectors/java.py,sha256=xlp4mqd26QWJf3MWqmTbD0IND_VEVzPHlGaLC4MNXNA,39028
92
+ sourcecode/detectors/java.py,sha256=rTeVIKIliElE1yPdIkll1pKqDUzXD1EFFJdXxp24gr4,41005
89
93
  sourcecode/detectors/jvm_ext.py,sha256=EgHJ5W8EE-ZTN9V607mVzohyKgZE8Mc2jCi-DF8RAZU,2616
90
94
  sourcecode/detectors/nodejs.py,sha256=Hg3Gmr7yIMJFiLoDwOTk2wtu00wxIs6kZf-oQujTFUA,13187
91
95
  sourcecode/detectors/parsers.py,sha256=ug9K31tyHqinmv0HkIVQVjdTZpBv67FYKAEf52YXOSM,3178
@@ -113,8 +117,8 @@ sourcecode/telemetry/consent.py,sha256=LIAO9ohJZF8OuZwM4u1VWtALlYfTCCKq4wV3Vwc7i
113
117
  sourcecode/telemetry/events.py,sha256=LtzYfaX9Ilckj5PTvAcTpDa9mLqDsYPDUiDkRa58piY,2580
114
118
  sourcecode/telemetry/filters.py,sha256=NHa5T-6DaZduQPFuC34jOqHWQgSizM-Ygq8aZ4j19ng,5834
115
119
  sourcecode/telemetry/transport.py,sha256=4gGHsq0WeY9VywEZXA3vUxykfiYnw9uuqfjAAec7F8o,1681
116
- sourcecode-2.1.0.dist-info/METADATA,sha256=YcJphSnTG4SGmAeb7R2XWhj4nIp4-1hazejT7QdPo9Y,10798
117
- sourcecode-2.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
118
- sourcecode-2.1.0.dist-info/entry_points.txt,sha256=-JEAdChrK5We51kZcb7OaDcyil-dHBjBPL-NhuO-QY8,89
119
- sourcecode-2.1.0.dist-info/licenses/LICENSE,sha256=7DdHrU9Z_3e7dSvq4ISijZNjnuHo5NIHNiHDouMQ9JU,10491
120
- sourcecode-2.1.0.dist-info/RECORD,,
120
+ sourcecode-2.3.0.dist-info/METADATA,sha256=sOmWl4PHteHOjBgUxeKpVh6H6Hc2Yo-Zyrk3c62z1CE,10837
121
+ sourcecode-2.3.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
122
+ sourcecode-2.3.0.dist-info/entry_points.txt,sha256=-JEAdChrK5We51kZcb7OaDcyil-dHBjBPL-NhuO-QY8,89
123
+ sourcecode-2.3.0.dist-info/licenses/LICENSE,sha256=7DdHrU9Z_3e7dSvq4ISijZNjnuHo5NIHNiHDouMQ9JU,10491
124
+ sourcecode-2.3.0.dist-info/RECORD,,