sourcecode 1.30.24__py3-none-any.whl → 1.30.25__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.
- sourcecode/__init__.py +1 -1
- sourcecode/cli.py +25 -0
- sourcecode/pr_comment_renderer.py +43 -42
- sourcecode/prepare_context.py +18 -4
- {sourcecode-1.30.24.dist-info → sourcecode-1.30.25.dist-info}/METADATA +3 -3
- {sourcecode-1.30.24.dist-info → sourcecode-1.30.25.dist-info}/RECORD +9 -9
- {sourcecode-1.30.24.dist-info → sourcecode-1.30.25.dist-info}/WHEEL +0 -0
- {sourcecode-1.30.24.dist-info → sourcecode-1.30.25.dist-info}/entry_points.txt +0 -0
- {sourcecode-1.30.24.dist-info → sourcecode-1.30.25.dist-info}/licenses/LICENSE +0 -0
sourcecode/__init__.py
CHANGED
sourcecode/cli.py
CHANGED
|
@@ -2030,6 +2030,10 @@ def prepare_context_cmd(
|
|
|
2030
2030
|
out["runtime_changes"] = output.runtime_changes
|
|
2031
2031
|
if output.build_changes:
|
|
2032
2032
|
out["build_changes"] = output.build_changes
|
|
2033
|
+
if output.committed_changes:
|
|
2034
|
+
out["committed_changes"] = output.committed_changes
|
|
2035
|
+
if output.uncommitted_changes:
|
|
2036
|
+
out["uncommitted_changes"] = output.uncommitted_changes
|
|
2033
2037
|
if output.review_hotspots:
|
|
2034
2038
|
out["review_hotspots"] = output.review_hotspots
|
|
2035
2039
|
if output.suggested_review_order:
|
|
@@ -2047,6 +2051,27 @@ def prepare_context_cmd(
|
|
|
2047
2051
|
"files": output.scope_files,
|
|
2048
2052
|
"repo_root": output.repo_root or "",
|
|
2049
2053
|
}
|
|
2054
|
+
# analysis_limiter: consolidate missing graph signals into one field
|
|
2055
|
+
_missing_signals: list[str] = []
|
|
2056
|
+
_dgraph = output.dependency_graph_summary or {}
|
|
2057
|
+
if not _dgraph.get("has_graph_evidence"):
|
|
2058
|
+
_missing_signals.append("dependency_graph")
|
|
2059
|
+
_has_import_ev = any(
|
|
2060
|
+
(rc.get("role") or {}).get("has_annotation_signal") or
|
|
2061
|
+
(rc.get("role") or {}).get("has_symbol_signal")
|
|
2062
|
+
for rc in (output.runtime_changes or [])
|
|
2063
|
+
)
|
|
2064
|
+
if not _has_import_ev:
|
|
2065
|
+
_missing_signals.append("import_graph")
|
|
2066
|
+
if _missing_signals:
|
|
2067
|
+
out["analysis_limiter"] = {"missing_signals": _missing_signals}
|
|
2068
|
+
# classification_confidence: global note when all runtime files are low confidence
|
|
2069
|
+
_all_low = bool(output.runtime_changes) and all(
|
|
2070
|
+
(rc.get("change_effect") or {}).get("epistemic_level") == "INFERRED (LOW CONFIDENCE)"
|
|
2071
|
+
for rc in output.runtime_changes
|
|
2072
|
+
)
|
|
2073
|
+
if _all_low:
|
|
2074
|
+
out["classification_confidence"] = "low"
|
|
2050
2075
|
if output.limitations:
|
|
2051
2076
|
out["limitations"] = output.limitations
|
|
2052
2077
|
if output.symptom:
|
|
@@ -171,13 +171,31 @@ def _section_priority_order(out: dict) -> str:
|
|
|
171
171
|
lines.append("*No priority order available — diff scope too narrow to rank.*")
|
|
172
172
|
return "\n".join(lines)
|
|
173
173
|
|
|
174
|
-
|
|
174
|
+
visible = order[:_MAX_PRIORITY_FILES]
|
|
175
|
+
all_low = visible and all(
|
|
176
|
+
(cls_map.get(p, {}).get("change_effect") or {}).get("epistemic_level")
|
|
177
|
+
== "INFERRED (LOW CONFIDENCE)"
|
|
178
|
+
for p in visible
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
for i, path in enumerate(visible, 1):
|
|
175
182
|
rc = cls_map.get(path, {})
|
|
176
183
|
effect = rc.get("change_effect", {})
|
|
177
184
|
stmt = effect.get("statement", "application source") if isinstance(effect, dict) else "application source"
|
|
178
|
-
ep = effect.get("epistemic_level", "STRUCTURAL SIGNAL") if isinstance(effect, dict) else "STRUCTURAL SIGNAL"
|
|
179
185
|
atype = rc.get("artifact_type", "source")
|
|
180
|
-
|
|
186
|
+
if all_low:
|
|
187
|
+
lines.append(f"{i}. `{_short(path)}` — {atype} — {stmt}")
|
|
188
|
+
else:
|
|
189
|
+
ep = effect.get("epistemic_level", "STRUCTURAL SIGNAL") if isinstance(effect, dict) else "STRUCTURAL SIGNAL"
|
|
190
|
+
lines.append(f"{i}. `{_short(path)}` — {_badge(ep)}: {atype} — {stmt}")
|
|
191
|
+
|
|
192
|
+
if all_low:
|
|
193
|
+
lines.append("")
|
|
194
|
+
lines.append(
|
|
195
|
+
f"*Classification confidence: low for all changed files "
|
|
196
|
+
f"{_badge('INFERRED (LOW CONFIDENCE)')} — "
|
|
197
|
+
"no annotation/import signals found in changed files.*"
|
|
198
|
+
)
|
|
181
199
|
|
|
182
200
|
return "\n".join(lines)
|
|
183
201
|
|
|
@@ -269,50 +287,26 @@ def _section_signals(out: dict) -> str:
|
|
|
269
287
|
def _section_guidance(out: dict) -> str:
|
|
270
288
|
lines = ["### 5. Review Guidance", ""]
|
|
271
289
|
|
|
272
|
-
# Inspect first
|
|
273
|
-
order: list[str] = out.get("suggested_review_order", []) or out.get("review_hotspots", [])
|
|
274
|
-
runtime: list[dict] = out.get("runtime_changes", [])
|
|
275
|
-
cls_map: dict[str, dict] = {rc["path"]: rc for rc in runtime}
|
|
276
|
-
|
|
277
|
-
if order:
|
|
278
|
-
lines.append("**Inspect first:**")
|
|
279
|
-
for path in order[:3]:
|
|
280
|
-
rc = cls_map.get(path, {})
|
|
281
|
-
effect = rc.get("change_effect", {})
|
|
282
|
-
stmt = effect.get("statement", "") if isinstance(effect, dict) else ""
|
|
283
|
-
ep = effect.get("epistemic_level", "STRUCTURAL SIGNAL") if isinstance(effect, dict) else "STRUCTURAL SIGNAL"
|
|
284
|
-
label = f" — {stmt}" if stmt else ""
|
|
285
|
-
lines.append(f"- `{_short(path)}`{label} {_badge(ep)}")
|
|
286
|
-
lines.append("")
|
|
287
|
-
|
|
288
|
-
# Uncertain — heuristic-only behavioral paths
|
|
289
|
-
behavioral: list[dict] = out.get("behavioral_impact", [])
|
|
290
|
-
weak_paths = [
|
|
291
|
-
bi for bi in behavioral
|
|
292
|
-
if bi.get("evidence_level", "none") == "heuristic_only"
|
|
293
|
-
]
|
|
294
|
-
if weak_paths:
|
|
295
|
-
lines.append("**Uncertain (heuristic-only — verify manually):**")
|
|
296
|
-
for bi in weak_paths[:_MAX_UNCERTAIN]:
|
|
297
|
-
entry = bi.get("entry_point", "")
|
|
298
|
-
affected: list[str] = bi.get("affected_path", [])
|
|
299
|
-
path_str = " → ".join(affected) if affected else "unknown"
|
|
300
|
-
lines.append(
|
|
301
|
-
f"- `{entry}` → {path_str} "
|
|
302
|
-
f"{_badge('INFERRED (LOW CONFIDENCE)')}: class reference only, no injection/call proof"
|
|
303
|
-
)
|
|
304
|
-
lines.append("")
|
|
305
|
-
|
|
306
|
-
# Evidence gaps
|
|
290
|
+
# Evidence gaps ONLY — "Inspect first" covered by §3, "Uncertain" covered by §2
|
|
307
291
|
gaps: list[str] = out.get("gaps", [])
|
|
308
292
|
cov = out.get("test_coverage_risk", {})
|
|
309
293
|
test_files: list[str] = cov.get("changed_files_without_tests", [])
|
|
310
294
|
test_basis = cov.get("basis", "")
|
|
311
295
|
cov_ep = cov.get("epistemic_level", "INFERRED (LOW CONFIDENCE)")
|
|
312
296
|
|
|
313
|
-
|
|
297
|
+
# Skip graph-absence gaps already captured in analysis_limiter
|
|
298
|
+
missing_signals: set[str] = set(
|
|
299
|
+
(out.get("analysis_limiter") or {}).get("missing_signals", [])
|
|
300
|
+
)
|
|
301
|
+
gap_items: list[str] = [
|
|
302
|
+
g for g in gaps
|
|
303
|
+
if not missing_signals or not any(
|
|
304
|
+
sig.replace("_", " ") in g.lower() for sig in missing_signals
|
|
305
|
+
)
|
|
306
|
+
]
|
|
307
|
+
|
|
314
308
|
if test_files:
|
|
315
|
-
shown = test_files[:
|
|
309
|
+
shown = test_files[:3]
|
|
316
310
|
omitted = len(test_files) - len(shown)
|
|
317
311
|
names = ", ".join(f"`{_short(f)}`" for f in shown)
|
|
318
312
|
suffix = f" +{omitted} more" if omitted else ""
|
|
@@ -323,12 +317,19 @@ def _section_guidance(out: dict) -> str:
|
|
|
323
317
|
)
|
|
324
318
|
|
|
325
319
|
if gap_items:
|
|
326
|
-
lines.append("**Evidence gaps
|
|
327
|
-
for g in gap_items:
|
|
320
|
+
lines.append("**Evidence gaps:**")
|
|
321
|
+
for g in gap_items[:3]:
|
|
328
322
|
lines.append(f"- {g}")
|
|
329
323
|
else:
|
|
330
324
|
lines.append("*No evidence gaps detected.*")
|
|
331
325
|
|
|
326
|
+
if missing_signals:
|
|
327
|
+
lines.append("")
|
|
328
|
+
lines.append(
|
|
329
|
+
f"{_badge('OMITTED')}: {', '.join(sorted(missing_signals))} — "
|
|
330
|
+
"graph-based impact analysis unavailable"
|
|
331
|
+
)
|
|
332
|
+
|
|
332
333
|
return "\n".join(lines)
|
|
333
334
|
|
|
334
335
|
|
sourcecode/prepare_context.py
CHANGED
|
@@ -1271,9 +1271,9 @@ class TaskContextBuilder:
|
|
|
1271
1271
|
"evidence": _evidence,
|
|
1272
1272
|
"change_effect": {
|
|
1273
1273
|
"statement": _ARTIFACT_CHANGE_EFFECT.get(_f_atype, "application source file (role could not be confirmed)"),
|
|
1274
|
-
"classification_method":
|
|
1274
|
+
"classification_method": _role_basis,
|
|
1275
1275
|
"epistemic_level": (
|
|
1276
|
-
"STRUCTURAL SIGNAL" if
|
|
1276
|
+
"STRUCTURAL SIGNAL" if _has_code_ev
|
|
1277
1277
|
else "INFERRED (LOW CONFIDENCE)"
|
|
1278
1278
|
),
|
|
1279
1279
|
},
|
|
@@ -2054,10 +2054,18 @@ class TaskContextBuilder:
|
|
|
2054
2054
|
if since is None and not committed_files and not uncommitted_files:
|
|
2055
2055
|
head_ok = _run("git", "rev-parse", "--verify", "HEAD~1")
|
|
2056
2056
|
if head_ok is not None: # HEAD~1 exists
|
|
2057
|
-
head_committed = _run("git", "diff", "--name-only", "--relative", "HEAD~1
|
|
2057
|
+
head_committed = _run("git", "diff", "--name-only", "--relative", "HEAD~1..HEAD")
|
|
2058
2058
|
if head_committed:
|
|
2059
2059
|
committed_files = head_committed
|
|
2060
2060
|
sources.append(DiffSourceType.HEAD_MINUS_1.value)
|
|
2061
|
+
else:
|
|
2062
|
+
# First commit — no HEAD~1; diff against git empty tree
|
|
2063
|
+
_GIT_EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
|
|
2064
|
+
first_committed = _run("git", "diff", "--name-only", "--relative",
|
|
2065
|
+
_GIT_EMPTY_TREE, "HEAD")
|
|
2066
|
+
if first_committed:
|
|
2067
|
+
committed_files = first_committed
|
|
2068
|
+
sources.append("initial_commit")
|
|
2061
2069
|
|
|
2062
2070
|
# ── Drop paths outside self.root ──────────────────────────────────────
|
|
2063
2071
|
def _drop_outside(lst: list[str]) -> list[str]:
|
|
@@ -3280,8 +3288,14 @@ class TaskContextBuilder:
|
|
|
3280
3288
|
files = _diff("HEAD~1")
|
|
3281
3289
|
if files is not None:
|
|
3282
3290
|
return _make(files or [], "HEAD~1", "head_minus_1_fallback")
|
|
3291
|
+
else:
|
|
3292
|
+
# First commit — no HEAD~1; diff against git empty tree
|
|
3293
|
+
_GIT_EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
|
|
3294
|
+
files = _diff(_GIT_EMPTY_TREE)
|
|
3295
|
+
if files is not None:
|
|
3296
|
+
return _make(files or [], _GIT_EMPTY_TREE, "initial_commit_fallback")
|
|
3283
3297
|
|
|
3284
|
-
# Confirmed no changes:
|
|
3298
|
+
# Confirmed no changes: empty repo
|
|
3285
3299
|
return {
|
|
3286
3300
|
"files": [],
|
|
3287
3301
|
"resolved_ref": "HEAD",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 1.30.
|
|
3
|
+
Version: 1.30.25
|
|
4
4
|
Summary: Deterministic codebase context for AI coding agents
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -221,7 +221,7 @@ Description-Content-Type: text/markdown
|
|
|
221
221
|
|
|
222
222
|
**Deterministic, behavior-aware codebase context for AI agents and PR review.**
|
|
223
223
|
|
|
224
|
-

|
|
225
225
|

|
|
226
226
|
|
|
227
227
|
---
|
|
@@ -257,7 +257,7 @@ pipx install sourcecode
|
|
|
257
257
|
|
|
258
258
|
```bash
|
|
259
259
|
sourcecode version
|
|
260
|
-
# sourcecode 1.30.
|
|
260
|
+
# sourcecode 1.30.25
|
|
261
261
|
```
|
|
262
262
|
|
|
263
263
|
---
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
sourcecode/__init__.py,sha256=
|
|
1
|
+
sourcecode/__init__.py,sha256=kJzip46z8Zv1pZNNGqmBkCQorsqmA5F7jeh9VqnPkaY,104
|
|
2
2
|
sourcecode/adaptive_scanner.py,sha256=RTNExwWPXzjgLaRueT7UuxkPj5ZEToWjGbx1j0LSZ9E,10250
|
|
3
3
|
sourcecode/architecture_analyzer.py,sha256=MyBa0Hf5HmkudZQDLKrjcWDKETXETXl0mQX1swtTwAA,39091
|
|
4
4
|
sourcecode/architecture_summary.py,sha256=z34_6v7cSwy98cof2UVciGho7SCrZ93tiqMmq5WNzRQ,20405
|
|
5
5
|
sourcecode/ast_extractor.py,sha256=XgrZg2DcWcUm9r87cRG3KGO7IK2TIL_N-CvhSbUmmh4,49901
|
|
6
6
|
sourcecode/classifier.py,sha256=pYve2J1LqtYssU3lYLMDz18PT-CjN5c18QYE7R_IG1Q,7507
|
|
7
|
-
sourcecode/cli.py,sha256=
|
|
7
|
+
sourcecode/cli.py,sha256=xNbK_xwsqdhUbAJT4VieJDitGlhMu_O_Y5xzY8yrc9Q,94497
|
|
8
8
|
sourcecode/code_notes_analyzer.py,sha256=y1MJBnPZHYp4i6cQCXUb9ATIyifS_qMQWjw_8lPkpsU,9215
|
|
9
9
|
sourcecode/confidence_analyzer.py,sha256=xw_Jv8pAd0wd8t2vvQlorw8Ih0rSF3YCoFS8K-_4aXg,15762
|
|
10
10
|
sourcecode/context_scorer.py,sha256=QpChSpsmaAYz91rXA4Ue5xzQmNz_ZboZN09YOHScq1U,14679
|
|
@@ -21,8 +21,8 @@ sourcecode/flow_analyzer.py,sha256=dSiuY4w49k29jW_EPXUOND9B5uVbuCA7kjnuHi-pIWA,2
|
|
|
21
21
|
sourcecode/git_analyzer.py,sha256=0Gyj-vMpIIN4nfriKXVRouNYBeJ59s6pQDX2Xu9Pq-U,13177
|
|
22
22
|
sourcecode/graph_analyzer.py,sha256=iUK-7pSV-cvGqqD2hENdYmhnm0wcXFEyK-xnu5ul8OU,62515
|
|
23
23
|
sourcecode/metrics_analyzer.py,sha256=m0ENgtqKeBL17kUIK3fmGkgo7UfXBNHxCMj0H_Y5K7c,22750
|
|
24
|
-
sourcecode/pr_comment_renderer.py,sha256=
|
|
25
|
-
sourcecode/prepare_context.py,sha256=
|
|
24
|
+
sourcecode/pr_comment_renderer.py,sha256=smHslxiG14lrytCkq5nFrFu-qTHgA-t-LFYfdrfjz2o,14423
|
|
25
|
+
sourcecode/prepare_context.py,sha256=PlmfECy56vJwPthp-9YwFKHtgaD6XZwreEhyZ7q-G7E,166416
|
|
26
26
|
sourcecode/progress.py,sha256=qn30sWaHOkjTgXsSBmiPkz7Rsbwc5oSlIe6JNEMYp_k,3149
|
|
27
27
|
sourcecode/ranking_engine.py,sha256=virVglafZufioHpZpwktjMvUiL0TZELWQCQnQNV8dFo,9360
|
|
28
28
|
sourcecode/redactor.py,sha256=xuGcadGEHaPw4qZXlMDvzMCsr4VOkdp3oBQptHyJk8c,2884
|
|
@@ -64,8 +64,8 @@ sourcecode/telemetry/consent.py,sha256=wLMvGNJeSSyZoNkQXpoUioY6mMv4Qdvuw7S9jAEWn
|
|
|
64
64
|
sourcecode/telemetry/events.py,sha256=oEvvulfsv5GIDWG2174gSS6tNB95w38AIYiYeifGKlE,2294
|
|
65
65
|
sourcecode/telemetry/filters.py,sha256=Asa71oRl7q3Wt_FMwuufIZJFzSYdgRNKS8LHCIyFeYE,4805
|
|
66
66
|
sourcecode/telemetry/transport.py,sha256=KJeIPCPWMdmbCP3ySGs2iUlia34U6vWne2dZsUezesw,1560
|
|
67
|
-
sourcecode-1.30.
|
|
68
|
-
sourcecode-1.30.
|
|
69
|
-
sourcecode-1.30.
|
|
70
|
-
sourcecode-1.30.
|
|
71
|
-
sourcecode-1.30.
|
|
67
|
+
sourcecode-1.30.25.dist-info/METADATA,sha256=kPiIROhykJQpgwjLYSkJKtEqag987u3EloszmgQ2HmY,28956
|
|
68
|
+
sourcecode-1.30.25.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
69
|
+
sourcecode-1.30.25.dist-info/entry_points.txt,sha256=ex3F9rmbXeyDIoFQHtkEqTsKSaJow8F0LrVu8XfIktQ,57
|
|
70
|
+
sourcecode-1.30.25.dist-info/licenses/LICENSE,sha256=7DdHrU9Z_3e7dSvq4ISijZNjnuHo5NIHNiHDouMQ9JU,10491
|
|
71
|
+
sourcecode-1.30.25.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|