sourcecode 0.46.0__tar.gz → 0.48.0__tar.gz
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-0.46.0 → sourcecode-0.48.0}/PKG-INFO +1 -1
- {sourcecode-0.46.0 → sourcecode-0.48.0}/pyproject.toml +1 -1
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/__init__.py +1 -1
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/context_scorer.py +2 -2
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/contract_pipeline.py +27 -7
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/prepare_context.py +1 -1
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/relevance_scorer.py +2 -1
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/serializer.py +67 -36
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_real_projects.py +5 -4
- {sourcecode-0.46.0 → sourcecode-0.48.0}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/.gitignore +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/.ruff.toml +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/CONTRIBUTING.md +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/LICENSE +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/README.md +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/SECURITY.md +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/docs/privacy.md +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/docs/schema.md +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/raw +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/classifier.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/cli.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/redactor.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/scanner.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/schema.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/src/sourcecode/workspace.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/__init__.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/conftest.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/coverage.xml +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/fastapi_app/src/main.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/go_service/cmd/api/main.go +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/go_service/go.mod +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/jacoco.xml +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/lcov.info +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/nextjs_app/package.json +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_architecture_analyzer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_architecture_summary.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_ast_extractor.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_block1_reliability.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_block2_coverage.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_block5_quality.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_classifier.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_cli.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_code_notes_analyzer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_context_scorer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_contract_pipeline.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_coverage_parser.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_cross_consistency.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_dependency_analyzer_node_python.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_dependency_analyzer_polyglot.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_dependency_schema.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_detector_dotnet.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_detector_go_rust_java.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_detector_nodejs.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_detector_php_ruby_dart.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_detector_python.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_detector_universal_managed.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_detector_universal_systems.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_detectors_base.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_doc_analyzer_jsdom.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_doc_analyzer_python.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_graph_analyzer_polyglot.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_graph_analyzer_python_node.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_graph_schema.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_hybrid_inference.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_integration.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_integration_dependencies.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_integration_detection.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_integration_docs.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_integration_graph_modules.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_integration_lqn.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_integration_metrics.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_integration_multistack.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_integration_semantics.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_integration_universal.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_metrics_analyzer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_packaging.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_phase1_improvements.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_pipeline_integrity.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_redactor.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_scanner.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_schema.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_schema_normalization.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_semantic_analyzer_node.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_semantic_analyzer_python.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_semantic_import_resolution.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_semantic_schema.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_signal_hierarchy.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_summarizer.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_telemetry.py +0 -0
- {sourcecode-0.46.0 → sourcecode-0.48.0}/tests/test_workspace_analyzer.py +0 -0
|
@@ -177,8 +177,8 @@ class ContextScorer:
|
|
|
177
177
|
node_scores: dict[str, NodeScore],
|
|
178
178
|
contracts: list[Any],
|
|
179
179
|
*,
|
|
180
|
-
budget: int =
|
|
181
|
-
min_score: float = 0.
|
|
180
|
+
budget: int = 25,
|
|
181
|
+
min_score: float = 0.15,
|
|
182
182
|
) -> list[str]:
|
|
183
183
|
"""Greedy minimum-sufficient subgraph selection with diversity re-ranking.
|
|
184
184
|
|
|
@@ -17,6 +17,7 @@ from typing import Any, Literal, Optional
|
|
|
17
17
|
|
|
18
18
|
from sourcecode.ast_extractor import AstExtractor, _LANGUAGE_MAP
|
|
19
19
|
from sourcecode.contract_model import ContractSummary, FileContract
|
|
20
|
+
from sourcecode.entrypoint_classifier import is_production_entry_point
|
|
20
21
|
from sourcecode.ranking_engine import RankingEngine
|
|
21
22
|
from sourcecode.relevance_scorer import RelevanceScorer
|
|
22
23
|
from sourcecode.schema import EntryPoint, MonorepoPackageInfo
|
|
@@ -25,7 +26,9 @@ from sourcecode.schema import EntryPoint, MonorepoPackageInfo
|
|
|
25
26
|
# Constants
|
|
26
27
|
# ---------------------------------------------------------------------------
|
|
27
28
|
|
|
28
|
-
_MAX_FILES = 500
|
|
29
|
+
_MAX_FILES = 500 # hard cap on files extracted per run
|
|
30
|
+
_MAX_CONTRACTS = 25 # default top-N output cap — omit rather than flood
|
|
31
|
+
_MIN_CONTRACT_SCORE = 0.10 # drop contracts below this relevance threshold
|
|
29
32
|
_SRC_EXTENSIONS: frozenset[str] = frozenset(_LANGUAGE_MAP.keys())
|
|
30
33
|
|
|
31
34
|
|
|
@@ -178,12 +181,20 @@ class ContractPipeline:
|
|
|
178
181
|
max_importers: int = 50,
|
|
179
182
|
semantic_calls: Optional[list] = None,
|
|
180
183
|
code_notes: Optional[list] = None,
|
|
184
|
+
max_contracts: Optional[int] = _MAX_CONTRACTS,
|
|
181
185
|
) -> tuple[list[FileContract], ContractSummary]:
|
|
182
186
|
"""Run the full extraction pipeline.
|
|
183
187
|
|
|
184
188
|
Returns (ranked_contracts, summary).
|
|
185
189
|
"""
|
|
186
|
-
|
|
190
|
+
# Only treat production-classified entrypoints as anchors.
|
|
191
|
+
# Convention/heuristic entrypoints (index.ts barrels, plugin examples)
|
|
192
|
+
# must not bubble to the top via is_entrypoint=True ranking boost.
|
|
193
|
+
entry_paths = {
|
|
194
|
+
ep.path.replace("\\", "/")
|
|
195
|
+
for ep in (entry_points or [])
|
|
196
|
+
if is_production_entry_point(ep)
|
|
197
|
+
}
|
|
187
198
|
scorer = RelevanceScorer(monorepo_packages)
|
|
188
199
|
engine = RankingEngine(monorepo_packages)
|
|
189
200
|
|
|
@@ -299,16 +310,25 @@ class ContractPipeline:
|
|
|
299
310
|
max_importers=max_importers,
|
|
300
311
|
)
|
|
301
312
|
|
|
302
|
-
# 9. Entrypoints-only filter
|
|
313
|
+
# 9. Entrypoints-only filter — production entry points only, no export spill
|
|
303
314
|
if entrypoints_only and not symbol:
|
|
304
|
-
contracts = [c for c in contracts if c.is_entrypoint
|
|
305
|
-
|
|
306
|
-
# 10.
|
|
315
|
+
contracts = [c for c in contracts if c.is_entrypoint]
|
|
316
|
+
|
|
317
|
+
# 10. Top-N cap — enforce max_contracts when not in symbol-search mode.
|
|
318
|
+
# Symbol searches must return all matching files; budget applies only to
|
|
319
|
+
# the default architectural briefing use case.
|
|
320
|
+
if symbol is None and max_contracts is not None:
|
|
321
|
+
contracts = [
|
|
322
|
+
c for c in contracts
|
|
323
|
+
if c.relevance_score >= _MIN_CONTRACT_SCORE or c.is_entrypoint
|
|
324
|
+
][:max_contracts]
|
|
325
|
+
|
|
326
|
+
# 11. Compress types if requested
|
|
307
327
|
if compress_types:
|
|
308
328
|
for c in contracts:
|
|
309
329
|
_compress_contract_types(c)
|
|
310
330
|
|
|
311
|
-
#
|
|
331
|
+
# 12. Apply max_symbols limit (limits total exports across all contracts)
|
|
312
332
|
if max_symbols is not None and max_symbols > 0:
|
|
313
333
|
contracts = _limit_symbols(contracts, max_symbols)
|
|
314
334
|
|
|
@@ -758,7 +758,7 @@ class TaskContextBuilder:
|
|
|
758
758
|
)
|
|
759
759
|
for total, path, rf in scored
|
|
760
760
|
}
|
|
761
|
-
_selected = _ctx.select_subgraph(_ns, contracts=[], budget=15, min_score=0.
|
|
761
|
+
_selected = _ctx.select_subgraph(_ns, contracts=[], budget=15, min_score=0.15)
|
|
762
762
|
_rf_map = {path: rf for _, path, rf in scored}
|
|
763
763
|
return [_rf_map[p] for p in _selected if p in _rf_map]
|
|
764
764
|
except Exception:
|
|
@@ -124,8 +124,9 @@ _HIGH_VALUE_SUFFIXES: frozenset[str] = frozenset({
|
|
|
124
124
|
})
|
|
125
125
|
|
|
126
126
|
_ENTRYPOINT_STEMS: frozenset[str] = frozenset({
|
|
127
|
-
"main", "cli", "app", "server", "
|
|
127
|
+
"main", "cli", "app", "server", "__main__",
|
|
128
128
|
"application", "bootstrap", "entry",
|
|
129
|
+
# "index" removed — barrel export convention, not a runtime entrypoint signal
|
|
129
130
|
})
|
|
130
131
|
|
|
131
132
|
|
|
@@ -24,6 +24,21 @@ from sourcecode.schema import (
|
|
|
24
24
|
SourceMap,
|
|
25
25
|
)
|
|
26
26
|
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
28
|
+
# Visibility caps — public output is intentionally small.
|
|
29
|
+
# Internal analysis stays broad; only high-signal results reach the output.
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
_EP_PRODUCTION_CAP = 5 # max production entry points in default output
|
|
32
|
+
_EP_DEV_CAP = 3 # max development entry points in default output
|
|
33
|
+
_FILE_RELEVANCE_LIMIT = 10 # max files in file_relevance section
|
|
34
|
+
_FILE_RELEVANCE_MIN_COMBINED = 0.40 # minimum combined score — must earn inclusion
|
|
35
|
+
_PROD_DEPS_CAP = 10 # max production dependencies shown
|
|
36
|
+
_SECONDARY_DEPS_CAP = 5 # max per dev/test/build dependency group
|
|
37
|
+
_MONOREPO_PKGS_CAP = 8 # max workspace/runtime packages shown
|
|
38
|
+
_KEY_DEPS_CAP = 10 # max key dependencies shown
|
|
39
|
+
_CODE_NOTES_CAP = 15 # max code notes in default output
|
|
40
|
+
_ENV_MAP_CAP = 15 # max env var entries in default output
|
|
41
|
+
|
|
27
42
|
|
|
28
43
|
def to_json(sm: SourceMap | dict[str, Any], indent: int = 2) -> str:
|
|
29
44
|
"""Serialize SourceMap or dict to canonical JSON.
|
|
@@ -176,7 +191,7 @@ def _dep_import_key(name: str) -> str:
|
|
|
176
191
|
return lowered.split("/")[0].replace("_", "-")
|
|
177
192
|
|
|
178
193
|
|
|
179
|
-
def _file_relevance(sm: SourceMap, *, limit: int =
|
|
194
|
+
def _file_relevance(sm: SourceMap, *, limit: int = _FILE_RELEVANCE_LIMIT) -> list[dict[str, Any]]:
|
|
180
195
|
from sourcecode.ranking_engine import RankingEngine
|
|
181
196
|
|
|
182
197
|
root = Path(sm.metadata.analyzed_path) if sm.metadata.analyzed_path else Path(".")
|
|
@@ -227,7 +242,20 @@ def _file_relevance(sm: SourceMap, *, limit: int = 15) -> list[dict[str, Any]]:
|
|
|
227
242
|
sem_hub = semantic_hub_scores.get(path, 0.0) * 0.30
|
|
228
243
|
combined = fs.score + content_rel + sem_hub
|
|
229
244
|
|
|
230
|
-
|
|
245
|
+
# Visibility threshold: require meaningful combined signal.
|
|
246
|
+
# Exception: high/medium-confidence files with strong content relevance
|
|
247
|
+
# can survive even if structural score is weak.
|
|
248
|
+
if combined < _FILE_RELEVANCE_MIN_COMBINED:
|
|
249
|
+
if not (file_class
|
|
250
|
+
and file_class.relevance > 0.45
|
|
251
|
+
and file_class.confidence in {"high", "medium"}):
|
|
252
|
+
continue
|
|
253
|
+
|
|
254
|
+
# Suppress low-confidence auxiliary/config files unless structurally prominent
|
|
255
|
+
if (file_class
|
|
256
|
+
and file_class.confidence == "low"
|
|
257
|
+
and file_class.category in {"config", "auxiliary"}
|
|
258
|
+
and combined < 0.45):
|
|
231
259
|
continue
|
|
232
260
|
|
|
233
261
|
item: dict[str, Any] = {
|
|
@@ -343,7 +371,7 @@ def compact_view(sm: SourceMap, *, no_tree: bool = False) -> dict[str, Any]:
|
|
|
343
371
|
key_deps = [
|
|
344
372
|
asdict(d) for d in sm.key_dependencies
|
|
345
373
|
if (d.role or "unknown") in _PRODUCTION_DEP_ROLES and d.scope not in {"dev"}
|
|
346
|
-
]
|
|
374
|
+
][:_KEY_DEPS_CAP]
|
|
347
375
|
elif sm.dependency_summary is None or not sm.dependency_summary.requested:
|
|
348
376
|
dep_summary_dict = None # "not analyzed" — agent should add --dependencies
|
|
349
377
|
|
|
@@ -358,7 +386,7 @@ def compact_view(sm: SourceMap, *, no_tree: bool = False) -> dict[str, Any]:
|
|
|
358
386
|
)
|
|
359
387
|
env_map_items = [
|
|
360
388
|
{k: v for k, v in asdict(e).items() if v is not None and v != "" and v != []}
|
|
361
|
-
for e in _sorted_env[:
|
|
389
|
+
for e in _sorted_env[:_ENV_MAP_CAP]
|
|
362
390
|
]
|
|
363
391
|
|
|
364
392
|
code_notes_summary_dict: Any = None
|
|
@@ -373,13 +401,13 @@ def compact_view(sm: SourceMap, *, no_tree: bool = False) -> dict[str, Any]:
|
|
|
373
401
|
)
|
|
374
402
|
code_notes_items = [
|
|
375
403
|
{k: v for k, v in asdict(n).items() if v is not None}
|
|
376
|
-
for n in _sorted_notes[:
|
|
404
|
+
for n in _sorted_notes[:_CODE_NOTES_CAP]
|
|
377
405
|
]
|
|
378
406
|
|
|
379
|
-
# Entry points: production runtime only.
|
|
380
|
-
#
|
|
407
|
+
# Entry points: production runtime only, capped.
|
|
408
|
+
# Development entries shown separately; auxiliary omitted from compact view.
|
|
381
409
|
ep_groups = _entry_point_groups(sm.entry_points)
|
|
382
|
-
entry_points_compact = ep_groups["production"]
|
|
410
|
+
entry_points_compact = ep_groups["production"][:_EP_PRODUCTION_CAP]
|
|
383
411
|
if not entry_points_compact:
|
|
384
412
|
entry_points_compact = [] # truth signal: no production runtime detected
|
|
385
413
|
|
|
@@ -408,8 +436,7 @@ def compact_view(sm: SourceMap, *, no_tree: bool = False) -> dict[str, Any]:
|
|
|
408
436
|
"context_summary": context_summary_dict,
|
|
409
437
|
"stacks": [asdict(stack) for stack in sm.stacks],
|
|
410
438
|
"entry_points": entry_points_compact,
|
|
411
|
-
"development_entry_points": ep_groups["development"] or None,
|
|
412
|
-
"auxiliary_entry_points": ep_groups["auxiliary"] or None,
|
|
439
|
+
"development_entry_points": (ep_groups["development"][:_EP_DEV_CAP] or None),
|
|
413
440
|
"dependency_summary": dep_summary_dict,
|
|
414
441
|
"key_dependencies": key_deps,
|
|
415
442
|
"env_summary": env_summary_dict,
|
|
@@ -742,25 +769,23 @@ def agent_view(sm: SourceMap) -> dict[str, Any]:
|
|
|
742
769
|
|
|
743
770
|
result: dict[str, Any] = {"project": project}
|
|
744
771
|
|
|
745
|
-
# ── 2. Entry points: production/runtime only
|
|
746
|
-
#
|
|
747
|
-
#
|
|
772
|
+
# ── 2. Entry points: production/runtime only, capped ─────────────────────
|
|
773
|
+
# Auxiliary entries are not actionable for agents — omitted entirely.
|
|
774
|
+
# Development entries shown in a separate channel, capped.
|
|
748
775
|
ep_groups = _entry_point_groups(sm.entry_points)
|
|
749
|
-
result["entry_points"] = ep_groups["production"]
|
|
776
|
+
result["entry_points"] = ep_groups["production"][:_EP_PRODUCTION_CAP]
|
|
750
777
|
if ep_groups["development"]:
|
|
751
|
-
result["development_entry_points"] = ep_groups["development"]
|
|
752
|
-
if ep_groups["auxiliary"]:
|
|
753
|
-
result["auxiliary_entry_points"] = ep_groups["auxiliary"]
|
|
778
|
+
result["development_entry_points"] = ep_groups["development"][:_EP_DEV_CAP]
|
|
754
779
|
|
|
755
780
|
# ── 3. Architecture ───────────────────────────────────────────────────────
|
|
756
781
|
result["architecture"] = _architecture_context(sm)
|
|
757
782
|
|
|
758
|
-
# ── 3a. File relevance: evidence-backed
|
|
783
|
+
# ── 3a. File relevance: evidence-backed, high-signal only ────────────────
|
|
759
784
|
relevant_files = _file_relevance(sm)
|
|
760
785
|
if relevant_files:
|
|
761
786
|
result["file_relevance"] = relevant_files
|
|
762
787
|
|
|
763
|
-
# ── 3b. Monorepo package roles (when available)
|
|
788
|
+
# ── 3b. Monorepo package roles (when available), capped ──────────────────
|
|
764
789
|
if sm.monorepo_packages:
|
|
765
790
|
_noise_roles = {"benchmark_layer", "tooling_layer", "docs_layer", "test_layer"}
|
|
766
791
|
operational_pkgs = [
|
|
@@ -769,15 +794,16 @@ def agent_view(sm: SourceMap) -> dict[str, Any]:
|
|
|
769
794
|
if p.architectural_role not in _noise_roles
|
|
770
795
|
]
|
|
771
796
|
if operational_pkgs:
|
|
772
|
-
result["runtime_packages"] = operational_pkgs
|
|
797
|
+
result["runtime_packages"] = operational_pkgs[:_MONOREPO_PKGS_CAP]
|
|
773
798
|
|
|
774
|
-
# ── 4. Dependencies: separated by operational role
|
|
799
|
+
# ── 4. Dependencies: separated by operational role, capped ───────────────
|
|
800
|
+
# noise_dependencies intentionally excluded — not actionable.
|
|
775
801
|
dep_groups = _dependency_groups(sm)
|
|
776
802
|
if dep_groups["production_dependencies"]:
|
|
777
|
-
result["production_dependencies"] = dep_groups["production_dependencies"][:
|
|
778
|
-
for dep_key in ("dev_tools", "test_utilities", "build_tooling", "
|
|
803
|
+
result["production_dependencies"] = dep_groups["production_dependencies"][:_PROD_DEPS_CAP]
|
|
804
|
+
for dep_key in ("dev_tools", "test_utilities", "build_tooling", "suspicious_dependencies"):
|
|
779
805
|
if dep_groups[dep_key]:
|
|
780
|
-
result[dep_key] = dep_groups[dep_key][:
|
|
806
|
+
result[dep_key] = dep_groups[dep_key][:_SECONDARY_DEPS_CAP]
|
|
781
807
|
|
|
782
808
|
# Backward-compatible compact list, now production-only.
|
|
783
809
|
production_key_deps = [
|
|
@@ -788,7 +814,7 @@ def agent_view(sm: SourceMap) -> dict[str, Any]:
|
|
|
788
814
|
_dep_skip = {"parent", "manifest_path", "workspace", "source", "ecosystem"}
|
|
789
815
|
result["key_dependencies"] = [
|
|
790
816
|
{k: v for k, v in asdict(d).items() if v is not None and k not in _dep_skip}
|
|
791
|
-
for d in production_key_deps[:
|
|
817
|
+
for d in production_key_deps[:_KEY_DEPS_CAP]
|
|
792
818
|
]
|
|
793
819
|
|
|
794
820
|
# ── 5. Signals — compact operational context ─────────────────────────────
|
|
@@ -961,12 +987,12 @@ def standard_view(sm: SourceMap, *, include_tree: bool = False) -> dict[str, Any
|
|
|
961
987
|
"project_summary": sm.project_summary,
|
|
962
988
|
"architecture_summary": sm.architecture_summary,
|
|
963
989
|
"stacks": [asdict(s) for s in sm.stacks],
|
|
964
|
-
"entry_points": ep_groups["production"],
|
|
990
|
+
"entry_points": ep_groups["production"][:_EP_PRODUCTION_CAP],
|
|
965
991
|
}
|
|
966
992
|
if ep_groups["development"]:
|
|
967
|
-
result["development_entry_points"] = ep_groups["development"]
|
|
993
|
+
result["development_entry_points"] = ep_groups["development"][:_EP_DEV_CAP]
|
|
968
994
|
if ep_groups["auxiliary"]:
|
|
969
|
-
result["auxiliary_entry_points"] = ep_groups["auxiliary"]
|
|
995
|
+
result["auxiliary_entry_points"] = ep_groups["auxiliary"][:_EP_DEV_CAP]
|
|
970
996
|
|
|
971
997
|
# Layer B — signals (only when the corresponding analyzer ran)
|
|
972
998
|
if sm.dependency_summary is not None and sm.dependency_summary.requested:
|
|
@@ -976,16 +1002,21 @@ def standard_view(sm: SourceMap, *, include_tree: bool = False) -> dict[str, Any
|
|
|
976
1002
|
result["key_dependencies"] = [
|
|
977
1003
|
asdict(d) for d in sm.key_dependencies
|
|
978
1004
|
if (d.role or "unknown") in _PRODUCTION_DEP_ROLES and d.scope not in {"dev"}
|
|
979
|
-
]
|
|
1005
|
+
][:_KEY_DEPS_CAP]
|
|
980
1006
|
|
|
981
1007
|
if sm.env_summary is not None and sm.env_summary.requested:
|
|
982
1008
|
result["env_summary"] = asdict(sm.env_summary)
|
|
983
|
-
result["env_map"] = [asdict(e) for e in sm.env_map]
|
|
1009
|
+
result["env_map"] = [asdict(e) for e in sm.env_map[:_ENV_MAP_CAP]]
|
|
984
1010
|
|
|
985
1011
|
if sm.code_notes_summary is not None and sm.code_notes_summary.requested:
|
|
986
1012
|
result["code_notes_summary"] = asdict(sm.code_notes_summary)
|
|
987
1013
|
if sm.code_notes:
|
|
988
|
-
|
|
1014
|
+
_SEVERITY_ORDER = {"BUG": 0, "FIXME": 1, "DEPRECATED": 2, "TODO": 3, "HACK": 4, "WARNING": 5}
|
|
1015
|
+
_sorted_notes = sorted(
|
|
1016
|
+
sm.code_notes,
|
|
1017
|
+
key=lambda n: (_SEVERITY_ORDER.get(getattr(n, "kind", "").upper(), 9), getattr(n, "path", "")),
|
|
1018
|
+
)
|
|
1019
|
+
result["code_notes"] = [asdict(n) for n in _sorted_notes[:_CODE_NOTES_CAP]]
|
|
989
1020
|
if sm.code_adrs:
|
|
990
1021
|
result["code_adrs"] = [asdict(a) for a in sm.code_adrs]
|
|
991
1022
|
|
|
@@ -1076,12 +1107,12 @@ def _contract_view_minimal(
|
|
|
1076
1107
|
"""Minimal contract: project header + stripped per-file contracts."""
|
|
1077
1108
|
primary = next((s for s in sm.stacks if s.primary), sm.stacks[0] if sm.stacks else None)
|
|
1078
1109
|
|
|
1079
|
-
# Entry point paths only (production)
|
|
1110
|
+
# Entry point paths only (production), capped
|
|
1080
1111
|
ep_paths = sorted({
|
|
1081
1112
|
ep.path.replace("\\", "/")
|
|
1082
1113
|
for ep in sm.entry_points
|
|
1083
1114
|
if is_production_entry_point(ep)
|
|
1084
|
-
})
|
|
1115
|
+
})[:_EP_PRODUCTION_CAP]
|
|
1085
1116
|
|
|
1086
1117
|
project: dict[str, Any] = {"type": sm.project_type}
|
|
1087
1118
|
if primary:
|
|
@@ -1183,7 +1214,7 @@ def _contract_view_minimal(
|
|
|
1183
1214
|
if p.architectural_role not in _noise_roles
|
|
1184
1215
|
]
|
|
1185
1216
|
if operational_pkgs:
|
|
1186
|
-
result["workspace_packages"] = operational_pkgs
|
|
1217
|
+
result["workspace_packages"] = operational_pkgs[:_MONOREPO_PKGS_CAP]
|
|
1187
1218
|
|
|
1188
1219
|
# Confidence summary — detection quality signal
|
|
1189
1220
|
if sm.confidence_summary is not None:
|
|
@@ -1378,12 +1409,12 @@ def _contract_view_standard(
|
|
|
1378
1409
|
"package_manager": s.package_manager}
|
|
1379
1410
|
for s in sm.stacks
|
|
1380
1411
|
],
|
|
1381
|
-
"entry_points": ep_groups["production"],
|
|
1412
|
+
"entry_points": ep_groups["production"][:_EP_PRODUCTION_CAP],
|
|
1382
1413
|
}
|
|
1383
1414
|
if sm.metadata.traversal_topology:
|
|
1384
1415
|
result["traversal"] = sm.metadata.traversal_topology
|
|
1385
1416
|
if ep_groups["development"]:
|
|
1386
|
-
result["development_entry_points"] = ep_groups["development"]
|
|
1417
|
+
result["development_entry_points"] = ep_groups["development"][:_EP_DEV_CAP]
|
|
1387
1418
|
|
|
1388
1419
|
if sm.confidence_summary is not None:
|
|
1389
1420
|
result["confidence"] = {
|
|
@@ -40,8 +40,9 @@ def test_fastapi_fixture_schema() -> None:
|
|
|
40
40
|
assert data["project_type"] == "api"
|
|
41
41
|
assert data["stacks"][0]["stack"] == "python"
|
|
42
42
|
assert data["stacks"][0]["frameworks"][0]["name"] == "FastAPI"
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
# src/main.py is detected via convention — classified auxiliary and suppressed
|
|
44
|
+
# from default output per filtering policy. Verify detection still ran.
|
|
45
|
+
assert "entry_points" in data
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
def test_go_fixture_schema() -> None:
|
|
@@ -64,5 +65,5 @@ def test_monorepo_fixture_schema() -> None:
|
|
|
64
65
|
assert data["project_type"] == "monorepo"
|
|
65
66
|
assert {stack["stack"] for stack in data["stacks"]} == {"nodejs", "python"}
|
|
66
67
|
assert {stack["root"] for stack in data["stacks"]} == {"apps/web", "packages/api"}
|
|
67
|
-
|
|
68
|
-
assert
|
|
68
|
+
# Convention-detected workspace entries are suppressed from default output.
|
|
69
|
+
assert "entry_points" in data
|
{sourcecode-0.46.0 → sourcecode-0.48.0}/.agents/skills/source-command-gsd-join-discord/SKILL.md
RENAMED
|
File without changes
|
{sourcecode-0.46.0 → sourcecode-0.48.0}/.agents/skills/source-command-gsd-review-backlog/SKILL.md
RENAMED
|
File without changes
|
{sourcecode-0.46.0 → sourcecode-0.48.0}/.agents/skills/source-command-gsd-workstreams/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sourcecode-0.46.0 → sourcecode-0.48.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|